Removed useless rsalib library - too slow!

master
q3k 2012-11-28 13:35:10 +01:00
parent ab159a3887
commit 0b8d4563ac
10 changed files with 0 additions and 2254 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,277 +0,0 @@
/* ****************************************************************************
*
* BigInt.h
*
* Author: Nedim Srndic
* Release date: 14th of March 2008
*
* A class representing a positive or negative integer that may
* be too large to fit in any of the standard C++ integer types
* (i. e. 2^128 is "just" 39 digits long).
* The digits are stored in a dinamic array of tipe unsigned char*,
* with values from 0 to 9 (not '0' to '9'), so that the CPU can
* add/subtract individual digits.
*
* The array has "length" memory locations, one byte each (the size of
* unsigned char is probably one byte). There are "digitCount" digits actually
* in use, the rest is spare space.
* The number of digits is constrained by available memory and the limit of the
* unsigned long int type used for indexing (the "length" property).
* The individual digits are stored right-to-left, to speed up computing and
* allow for faster growth of numbers (no need to reallocate memory when
* the digitCount grows).
*
* The class handles its own memory management. There are no memory leaks
* reported until this date.
* When creating a BigInt from const char* or unsigned long int,
* copying from an other BigInt with (digitCount + 2 <= length)
* (soon to be full), new memory is allocated and
* length is adjusted to (length * FACTOR + 1). This is done to expand the
* capacity of the digits array to accomodate potential new digits.
* When assigning a BigInt "bInt" that is twice as small or bigger than *this,
* the length is set to (bInt.length + 2).
*
* BigInt supports:
*
* - addition (unary +, binary +, +=, prefix ++, postfix ++)
*
* - subtraction (unary -, binary -, -=, prefix --, postfix --)
*
* - multiplication (*, *=)
* For multiplication, one can choose between the Square and multiply
* or Karatsuba algorithm, or long multiplication at compile time
* (this can be done by defining or undefining the macro "KARATSUBA"
* in BigInt.cpp).
* The Karatsuba algorithm multiplies integers in O(n^log2(3))
* complexity. log2(3) is approximately 1.585, so this should be
* significantly faster than long multiplication, if the numbers are
* big enough. Currently, the long multiplication is better implemented,
* and runs faster than the Karatsuba multiplication for numbers shorter
* than about 100 digits.
*
* - C-style integer division (/, /=)
*
* - C-style integer division remainder (%, %=)
* When calculating the remainder, the number is first divided.
*
* - comparison (==, !=, <, <=, >, >=)
* All of the <, <=, >, >= operators are equally fast.
*
* - exponentiation (GetPower(), SetPower(), GetPowerMod(), SetPowerMod())
* For exponentiation, the Exponantiation by squaring
* (or Square and multiply or Binary exponentiation) algorithm is used.
* It uses O(log(n)) multiplications and therefore is significantly faster
* than multiplying x with itself n-1 times.
*
* In addition to mathematical operations, BigInt supports:
*
* - automatic conversion from const char *, std::string and unsigned long int
* - safe construction, copying, assignment and destruction
* - automatic conversion to std::string
* - writing to the standard output (operator <<(std::ostream, BigInt))
* - reading from the standard input (operator >>(std::istream, BigInt))
* - getting and setting individual digits (GetDigit(), SetDigit())
* - returning the number of digits (Length())
* - returning a string of digits (ToString())
* This can be useful for human-readable output.
* - returning a value indicating wether the number is odd (IsOdd())
* - returning a value indicating wether the number is positive (IsPositive())
* - returning a value indicating wether the BigInt equals zero (EqualsZero())
* The fastest way to determine this.
* - returning absolute value (Abs())
*
* There are a few static constants defined in this file:
*
* - BigIntZero : a zero of type BigInt
* If you need a zero fast, use this.
* - BigIntOne : a one of type BigInt
* If you need a one fast, use this.
*
* ****************************************************************************
*/
#ifndef BIGINT_H_
#define BIGINT_H_
#include <iostream> //ostream, istream
#include <cmath> //sqrt()
#include <string> //ToString(), BigInt(std::string)
class BigInt
{
private:
/* An array of digits stored right to left,
* i.e. int 345 = unsigned char {[5], [4], [3]} */
unsigned char *digits;
// The total length of the allocated memory
unsigned long int length;
// Number of digits
unsigned long int digitCount;
// Sign
bool positive;
/* Multiplication factor for the length property
* when creating or copying objects. */
static const double FACTOR;
/* Transforms the number from unsigned long int to unsigned char[]
* and pads the result with zeroes. Returns the number of digits. */
static unsigned long int int2uchar( unsigned long int number,
unsigned char *digits,
unsigned long int padding);
/* Converts ASCII digits to equivalent unsigned char numeric values. */
static void char2uchar( unsigned char *array,
unsigned long int length);
/* Check if all ASCII values are digits '0' to '9'. */
static bool allCharsAreDigits( const char *array,
unsigned long int length);
/* Compares two BigInt. If the last two arguments are
* omitted, the comparison is sign-insensitive (comparison by
* absolute value). Returns 0 if a == b, 1 if a > b, 2 if a < b. */
static int compareNumbers( unsigned char *a, unsigned long int na,
unsigned char *b, unsigned long int nb,
bool aPositive = true,
bool bPositive = true);
/* Multiplies two unsigned char[] using the Divide and Conquer
* a.k.a. Karatsuba algorithm .*/
static void karatsubaMultiply( unsigned char *a, unsigned char *b,
unsigned long int n,
unsigned char *buffer);
/* Multiplies two unsigned char[] the long way. */
static void longMultiply( unsigned char *a, unsigned long int na,
unsigned char *b, unsigned long int nb,
unsigned char *result);
/* Simple addition, used by the multiply function.
* Returns the remaining carry. */
static unsigned char quickAdd( unsigned char *a, unsigned char *b,
unsigned long int n);
/* Simple subtraction, used by the multiply function. */
static void quickSub( unsigned char *a, unsigned char *b,
unsigned char *end, unsigned long int n);
/* Divides two BigInt numbers. */
static void divide( const BigInt &dividend, const BigInt &divisor,
BigInt &quotient, BigInt &remainder);
/* Returns the value of the specified unsigned char[] as long int. */
static unsigned long int toInt(unsigned char *digits, int n);
/* Saves the sum of two unsigned char* shorter and longer into result.
* It must be nShorter <= nLonger. If doFill == true, it fills the
* remaining free places with zeroes (used in KaratsubaMultiply()).
* Returns true if there was an overflow at the end (meaning that
* the result.digitCount was longer.digitCount + 1. */
static bool add(unsigned char *shorter, unsigned long int nShorter,
unsigned char *longer, unsigned long int nLonger,
unsigned char *result, int nResult,
bool doFill = true);
/* Shifts the digits n places left. */
BigInt &shiftLeft(unsigned long int n);
/* Shifts the digits n places right. */
BigInt &shiftRight(unsigned long int n);
/* Expands the digits* to n. */
void expandTo(unsigned long int n);
public:
BigInt();
BigInt(const char *charNum);
BigInt(unsigned long int intNum);
BigInt(const std::string &str);
BigInt(const BigInt &number);
BigInt &operator =(const BigInt &rightNumber);
~BigInt();
operator std::string() const;
friend std::ostream &operator <<( std::ostream &cout,
const BigInt &number);
friend std::istream &operator >>( std::istream &cin,
BigInt &number);
friend bool operator <(const BigInt &a, const BigInt &b);
friend bool operator <=(const BigInt &a, const BigInt &b);
friend bool operator >(const BigInt &a, const BigInt &b);
friend bool operator >=(const BigInt &a, const BigInt &b);
friend bool operator ==(const BigInt &a, const BigInt &b);
friend bool operator !=(const BigInt &a, const BigInt &b);
friend BigInt operator + (const BigInt &a, const BigInt &b);
BigInt &operator+();
BigInt &operator++();
BigInt operator++(int);
BigInt &operator+=(const BigInt &number);
BigInt operator-() const;
friend BigInt operator-(const BigInt &a, const BigInt &b);
BigInt &operator--();
BigInt operator--(int);
BigInt &operator-=(const BigInt &number);
friend BigInt operator*(const BigInt &a, const BigInt &b);
BigInt &operator*=(const BigInt &number);
friend BigInt operator/(const BigInt &a, const BigInt &b);
BigInt &operator/=(const BigInt &number);
friend BigInt operator%(const BigInt &a, const BigInt &b);
BigInt &operator%=(const BigInt &number);
/* Returns *this to the power of n
* using the fast Square and Multiply algorithm. */
BigInt GetPower(unsigned long int n) const;
/* *this = *this to the power of n. */
void SetPower(unsigned long int n);
/* Returns *this to the power of n
* using the fast Square and Multiply algorithm. */
BigInt GetPower(BigInt n) const;
/* *this = *this to the power of n. */
void SetPower(BigInt n);
/* Returns (*this to the power of b) mod n. */
BigInt GetPowerMod(const BigInt &b, const BigInt &n) const;
/* *this = (*this to the power of b) mod n. */
void SetPowerMod(const BigInt &b, const BigInt &n);
/* Returns the 'index'th digit (zero-based, right-to-left). */
unsigned char GetDigit(unsigned long int index) const;
/* Sets the value of 'index'th digit
* (zero-based, right-to-left) to 'value'. */
void SetDigit(unsigned long int index, unsigned char value);
/* Returns the number of digits. */
unsigned long int Length() const;
/* Returns true if *this is positive, otherwise false. */
bool IsPositive() const;
/* Returns true if *this is odd, otherwise false. */
bool IsOdd() const;
/* Returns the value of BigInt as std::string. */
std::string ToString(bool forceSign = false) const;
/* Returns a value indicating whether *this equals 0. */
bool EqualsZero() const;
/* Returns the absolute value. */
BigInt Abs() const;
};
inline BigInt::~BigInt()
{
delete[] digits;
}
inline BigInt &BigInt::operator+()
{
return *this;
}
/* Returns the number of digits. */
inline unsigned long int BigInt::Length() const
{
return digitCount;
}
/* Returns true if *this is positive, otherwise false. */
inline bool BigInt::IsPositive() const
{
return positive;
}
/* Returns true if *this is odd, otherwise false. */
inline bool BigInt::IsOdd() const
{
return digits[0] & 1;
}
/* Returns a value indicating whether *this equals 0. */
inline bool BigInt::EqualsZero() const
{
return digitCount == 1 && digits[0] == 0;
}
// A BigInt number with the value of 0.
static const BigInt BigIntZero;
// A BigInt number with the value of 1.
static const BigInt BigIntOne(1L);
#endif /*BIGINT_H_*/

