RSA Signature Schemes

From Crypto++ Wiki
Jump to navigation Jump to search

For the main RSA page, visit RSA Cryptography. For encryption schemes, visit RSA Encryption Schemes. For a detailed treatment of key generation, loading, saving, validation, and formats, see Keys and Formats.

Sample Programs

The following is a handful of sample programs demonstrating ways to create keys, sign messages and verify messages.

The examples below use SHA256. You should avoid SHA1 because it is considered weak and wounded. You can use other HashTransformation derived hashes, like Whirlpool, SHA512, SHA3_256 or SHA3_512.

When pairing RSA modulus sizes with hashes, be sure to visit Security Levels. For example, RSA 1024 can be paired with SHA1 because the security levels are mostly equivalent. That is, neither the modulus or the hash is significantly weaker than the other.

Generate Keys

///////////////////////////////////////
// Pseudo Random Number Generator
AutoSeededRandomPool rng;

///////////////////////////////////////
// Generate Parameters
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, 3072);

///////////////////////////////////////
// Generated Parameters
Integer n = params.GetModulus();
Integer p = params.GetPrime1();
Integer q = params.GetPrime2();
Integer d = params.GetPrivateExponent();
Integer e = params.GetPublicExponent();

///////////////////////////////////////
// Dump
cout << "RSA Parameters:" << endl;
cout << " n: " << n << endl;
cout << " p: " << p << endl;
cout << " q: " << q << endl;
cout << " d: " << d << endl;
cout << " e: " << e << endl;
cout << endl;

///////////////////////////////////////
// Create Keys
RSA::PrivateKey privateKey(params);
RSA::PublicKey publicKey(params);

RSA Signature Scheme with Appendix

AutoSeededRandomPool rng;

InvertibleRSAFunction parameters;
parameters.GenerateRandomWithKeySize(rng, 3072);

RSA::PrivateKey privateKey(parameters);
RSA::PublicKey publicKey(parameters);

// Message
string message = "Yoda said, Do or Do Not. There is no try.";

// Signer object
RSASS<PSS, SHA256>::Signer signer(privateKey);

// Create signature space
size_t length = signer.MaxSignatureLength();
SecByteBlock signature(length);

// Sign message
length = signer.SignMessage(rng, (const byte*) message.c_str(),
    message.length(), signature);

// Resize now we know the true size of the signature
signature.resize(length);

// Verifier object
RSASS<PSS, SHA256>::Verifier verifier(publicKey);

// Verify
bool result = verifier.VerifyMessage((const byte*)message.c_str(),
    message.length(), signature, signature.size());

// Result
if(true == result) {
    cout << "Signature on message verified" << endl;
} else {
    cout << "Message verification failed" << endl;
}

RSA Signature Scheme with Appendix (Filters)

// Generate ot Load keys
RSA::PrivateKey privateKey = ...;
RSA::PublicKey publicKey = ...;

// Message
string message = "Yoda said, Do or Do Not. There is no try.";
string signature, recovered;

////////////////////////////////////////////////
// Sign and Encode
RSASS<PSS, SHA256>::Signer signer(privateKey);

StringSource ss1(message, true, 
    new SignerFilter(rng, signer,
        new StringSink(signature)
  ) // SignerFilter
); // StringSource

////////////////////////////////////////////////
// Verify and Recover
RSASS<PSS, SHA256>::Verifier verifier(publicKey);

StringSource ss2(message+signature, true,
    new SignatureVerificationFilter(
        verifier,
        new StringSink(recovered),
        SignatureVerificationFilter::THROW_EXCEPTION |
        SignatureVerificationFilter::PUT_MESSAGE
  ) // SignatureVerificationFilter
); // StringSource

////////////////////////////////////////////////
// No exception - use recovered message
...

RSA Probabilistic Signature Scheme with Recovery

////////////////////////////////////////////////
// Generate keys
AutoSeededRandomPool rng;

InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, 3072);

RSA::PrivateKey privateKey(params);
RSA::PublicKey publicKey(params);

// Signing      
RSASS<PSSR, SHA256>::Signer signer(privateKey);
RSASS<PSSR, SHA256>::Verifier verifier(publicKey);

// Setup
byte message[] = "RSA-PSSR Test";
size_t messageLen = sizeof(message);      

////////////////////////////////////////////////
// Sign and Encode
SecByteBlock signature(signer.MaxSignatureLength(messageLen));

size_t signatureLen = signer.SignMessageWithRecovery(rng, message,
    messageLen, NULL, 0, signature);

// Resize now we know the true size of the signature
signature.resize(signatureLen);

