RSA Cryptography
From Crypto++ Wiki
RSA is the work of Ron Rivest, Adi Shamir, and Leonard Adleman. It is based on the Integer Factorization Problem. The system was developed in 1977 and patented by the Massachusetts Institute of Technology. Though Rivest, Shamir, and Adleman are generally credited with the discovery, Clifford Cocks (Chief Mathematician at GCHQ - the British equivalent of the NSA) described the system in 1973. However, Cocks did not publish (the work was considered classified), so the credit lay with Rivest, Shamir, and Adleman.
Contents |
Mathematical Problem
The underlying mathematical problem of RSA is Integer Factorization [1].
Remarks
When encrypting and decrypting using Crypto++, the plaintext and ciphertext buffers can be the same. This effectively means you can do in-place encryption and decryption:
// Encrypt publicKey.Encrypt(rnd, (byte*)plainText, sizeof(byte) * plainTextLen, (byte*)plainText); int cipherTextSize = (int)publicKey.CiphertextLength(plainTextLen); // Decrypt DecodingResult result = privateKey.Decrypt(rnd, (byte*)plainText, cipherTextSize, (byte*)plainText); int plainTextSize = (int)result.messageLength;
However, always make sure the buffer is big enough to hold the encrypted data (which will be larger than the plaintext).
Usage
Plain Text Length
The maximum length of a plaintext string that can be encrypted with RSA can be determined by FixedMaxPlaintextLength().
Cipher Text Length
The length of the resulting ciphertext can be determined by FixedCiphertextLength().
Examples
Please see also BEREncode and BERDecode
Generate Keys - 1
std::string PrivateKeyFile = "key.pv";
std::string PublicKeyFile = "key.pb";
CryptoPP::AutoSeededRandomPool rng;
// Specify 512 bit modulus, accept e = 17
CryptoPP::RSAES_OAEP_SHA_Decryptor Decryptor( rng, 512 /*, e */ );
CryptoPP::HexEncoder privFile(new
CryptoPP::FileSink( PrivateKeyFile.c_str() )
); // Hex Encoder
Decryptor.DEREncode(privFile);
privFile.MessageEnd();
CryptoPP:: RSAES_OAEP_SHA_Encryptor Encryptor(Decryptor);
CryptoPP::HexEncoder pubFile(new
CryptoPP::FileSink( PublicKeyFile.c_str() )
); // Hex Encoder
Encryptor.DEREncode(pubFile);
pubFile.MessageEnd();
Generate Keys - 2
/////////////////////////////////////// // Pseudo Random Number Generator CryptoPP::AutoSeededRandomPool rng; /////////////////////////////////////// // Key Generation CryptoPP::InvertibleRSAFunction keys; keys.GenerateRandomWithKeySize( rng, 512 ); /////////////////////////////////////// // Generated Parameters CryptoPP::Integer n = keys.GetModulus(); CryptoPP::Integer p = keys.GetPrime1(); CryptoPP::Integer q = keys.GetPrime2(); CryptoPP::Integer d = keys.GetPrivateExponent(); CryptoPP::Integer e = keys.GetPublicExponent(); /////////////////////////////////////// // Dump std::cout << "RSA Parameters:" << std::endl; std::cout << " n: " << n << std::endl; std::cout << " p: " << p << std::endl; std::cout << " q: " << q << std::endl; std::cout << " d: " << d << std::endl; std::cout << " e: " << e << std::endl; std::cout << std::endl;
Dump Keys
std::string PrivateKeyFile = "key.pv"; std::string PublicKeyFile = "key.pb"; CryptoPP::FileSource pubFile( PublicKeyFile.c_str(), true, new CryptoPP::HexDecoder ); CryptoPP::FileSource privFile( PrivateKeyFile.c_str(), true, new CryptoPP::HexDecoder); CryptoPP::RSAES_OAEP_SHA_Decryptor Decryptor( privFile ); CryptoPP::RSAES_OAEP_SHA_Encryptor Encryptor ( pubFile ); std::cout << "n: " << Encryptor.GetTrapdoorFunction().GetModulus(); std::cout << std::endl; std::cout << "d: " << Decryptor.GetTrapdoorFunction().GetPrivateExponent(); std::cout << std::endl; std::cout << "e: " << Encryptor.GetTrapdoorFunction().GetPublicExponent(); std::cout << std::endl; std::cout << "p: " << Decryptor.GetTrapdoorFunction().GetPrime1(); std::cout << std::endl; std::cout << "q: " << Decryptor.GetTrapdoorFunction().GetPrime2(); std::cout << std::endl;
RSA Signature
CryptoPP::AutoSeededRandomPool rng;
std::string message = "Yoda said, Do or Do Not. There is not try.";
// Input: Private Key
std::string PrivateKeyFile = "key.pv";
// Output: Signed Message M
std::string SignedFile = "message.sig";
CryptoPP::FileSource privFile( PrivateKeyFile.c_str(), true,
new CryptoPP::HexDecoder);
CryptoPP::RSASSA_PKCS1v15_SHA_Signer priv(privFile);
// Sign Away...
CryptoPP::StringSource( message, true,
new CryptoPP::SignerFilter( rng, priv,
new CryptoPP::HexEncoder(
new CryptoPP::FileSink( SignedFile.c_str() )
) // HexEncoder
) // SignerFilter
); // StringSource
RSA Signature Verification
std::string PublicKeyFile = "key.pb";
std::string SignatureFile = "message.sig";
std::string message = "Yoda said, Do or Do Not. There is no try.";
// Inputs
CryptoPP::FileSource pubFile( PublicKeyFile.c_str(), true
new CryptoPP::HexDecoder );
CryptoPP::FileSource SignatureFile( SignatureFile.c_str()
true, new CryptoPP::HexDecoder);
// Verifier Object
CryptoPP::RSASSA_PKCS1v15_SHA_Verifier pub(pubFile);
// Sanity Check
if (SignatureFile.MaxRetrievable() != pub.SignatureLength() )
{ throw error; }
CryptoPP::SecByteBlock signature( pub.SignatureLength() )
SignatureFile.Get( signature, signature.size() );
// Setup
CryptoPP::VerifierFilter *verifierFilter =
new CryptoPP::VerifierFilter(pub);
verifierFilter->Put(signature, pub.SignatureLength());
// Invoke Verifier
CryptoPP::StringSource tmpSS( message, true, verifierFilter );
// Paydirt
if( false == verifierFilter->GetLastResult() )
{ throw error; }
RSA Signature Verification Given e and n
CryptoPP::RSASS<CryptoPP::PSS, CryptoPP::SHA>::Verifier pub(n, e);
CryptoPP::RSASS<CryptoPP::PSS, CryptoPP::SHA>::Verifier pub; pub.AccessKey().Initialize(n, e);
RSA Probabilistic Signature Scheme with Recovery
// Specify modulus, accept e = 17
CryptoPP::RSAES_OAEP_SHA_Decryptor Decryptor( rng, 384 /*, e */ );
CryptoPP::RSAES_OAEP_SHA_Encryptor Encryptor( Decryptor );
// BER Encoded Keys
std::string pubkey, prvkey;
{ // BER Encode Private Key
Decryptor.AccessKey().Save(
CryptoPP::HexEncoder(
new CryptoPP::StringSink( prvkey )
)
);
} // BER Encode Private Key
{ // BER Encode Public Key
Encryptor.AccessKey().Save(
CryptoPP::HexEncoder(
new CryptoPP::StringSink( pubkey )
)
);
} // BER Encode Public Key
// Signing
CryptoPP::StringSource s( prvkey, true, new CryptoPP::HexDecoder);
CryptoPP::RSASS<CryptoPP::PSSR, CryptoPP::SHA>::Signer signer( s );
CryptoPP::RSASS<CryptoPP::PSSR, CryptoPP::SHA>::Verifier verifier( signer );
// Setup
byte message[] = "Test";
unsigned int messageLen = sizeof(message);
// Sign
CryptoPP::SecByteBlock signature(signer.MaxSignatureLength(messageLen));
unsigned int signatureLen =
signer.SignMessageWithRecovery(rng, message, messageLen, NULL, 0, signature);
//Recover
CryptoPP::SecByteBlock recovered(
verifier.MaxRecoverableLengthFromSignatureLength(signatureLen)
);
// Verify
CryptoPP::DecodingResult result =
verifier.RecoverMessage(recovered, NULL, 0, signature, signatureLen);
if (!result.isValidCoding) { throw "Invalid Signature"; }
unsigned int recoveredLen = result.messageLength;
Sample Programs
RSA Key Generation
RSAKeyGen.zip - Generates a Public and Private key pair, and then saves to separate files after DER and Hex Encoding. Based on Wei Dai's example.
RSA Key Dump
RSADumpKeys.zip - Loads the DER and Hex Encoded Keys from disk, and dumps the parameters p, q, e, d, and n.
RSA Signature
RSASign.zip - Loads a DER and Hex Encoded Private Key from disk, signs a std::string message, and then writes the signature to disk after Hex Encoding.
RSA Signature Verification
RSASignVer.zip - Loads a Hex encoded Signature from disk, loads a DER and Hex Encoded Public Key from disk, and then verifies the signature.
RSA Probabilistic Signature Scheme with Recovery
RSAPSSR.zip - Demonstrates PSSR using RSA with OAEP and BER Encoded Keys - 3.6Kb
Keywords
RSA Sample Samples Example Examples Source Code Project Workspace