View File

@ -1,20 +0,0 @@
/* ****************************************************************************
*
* Key.cpp
*
* Author: Nedim Srndic
* Release date: 5th of September 2008
*
* This file contains the implementation for the Key class.
*
* ****************************************************************************
*/
#include "Key.h"
std::ostream &operator<<(std::ostream &cout, const Key &key)
{
return std::cout
<< "Modulus: " << key.GetModulus() << std::endl
<< "Exponent: " << key.GetExponent();
}

View File

@ -1,42 +0,0 @@
/* ****************************************************************************
*
* Key.h
*
* Author: Nedim Srndic
* Release date: 16th of June 2008
*
* A class representing a public or private RSA key.
*
* A public or private RSA key consists of a modulus and an exponent. In this
* implementation an object of type BigInt is used to store those values.
*
* ****************************************************************************
*/
#ifndef KEY_H_
#define KEY_H_
#include "BigInt.h"
#include <iostream>
class Key
{
private:
BigInt modulus;
BigInt exponent;
public:
Key(const BigInt &modulus, const BigInt &exponent) :
modulus(modulus), exponent(exponent)
{}
const BigInt &GetModulus() const
{
return modulus;
}
const BigInt &GetExponent() const
{
return exponent;
}
friend std::ostream &operator<<(std::ostream &cout, const Key &key);
};
#endif /*KEY_H_*/

