SignatureVerificationFilter

From Crypto++ Wiki
Jump to: navigation, search

SignatureVerificationFilter is a generic interface that Crypto++ uses for verifying signatures. SignatureVerificationFilter is a PK_Verifier-derived class used to verify a digital signature on input data. The counterpart to a SignatureVerificationFilter is a SignerFilter.

The class reference for SignatureVerificationFilter can be found at the SignatureVerificationFilter Class Reference.

Constructor

SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation
    *attachment = NULL, word32 flags = DEFAULT_FLAGS)

The first parameter, verifier, is a reference to a PK_Verifier object, which is usually a public key. The second parameter, attachment, is a BufferedTransformation derived object which allows the filter to forward the verified data.

The third parameter, flags, is most interesting. The values and their meanings are as follows. Note that SIGNATURE_AT_BEGIN and SIGNATURE_AT_END are mutually exclusive.

  • DEFAULT_FLAGS = SIGNATURE_AT_BEGIN | PUT_RESULT.
  • SIGNATURE_AT_END (0)
    • specifies that the signature value will be located at the end of message
  • SIGNATURE_AT_BEGIN (1)
    • specifies that the signature value will be located at the beginning of message
  • PUT_MESSAGE (2)
    • specifies whether the message should be forwarded to the attached transformation
  • PUT_SIGNATURE (4)
    • specifies whether the the signature should be forwarded to the attached transformation
  • PUT_RESULT (8)
    • specifies whether the result of the verification (a boolean) should be forwarded to the attached transformation
  • THROW_EXCEPTION (16)
    • specifies whether an exception should be thrown if signature verification fails

Signature Generation and Verification

In the following examples, it is presumed that PublicKey and PrivateKey have been properly initialized as either DSA::PublicKey or DSA::PrivateKey, where appropriate. For details of key generation, verification, formats, loading, and saving, see Keys and Formats.

Most samples are written in the context of DSA, so please refer to the Digital Signature Algorithm for details of key generation. One sample uses RSA and its message recovery mechanism. Details of RSA can be found at RSA Cryptography.

Verification with THROW_EXCEPTION

The first three samples are based on Crypto++ throwing an exception when verification fails, so an exception handler for SignatureVerificationFailed should be in place. Since the filter is throwing, the SignatureVerificationFilter is constructed using the THROW_EXCEPTION flag.

// Generate or Load the Public and Private Keys
DSA::PrivateKey privateKey; 
DSA::PublicKey publicKey;
...

string message = "DSA Signature";
string signature;

DSA::Signer signer(privateKey);
StringSource ss1(message, true, 
    new SignerFilter(rng, signer,
        new StringSink(signature)
   ) // SignerFilter
); // StringSource

DSA::Verifier verifier(publicKey);
StringSource ss2(message+signature, true,
    new SignatureVerificationFilter(
        verifier, NULL, THROW_EXCEPTION
        /* SIGNATURE_AT_END */
   )
);

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

In the example above, the filter receives a concatenation of message+signature. When SIGNATURE_AT_BEGIN is not specified in the constructor, SIGNATURE_AT_END is implied and the signature to be verified must be presented after the message. If the signature is inserted first, SIGNATURE_AT_BEGIN must be be specified as an additional flags value as shown below.

...

DSA::Verifier verifier(publicKey);
StringSource ss(signature+message, true,
    new SignatureVerificationFilter(
        verifier, NULL,
        THROW_EXCEPTION | SIGNATURE_AT_BEGIN
   )
);

The final example uses RSA and its Signature Scheme with Recovery to exercise PUT_MESSAGE. In a recovery scheme, the message is interleaved with the signature through use of a Redundancy Function. Because the message is present in the signature, a StringSink was added to recover the message.

In the example below, note that the SignerFilter constructor specifies all arguments, including putMessage=true. See SignerFilter Class Reference.

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

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

////////////////////////////////////////////////
// Sign and Encode
RSASS<PSSR, SHA1>::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, SHA1>::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;

Verification without THROW_EXCEPTION

The remaining two samples verify the signature without throwing an exception. This first sample uses the PUT_RESULT flag. Using this flag will instruct the SignatureVerificationFilter to forward the result of the verification to its attached transformation. In the sample below, the result is pipelined into the bool value result. To facilitate the pipeline, the variable is wrapped in an ArraySink.

There are three points to observe below. First, it does not make sense to specify both PUT_RESULT and THROW_EXCEPTION as a flag. Second, a StringSink cannot be used since the boolean variable does not derive from std::basic_string. Finally, because PUT_RESULT is being used, message recovery (using PUT_MESSAGE) is not available.

...

DSA::Verifier verifier(publicKey);

bool result = false;
StringSource ss(message+signature, true,
    new SignatureVerificationFilter(
        verifier,
        new ArraySink(
            (byte*)&result, sizeof(result)),
        PUT_RESULT | SIGNATURE_AT_END
   )
);

if(true == result) {
    cout << "Verified signature on message" << endl;
}

The final example uses a little known sink called a Redirector. The Redirector does not own its attached BufferedTransformation, so the attached object is not deleted (as a consequence of the behavior, the Redirector takes a reference and not a pointer). It is useful when an intermediate result is required from an object that would otherwise be participating in pipelining.

...

DSA::Verifier verifier(publicKey);
SignatureVerificationFilter svf(
    verifier
); // SignatureVerificationFilter

StringSource ss(signature+message, true,
    new Redirector(svf)
); // StringSource

if(true == svf.GetLastResult()) {
    cout << "Verified signature on message" << endl;
}

Downloads

DSA-Test.zip Crypto++ DSA sample program - 5KB

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

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