////////////////////////////////////////////////
// Verify and Recover
SecByteBlock recovered(
    verifier.MaxRecoverableLengthFromSignatureLength(signatureLen)
);

DecodingResult result = verifier.RecoverMessage(recovered, NULL,
    0, signature, signatureLen);

if (!result.isValidCoding) {
    throw Exception(Exception::OTHER_ERROR, "Invalid Signature");
}

////////////////////////////////////////////////
// Use recovered message
//  MaxSignatureLength is likely larger than messageLength
recovered.resize(result.messageLength);
...

RSA Probabilistic Signature Scheme with Recovery (Filter)

////////////////////////////////////////////////
// Generate or Load keys
RSA::PrivateKey privateKey = ...;
RSA::PublicKey publicKey = ...; 

////////////////////////////////////////////////
// Setup
string message = "RSA-PSSR Test", signature, recovered;    

////////////////////////////////////////////////
// Sign and Encode
RSASS<PSSR, SHA256>::Signer signer(privateKey);

StringSource ss1(message, true, 
    new SignerFilter(rng, signer,
        new StringSink(signature),
        true // putMessage for recovery
   ) // SignerFilter
); // StringSource

////////////////////////////////////////////////
// Verify and Recover
RSASS<PSSR, SHA256>::Verifier verifier(publicKey);

StringSource ss2(signature, true,
    new SignatureVerificationFilter(
        verifier,
        new StringSink(recovered),
        THROW_EXCEPTION | PUT_MESSAGE
   ) // SignatureVerificationFilter
); // StringSource

cout << "Verified signature on message" << endl;

RSA Signature Scheme (PKCS v1.5)

Though similar to RSA-SSA, RSASSA_PKCS1v15_SHA_Signer and RSASSA_PKCS1v15_SHA_Verifier uses PKCS v1.5 padding. The MD2 and MD5 variants of RSASSA_PKCS1v15_<Digest>_Signer and RSASSA_PKCS1v15_<Digest>_Verifier should not be used.

AutoSeededRandomPool rng;

InvertibleRSAFunction parameters;
parameters.GenerateRandomWithKeySize(rng, 3072);

RSA::PrivateKey privateKey(parameters);
RSA::PublicKey publicKey(parameters);

// Message
string message = "Yoda said, Do or Do Not. There is no try.";

// Signer object
RSASSA_PKCS1v15_SHA_Signer signer(privateKey);

// Create signature space
size_t length = signer.MaxSignatureLength();
SecByteBlock signature(length);

// Sign message
length = signer.SignMessage(rng, (const byte*) message.c_str(),
    message.length(), signature);

// Resize now we know the true size of the signature
signature.resize(length);

// Verifier object
RSASSA_PKCS1v15_SHA_Verifier verifier(publicKey);

// Verify
bool result = verifier.VerifyMessage((const byte*)message.c_str(),
    message.length(), signature, signature.size());

// Result
if(true == result) {
    cout << "Signature on message verified" << endl;
} else {
    cout << "Message verification failed" << endl;
}

RSA Signature Generation Given d and n

Given Integers d and n rather than a RSA::PrivateKey, perform the following to create a signer object [1]. Attempting to use a RSA::PrivateKey by calling Initialize (i.e., not factoring n) will result in an exception [2].

// Use InvertibleRSAFunction to factor 'n'
InvertibleRSAFunction params;
params.Initialize(n, e, d);

RSA::PrivateKey(params);

...

If the public exponent has been misplaced, common values for the exponent are 3 (Microsoft CAPI/C#), 17 (Crypto++), and 65535 (Java).

RSA Signature Verification Given e and n

Given Integers e and n rather than a RSA::PublicKey, perform the following to create a verifier object.

RSASS<PSS, SHA>::Verifier verifier(n, e);
RSASS<PSS, SHA>::Verifier verifier;
verifier.AccessKey().Initialize(n, e);

Bouncy Castle

If you are using Bouncy Castle and need to recover the signature under a PSSR scheme, then see Iso9796d2PssSigner class in the Org.BouncyCastle.Crypto.Signers namespace. Also see BouncyCastle RSA Probabilistic Signature Scheme with Recovery on Stack Overflow.

Downloads

RSA-SSA-Test.zip - Demonstrates RSA-SSA (Appendix) - 5KB

RSA-SSA-Filter-Test.zip - Demonstrates RSA-SSA (Appendix) using Filters - 5KB

RSA-PSSR-Test.zip - Demonstrates RSA-PSSR (Recovery) - 7KB

RSA-PSSR-Filter-Test.zip Demonstrates RSA-PSSR (Recovery) using Filters - 5KB

RSA-SSA-PKCSv15-Test.zip - Demonstrates RSA-SSA (PKCS v1.5) - 5KB