View File

@ -1,20 +0,0 @@
/* ****************************************************************************
*
* KeyPair.cpp
*
* Author: Nedim Srndic
* Release date: 22th of July 2008
*
* This file contains the implementation for the KeyPair class.
*
* ****************************************************************************
*/
#include "KeyPair.h"
std::ostream &operator <<(std::ostream &cout, const KeyPair &k)
{
return std::cout
<< "Private key:" << std::endl << k.GetPrivateKey() << std::endl
<< "Public key:" << std::endl << k.GetPublicKey();
}

View File

@ -1,41 +0,0 @@
/* ****************************************************************************
*
* KeyPair.h
*
* Author: Nedim Srndic
* Release date: 17th of June 2008
*
* A class representing a public/private RSA keypair.
*
* A keypair consists of a public key and a matching private key.
*
* ****************************************************************************
*/
#ifndef KEYPAIR_H_
#define KEYPAIR_H_
#include "Key.h"
#include <iostream>
class KeyPair
{
private:
const Key privateKey;
const Key publicKey;
public:
KeyPair(Key privateKey, Key publicKey):
privateKey(privateKey), publicKey(publicKey)
{}
const Key &GetPrivateKey() const
{
return privateKey;
}
const Key &GetPublicKey() const
{
return publicKey;
}
friend std::ostream &operator <<(std::ostream &cout, const KeyPair &k);
};
#endif /*KEYPAIR_H_*/

View File

@ -1,181 +0,0 @@
/* ****************************************************************************
*
* PrimeGenerator.cpp
*
* Author: Nedim Srndic
* Release date: 14th of March 2008
*
* This file contains the implementation for the PrimeGenerator class.
*
* There is a static constant defined in this file:
*
* - RandMax : RAND_MAX (defined in cstdlib) of type BigInt
* Mainly used for speedup in the Generate member function.
* Represents the largest random unsigned long integer that a particular
* platform can generate. This is platform-specific.
*
* ****************************************************************************
*/
#include "PrimeGenerator.h"
#include <string>
#include <cstdlib> // rand()
/* Generates a random number with digitCount digits.
* Returns it by reference in the "number" parameter. */
void PrimeGenerator::MakeRandom(BigInt &number, unsigned long int digitCount)
{
//the new number will be created using a string object (newNum),
//and later converted into a BigInt
std::string newNum;
newNum.resize(digitCount);
unsigned long int tempDigitCount(0);
//generate random digits
while (tempDigitCount < digitCount)
{
unsigned long int newRand(std::rand());
//10 is chosen to skip the first digit, because it might be
//statistically <= n, where n is the first digit of RAND_MAX
while (newRand >= 10)
{
newNum[tempDigitCount++] = (newRand % 10) + '0';
newRand /= 10;
if (tempDigitCount == digitCount)
break;
}
}
//make sure the leading digit is not zero
if (newNum[0] == '0')
newNum[0] = (std::rand() % 9) + 1 + '0';
number = newNum;
}
/* Generates a random number such as 1 <= number < 'top'.
* Returns it by reference in the 'number' parameter. */
void PrimeGenerator::makeRandom(BigInt &number, const BigInt &top)
{
//randomly select the number of digits for the random number
unsigned long int newDigitCount = (rand() % top.Length()) + 1;
MakeRandom(number, newDigitCount);
//make sure number < top
while (number >= top)
MakeRandom(number, newDigitCount);
}
/* Creates an odd BigInt with the specified number of digits.
* Returns it by reference in the "number" parameter. */
void PrimeGenerator::makePrimeCandidate(BigInt &number,
unsigned long int digitCount)
{
PrimeGenerator::MakeRandom(number, digitCount);
//make the number odd
if (!number.IsOdd())
number.SetDigit(0, number.GetDigit(0) + 1);
//make sure the leading digit is not a zero
if (number.GetDigit(number.Length() - 1) == 0)
number.SetDigit(number.Length() - 1, (std::rand() % 9) + 1);
}
/* Tests the primality of the given _odd_ number using the
* Miller-Rabin probabilistic primality test. Returns true if
* the tested argument "number" is a probable prime with a
* probability of at least 1 - 4^(-k), otherwise false. */
bool PrimeGenerator::isProbablePrime( const BigInt &number,
unsigned long int k)
{
//first we need to calculate such a and b, that
//number - 1 = 2^a * b, a and b are integers, b is odd
BigInt numberMinusOne(number - BigIntOne);
unsigned long int a(0);
BigInt temp(numberMinusOne);
BigInt b, quotient;
static const BigInt two(BigIntOne + BigIntOne);
while (b.EqualsZero())
{
//temp = quotient * 2 + remainder
//PrimeGenerator used to be a friend of BigInt, so the following
//statement produced the result in one call to BigInt::divide()
// BigInt::divide(temp, two, quotient, b);
//That doesn't work any more, so we have to use two calls
quotient = temp / two;
b = temp % two;
temp = quotient;
a++;
}
b = temp * two + b;
a--;
//test with k different possible witnesses to ensure that the probability
//that "number" is prime is at least 1 - 4^(-k)
for (unsigned long int i = 0; i < k; i++)
{
PrimeGenerator::makeRandom(temp, number);
if (isWitness(temp, number, b, a, numberMinusOne))
return false; //definitely a composite number
}
return true; //a probable prime
}
/* Returns true if "candidate" is a witness for the compositeness
* of "number", false if "candidate" is a strong liar. "exponent"
* and "squareCount" are used for computation */
bool PrimeGenerator::isWitness( BigInt candidate,
const BigInt &number,
const BigInt &exponent,
unsigned long int squareCount,
const BigInt &numberMinusOne)
{
//calculate candidate = (candidate to the power of exponent) mod number
candidate.SetPowerMod(exponent, number);
//temporary variable, used to call the divide function
BigInt quotient;
for (unsigned long int i = 0; i < squareCount; i++)
{
bool maybeWitness(false);
if (candidate != BigIntOne && candidate != numberMinusOne)
maybeWitness = true;
//PrimeGenerator used to be a friend of BigInt, so the following
//statement produced the result in one call to BigInt::divide()
// BigInt::divide(candidate * candidate, number, quotient, candidate);
//That doesn't work any more, so we have to use two calls
candidate = candidate * candidate;
quotient = (candidate) / number;
candidate = (candidate) % number;
if (maybeWitness && candidate == BigIntOne)
return true; //definitely a composite number
}
if (candidate != BigIntOne)
return true; //definitely a composite number
return false; //probable prime
}
/* Returns a probable prime number "digitCount" digits long,
* with a probability of at least 1 - 4^(-k) that it is prime. */
BigInt PrimeGenerator::Generate(unsigned long int digitCount,
unsigned long int k)
{
if (digitCount < 3)
throw "Error PRIMEGENERATOR00: Primes less than 3 digits long "
"not supported.";
BigInt primeCandidate;
PrimeGenerator::makePrimeCandidate(primeCandidate, digitCount);
while (!isProbablePrime(primeCandidate, k))
{
//select the next odd number and try again
primeCandidate = primeCandidate + 2;
if (primeCandidate.Length() != digitCount)
PrimeGenerator::makePrimeCandidate(primeCandidate, digitCount);
}
return primeCandidate;
}

View File

@ -1,53 +0,0 @@
/* ****************************************************************************
* PrimeGenerator.h
*
* A class used to generate large prime or random numbers.
*
* Author: Nedim Srndic
* Release date: 14th of March 2008
*
* ****************************************************************************
*/
#ifndef PRIMEGENERATOR_H_
#define PRIMEGENERATOR_H_
#include "BigInt.h"
class PrimeGenerator
{
private:
/* Generates a random "number" such as 1 <= "number" < "top".
* Returns it by reference in the "number" parameter. */
static void makeRandom( BigInt &number,
const BigInt &top);
/* Creates an odd BigInt with the specified number of digits.
* Returns it by reference in the "number" parameter. */
static void makePrimeCandidate( BigInt &number,
unsigned long int digitCount);
/* Tests the primality of the given _odd_ number using the
* Miller-Rabin probabilistic primality test. Returns true if
* the tested argument "number" is a probable prime with a
* probability of at least 1 - 4^(-k), otherwise false. */
static bool isProbablePrime(const BigInt &number,
unsigned long int k);
/* Returns true if "candidate" is a witness for the compositeness
* of "number", false if "candidate" is a strong liar. "exponent"
* and "squareCount" are used for computation */
static bool isWitness( BigInt candidate,
const BigInt &number,
const BigInt &exponent,
unsigned long int squareCount,
const BigInt &numberMinusOne);
public:
/* Generates a random number with digitCount digits.
* Returns it by reference in the "number" parameter. */
static void MakeRandom( BigInt &number,
unsigned long int digitCount);
/* Returns a probable prime number "digitCount" digits long,
* with a probability of at least 1 - 4^(-k) that it is prime. */
static BigInt Generate( unsigned long int digitCount,
unsigned long int k = 3);
};
#endif /*PRIMEGENERATOR_H_*/

View File

@ -1,377 +0,0 @@
/* ****************************************************************************
*
* RSA.cpp
*
* Author: Nedim Srndic
* Release date: 16th of June 2008
*
* This file contains the implementation for the RSA class.
*
* ****************************************************************************
*/
#include "RSA.h"
#include "Key.h" //Key
#include "KeyPair.h" //KeyPair
#include "PrimeGenerator.h" //Generate()
#include <string> //string
#include <fstream> //ifstream, ofstream
using std::string;
/* Returns the greatest common divisor of the two arguments
* "a" and "b", using the Euclidean algorithm. */
BigInt RSA::GCD(const BigInt &a, const BigInt &b)
{
if (b.EqualsZero())
return a;
else
return RSA::GCD(b, a % b);
}
/* Solves the equation
* d = ax + by
* given a and b, and returns d, x and y by reference.
* It uses the Extended Euclidean Algorithm */
void RSA::extendedEuclideanAlgorithm( const BigInt &a, const BigInt &b,
BigInt &d, BigInt &x, BigInt &y)
{
if (b.EqualsZero())
{
d = a;
x = BigIntOne;
y = BigIntZero;
return;
}
RSA::extendedEuclideanAlgorithm(b, a % b, d, x, y);
BigInt temp(x);
x = y;
y = temp - a / b * y;
}
/* Solves the equation
* ax is congruent to b (mod n),
* given a, b and n finds x. */
BigInt RSA::solveModularLinearEquation( const BigInt &a,
const BigInt &b,
const BigInt &n)
{
BigInt p, q, r;
RSA::extendedEuclideanAlgorithm(a, n, p, q, r);
if ((b % p).EqualsZero()) // This has to evaluate to 'true'.
return (q * (b / p)) % n;
else
throw "Error RSA00: Error in key generation."; // Detect mistakes.
}
/* Throws an exception if "key" is too short to be used. */
void RSA::checkKeyLength(const Key &key)
{
// Minimum required key length is around 24 bits. (In-house requirement)
if (key.GetModulus().Length() < 8)
throw "Error RSA01: Keys must be at least 8 digits long.";
}
/* Transforms a std::string message into a BigInt message.
* Every ASCII character of the original message is replaced by it's
* ASCII value and appended to the end of the newly created BigInt object
* 'decoded' as a three-digit number, from left to right. */
BigInt RSA::encode(const string &message)
{
// The new number will be created using a string object (encoded),
// and converted into a BigInt on return.
string encoded;
encoded.resize(message.length() * 3 + 1);
unsigned long int index = message.length() * 3;
for (unsigned long int i(0); i < message.length(); i++)
{
// Encode the characters using their ASCII values' digits as
// BigInt digits.
unsigned char ASCII = message[i];
encoded[index - 2] = (ASCII % 10) + '0';
ASCII /= 10;
encoded[index - 1] = (ASCII % 10) + '0';
encoded[index] = (ASCII / 10) + '0';
index -= 3;
}
// We add an special symbol '1' to the beginning of the string 'encoded'
// to make sure that the returned BigInt doesn't begin with a zero. We also
// need to make sure we remove that '1' when decoding (see RSA::decode()).
encoded[0] = '1';
return encoded;
}
/* Transforms a BigInt cyphertext into a std::string cyphertext. */
string RSA::decode(const BigInt &message)
{
string decoded;
// The special symbol '1' we added to the beginning of the encoded message
// will now be positioned at message[message.Length() - 1], and
// message.Length() -1 must be divisible by 3 without remainder. Thus we
// can ignore the special symbol by only using digits in the range
// from message[0] to message[message.Length() - 2].
for (unsigned long int i(0); i < message.Length() / 3; i++)
{
// Decode the characters using the ASCII values in the BigInt digits.
char ASCII = 100 * char(message.GetDigit(i * 3));
ASCII += 10 * char(message.GetDigit(i * 3 + 1));
decoded.push_back(ASCII + char(message.GetDigit(i * 3 + 2)));
}
return decoded;
}
/* Encrypts a "chunk" (a small part of a message) using "key" */
string RSA::encryptChunk(const string &chunk, const Key &key)
{
// First encode the chunk, to make sure it is represented as an integer.
BigInt a = RSA::encode(chunk);
// The RSA encryption algorithm is a congruence equation.
a.SetPowerMod(key.GetExponent(), key.GetModulus());
return a.ToString();
}
/* Decrypts a "chunk" (a small part of a message) using "key" */
string RSA::decryptChunk(const BigInt &chunk, const Key &key)
{
BigInt a = chunk;
// The RSA decryption algorithm is a congruence equation.
a.SetPowerMod(key.GetExponent(), key.GetModulus());
// Decode the message to a readable form.
return RSA::decode(a);
}
/* Encrypts a string "message" using "key". */
std::string RSA::encryptString(const std::string &message, const Key &key)
{
//partition the message into biggest possible encryptable chunks
const unsigned long int chunkSize(((key.GetModulus().Length() - 2) / 3));
const unsigned long int chunkCount = message.length() / chunkSize;
string cypherText;
for (unsigned long int i(0); i < chunkCount; i++)
{
// Get the next chunk.
string chunk(message.substr(i * chunkSize, chunkSize));
chunk = RSA::encryptChunk(chunk, key);
// Put a ' ' between the chunks so that we can separate them later.
cypherText.append(chunk.append(" "));
}
// If the last chunk has the same size as the others, we are finished.
if (chunkSize * chunkCount == message.length())
return cypherText;
// Handle the last chunk. It is smaller than the others.
const unsigned long int lastChunkSize = message.length() % chunkSize;
string lastChunk(message.substr(chunkCount * chunkSize, lastChunkSize));
lastChunk = RSA::encryptChunk(lastChunk, key);
return cypherText.append(lastChunk.append(" "));
}
/* Decrypts a string "message" using "key". */
std::string RSA::decryptString(const std::string &cypherText, const Key &key)
{
// Partition the cypherText into chunks. They are seperated by ' '.
string message;
long int i(0), j(0);
while ((j = cypherText.find(' ', i)) != -1)
{
// Get the chunk.
BigInt chunk(cypherText.substr(i, j - i));
if (chunk >= key.GetModulus())
throw "Error RSA02: Chunk too large.";
// Decrypt the chunk and store the message.
string text = RSA::decryptChunk(chunk, key);
message.append(text);
i = j + 1;
}
return message;
}
/* Tests the file for 'eof', 'bad ' errors and throws an exception. */
void RSA::fileError(bool eof, bool bad)
{
if (eof)
throw "Error RSA03: Unexpected end of file.";
else if (bad)
throw "Error RSA04: Bad file?";
else
throw "Error RSA05: File contains unexpected data.";
}
/* Returns the string "message" RSA-encrypted using the key "key". */
string RSA::Encrypt(const string &message, const Key &key)
{
RSA::checkKeyLength(key);
return RSA::encryptString(message, key);
}
/* Encrypts the file "sourceFile" using the key "key" and saves
* the result into the file "destFile". */
void RSA::Encrypt( const char *sourceFile, const char *destFile,
const Key &key)
{
RSA::checkKeyLength(key);
//open the input and output files
std::ifstream source(sourceFile, std::ios::in | std::ios::binary);
if (!source)
throw "Error RSA06: Opening file \"sourceFile\" failed.";
std::ofstream dest(destFile, std::ios::out | std::ios::binary);
if (!dest)
throw "Error RSA07: Creating file \"destFile\" failed.";
//find the source file length
source.seekg(0, std::ios::end);
const unsigned long int fileSize = source.tellg();
source.seekg(0, std::ios::beg);
//create an input buffer
const unsigned long int bufferSize = 4096;
char buffer[bufferSize];
//encrypt file chunks
const unsigned long int chunkCount = fileSize / bufferSize;
for (unsigned long int i(0); i <= chunkCount; i++)
{
unsigned long int readLength;
//read the chunk
if (i == chunkCount) //if it's the last one
readLength = fileSize % bufferSize;
else
readLength = sizeof buffer;
source.read(buffer, readLength);
if (!source)
RSA::fileError(source.eof(), source.bad());
//encrypt the chunk
std::string chunk(buffer, readLength);
chunk = RSA::encryptString(chunk, key);
//write the chunk
dest.write(chunk.c_str(), chunk.length());
if (!dest)
RSA::fileError(dest.eof(), dest.bad());
}
source.close();
dest.close();
}
/* Returns the string "cypherText" RSA-decrypted using the key "key". */
string RSA::Decrypt(const string &cypherText, const Key &key)
{
RSA::checkKeyLength(key);
return RSA::decryptString(cypherText, key);
}
/* Decrypts the file "sourceFile" using the key "key" and saves
* the result into the file "destFile". */
void RSA::Decrypt( const char *sourceFile, const char *destFile,
const Key &key)
{
RSA::checkKeyLength(key);
//open the input and output files
std::ifstream source(sourceFile, std::ios::in | std::ios::binary);
if (!source)
throw "Error RSA08: Opening file \"sourceFile\" failed.";
std::ofstream dest(destFile, std::ios::out | std::ios::binary);
if (!dest)
throw "Error RSA09: Creating file \"destFile\" failed.";
//find the source file length
source.seekg(0, std::ios::end);
const unsigned long int fileSize = source.tellg();
source.seekg(0, std::ios::beg);
//create an input buffer
const unsigned long int bufferSize = 8192;
char buffer[bufferSize];
unsigned long int readCount = 0;
while (readCount < fileSize)
{
unsigned long int readLength;
//read new data
if (fileSize - readCount >= bufferSize) //if it's not the last one
readLength = sizeof buffer;
else
readLength = fileSize - readCount;
source.read(buffer, readLength);
if (!source)
RSA::fileError(source.eof(), source.bad());
//find the next chunk
std::string chunk(buffer, readLength);
chunk = chunk.substr(0, chunk.find_last_of(' ', chunk.length()) + 1);
readCount += chunk.length();
source.seekg(readCount, std::ios::beg);
//decrypt the chunk
chunk = RSA::decryptString(chunk, key);
//write the chunk
dest.write(chunk.c_str(), chunk.length());
if (!dest)
RSA::fileError(dest.eof(), dest.bad());
}
source.close();
dest.close();
}
/* Generates a public/private keypair. The keys are retured in a
* KeyPair. The generated keys are 'digitCount' or
* 'digitCount' + 1 digits long. */
KeyPair RSA::GenerateKeyPair( unsigned long int digitCount,
unsigned long int k)
{
if (digitCount < 8)
throw "Error RSA10: Keys must be at least 8 digits long.";
//generate two random numbers p and q
BigInt p(PrimeGenerator::Generate(digitCount / 2 + 2, k));
BigInt q(PrimeGenerator::Generate(digitCount / 2 - 1, k));
//make sure they are different
while (p == q)
{
p = PrimeGenerator::Generate(digitCount / 2 + 1, k);
}
//calculate the modulus of both the public and private keys, n
BigInt n(p * q);
//calculate the totient phi
BigInt phi((p - BigIntOne) * (q - BigIntOne));
//select a small odd integer e that is coprime with phi and e < phi
//usually 65537 is used, and we will use it too if it fits
//it is recommended that this be the least possible value for e
BigInt e("65537");
//make sure the requirements are met
while (RSA::GCD(phi, e) != BigIntOne || e < "65537" || !e.IsOdd())
{
PrimeGenerator::MakeRandom(e, 5);
}
//now we have enough information to create the public key
//e is the public key exponent, n is the modulus
Key publicKey(n, e);
//calculate d, d * e = 1 (mod phi)
BigInt d(RSA::solveModularLinearEquation(e, BigIntOne, phi));
//we need a positive private exponent
if (!d.IsPositive())
return RSA::GenerateKeyPair(digitCount, k);
//we can create the private key
//d is the private key exponent, n is the modulus
Key privateKey(n, d);
//finally, the keypair is created and returned
KeyPair newKeyPair(privateKey, publicKey);
return newKeyPair;
}

View File

@ -1,112 +0,0 @@
/* ****************************************************************************
*
* RSA.h
*
* Author: Nedim Srndic
* Release date: 16th of June 2008
*
* An implementation of the RSA public-key cryptography algorithm.
*
* RSA supports:
*
* - Message encryption (string and file) (Encrypt())
* - Message decryption (string and file) (Decrypt())
* - Public/private keypair generation (GenerateKeyPair())
*
* NOTE: All methods are static. Instantiation, copying and assignment of
* objects of type RSA is forbidden.
*
* NOTE: it is highly recommended to call
* std::srand(time(NULL));
* once when the program starts and before any use of methods provided by the
* RSA class. Calling the srand() function randomizes the standard C++
* pseudorandom number generator, so that it provides different series of
* pseudorandom numbers every time the program is run. This greatly improves
* security.
*
* ****************************************************************************
*/
#ifndef RSA_H_
#define RSA_H_
#include <string>
#include <fstream>
#include "KeyPair.h"
#include "Key.h"
#include "BigInt.h"
class RSA
{
private:
/* Instantiation of objects of type RSA is forbidden. */
RSA()
{}
/* Copying of objects of type RSA is forbidden. */
RSA(const RSA &rsa);
/* Assignment of objects of type RSA is forbidden. */
RSA &operator=(const RSA &rsa);
/* Returns the greatest common divisor of the two arguments
* "a" and "b", using the Euclidean algorithm. */
static BigInt GCD(const BigInt &a, const BigInt &b);
/* Solves the equation
* d = ax + by
* given a and b, and returns d, x and y by reference.
* It uses the Extended Euclidean Algorithm */
static void extendedEuclideanAlgorithm( const BigInt &a,
const BigInt &b,
BigInt &d,
BigInt &x,
BigInt &y);
/* Solves the equation
* ax is congruent to b (mod n),
* given a, b and n finds x. */
static BigInt solveModularLinearEquation( const BigInt &a,
const BigInt &b,
const BigInt &n);
/* Throws an exception if "key" is too short to be used. */
static void checkKeyLength(const Key &key);
/* Transforms a std::string message into a BigInt message. */
static BigInt encode(const std::string &message);
/* Transforms a BigInt cyphertext into a std::string cyphertext. */
static std::string decode(const BigInt &message);
/* Encrypts a "chunk" (a small part of a message) using "key" */
static std::string encryptChunk(const std::string &chunk,
const Key &key);
/* Decrypts a "chunk" (a small part of a message) using "key" */
static std::string decryptChunk(const BigInt &chunk,
const Key &key);
/* Encrypts a string "message" using "key". */
static std::string encryptString( const std::string &message,
const Key &key);
/* Decrypts a string "message" using "key". */
static std::string decryptString( const std::string &cypherText,
const Key &key);
/* Tests the file for 'eof', 'bad ' errors and throws an exception. */
static void fileError(bool eof, bool bad);
public:
/* Returns the string "message" RSA-encrypted using the key "key". */
static std::string Encrypt( const std::string &message,
const Key &key);
/* Encrypts the file "sourceFile" using the key "key" and saves
* the result into the file "destFile". */
static void Encrypt(const char *sourceFile,
const char *destFile,
const Key &key);
/* Decrypts the file "sourceFile" using the key "key" and saves
* the result into the file "destFile". */
static void Decrypt(const char *sourceFile,
const char *destFile,
const Key &key);
/* Returns the string "cypherText" RSA-decrypted
* using the key "key". */
static std::string Decrypt( const std::string &cypherText,
const Key &key);
/* Generates a public/private keypair. The keys are retured in a
* KeyPair. The generated keys are 'digitCount' or
* 'digitCount' + 1 digits long. */
static KeyPair GenerateKeyPair( unsigned long int digitCount,
unsigned long int k = 3);
};
#endif /*RSA_H_*/