Click here to Skip to main content
15,889,838 members
Articles / Desktop Programming / Win32

Cryptographic Interoperability: Digital Signatures

Rate me:
Please Sign up or sign in to vote.
4.98/5 (48 votes)
20 Oct 2009CPOL21 min read 220.2K   12.4K   176  
Sign and verify messages using Crypto++, Java, and C#.
// CryptoPP.cpp
//
#include "stdafx.h"

#include <dsa.h>
using CryptoPP::DSA;
using CryptoPP::DSA_DER;
using CryptoPP::DSA_P1363;

#include <pubkey.h>
using CryptoPP::PrivateKey;
using CryptoPP::PublicKey;

#include <osrng.h>
using CryptoPP::AutoSeededRandomPool;

#include <files.h>
using CryptoPP::FileSource;
using CryptoPP::FileSink;
using CryptoPP::StringSource;
using CryptoPP::StringSink;

bool CreateDSAKeys();
bool SignDSAMessage();
bool VerifyDSAMessage();

int main(int argc, char* argv[])
{
    CreateDSAKeys();

    SignDSAMessage();

    VerifyDSAMessage();

    return 0;
}

bool CreateDSAKeys()
{
    AutoSeededRandomPool prng;

    try
    {
        // Crypto++ Key Generation
        DSA::Signer signer;        
        PrivateKey& privateKey = signer.AccessPrivateKey();
        privateKey.GenerateRandom( prng );

        DSA::Verifier verifier( signer );
        PublicKey& publicKey = verifier.AccessPublicKey();

        // Crypto++ Save Keys
        privateKey.Save(FileSink("private.dsa.cpp.key"));
        publicKey.Save(FileSink("public.dsa.cpp.key"));
    }

    catch( CryptoPP::Exception& ex )
    {
        cerr << "Caught Error:" << endl;
        cerr << " " << ex.what() << endl;

        return false;
    }

    catch( std::exception& ex )
    {
        cerr << "Caught Error:" << endl;
        cerr << " " << ex.what() << endl;

        return false;
    }

    return true;
}


bool VerifyDSAMessage()
{
    try
    {
        //
        // Crypto++ Load the Pubic Key
        //
        DSA::Verifier verifier;
        PublicKey& publicKey = verifier.AccessPublicKey();

        // publicKey.Load(FileSource("public.dsa.cpp.key", true));
        // publicKey.Load(FileSource("public.dsa.java.key", true));
        publicKey.Load(FileSource("public.dsa.cs.key", true));

        //
        // Retrieve the Message and the Signature on Message
        //
        string message, signature;

        // C++
        FileSource( "dsa.cpp.msg", true, new StringSink( message ) );
        FileSource( "dsa.cpp.sig", true, new StringSink( signature ) );

        // Java
        // FileSource( "dsa.java.msg", true, new StringSink( message ) );
        // FileSource( "dsa.java.sig", true, new StringSink( signature ) );

        // C#
        // FileSource( "dsa.cs.msg", true, new StringSink( message ) );
        // FileSource( "dsa.cs.sig", true, new StringSink( signature ) );

        //*
        // --- Begin Java Specific Conversion ---

        //
        // Convert: DER -> P1363
        //

        // Java is DER Encoded Sequence.
        // Crypto++ is P1363 format.
        /*
        {            
            // From dsa.h: If toFormat == DSA_P1363,
            //   bufferSize must equal publicKey.SignatureLength()
            size_t length = verifier.SignatureLength();

            // A buffer for the conversion
            byte* buffer = new byte[ length ];

            // Shit or Go Blind. You make the choice.
            if( !buffer ) { return false; }

            // Reuse length
            length = CryptoPP::DSAConvertSignatureFormat( 
                buffer, length, DSA_P1363, (const byte*)signature.c_str(),
                signature.length(), DSA_DER );
            
            // Reinitialize signature so that it can be used
            //   in the verifier below with minimal effort
            signature = string( (const char*)buffer, length );
            delete[] buffer;
        }
        */
        // --- End Java Specific Conversion ---
        //*/

        //
        // Verify the Signature on the Message
        //
        bool result = verifier.VerifyMessage(
            (const byte*)message.c_str(), message.length(),
            (const byte*)signature.c_str(), signature.length() );

        if( result )
        {
            cout << "Signature on Message verified" << endl;
        }
        else
        {
            cerr << "Signature on Message not verified" << endl;
            
            return false;
        }

        //
        // Convert the Message
        //
        int nChars = MultiByteToWideChar( CP_UTF8, 0,
            message.c_str(), -1, NULL, NULL );

        wchar_t* p = new wchar_t[ nChars ];
        if( !p ) { return false; }

        MultiByteToWideChar( CP_UTF8, 0, message.c_str(), -1, p, nChars );
        wstring wide( p );

        delete[] p;

    }

    catch( CryptoPP::Exception& ex )
    {
        cerr << "Caught Error:" << endl;
        cerr << " " << ex.what() << endl;

        return false;
    }

    catch( std::exception& ex )
    {
        cerr << "Caught Error:" << endl;
        cerr << " " << ex.what() << endl;

        return false;
    }

    return true;
}

bool SignDSAMessage()
{
    try
    {
        //
        // Crypto++ Load Private Key
        //
        DSA::Signer signer;        
        PrivateKey& privateKey = signer.AccessPrivateKey();        
        privateKey.Load(FileSource("private.dsa.cpp.key", true));
        
        // Convert the Message
        wstring wide = L"Crypto Interop: \u9aa8";
        int nChars = WideCharToMultiByte( CP_UTF8, 0,
            wide.c_str(), -1, NULL, 0, NULL, FALSE );

        char* p = new char[ nChars ];
        if( !p ) { return false; }

        nChars = WideCharToMultiByte( CP_UTF8, 0,
            wide.c_str(), -1, p, nChars, NULL, FALSE );

        string narrow( p );
        delete[] p;

        //
        // Sign the Message
        //

        // Set up for SignMessage()
        byte* s = new byte[ signer.MaxSignatureLength() ];
        if( !s ) { return false; }

        // Sign...
        AutoSeededRandomPool prng;
        size_t length = signer.SignMessage( prng,
            (const byte*) narrow.c_str(), narrow.length(), s );

        // Convenience
        string signature( (const char*)s, length );

        // --- Begin Java Specific Conversion ---

        //
        // Convert: P1363 -> DER
        //

        // Crypto++ uses P1363 format.
        // Java requires a DER encoded sequence.
        /*
        {
            // Determine size of required buffer
            // We can call with a null buffer and 0 size
            // when going in this direction
            length = CryptoPP::DSAConvertSignatureFormat( 
                NULL, 0, DSA_DER, (const byte*)signature.c_str(),
                signature.length(), DSA_P1363 );

            // A buffer for the conversion
            byte* buffer = new byte[ length ];

            // Shit or Go Blind. You make the choice.
            if( !buffer ) { return false; }

            // Reuse length
            length = CryptoPP::DSAConvertSignatureFormat( 
                buffer, length, DSA_DER, (const byte*)signature.c_str(),
                signature.length(), DSA_P1363 );
            
            // Reinitialize signature so that it can be used
            //   in the verifier below with minimal effort
            signature = string( (const char*)buffer, length );
            delete[] buffer;
        }
        */
        // --- End Java Specific Conversion ---

        //
        // Save the Message and the Signature on Message
        //

        // mofs: message filestream
        // sofs: signature filestream
        ofstream mofs, sofs;
        mofs.open("dsa.cpp.msg", ios_base::binary | ios_base::trunc );
        sofs.open("dsa.cpp.sig", ios_base::binary | ios_base::trunc );

        // Save Original Message
        mofs.write( narrow.c_str(), (int)narrow.length() );

        // Save Signature on Message
        sofs.write( (const char*)signature.c_str(), (int)length );

        // Cleanup
        sofs.close();
        mofs.close();
    }

    catch( CryptoPP::Exception& ex )
    {
        cerr << "Caught Error:" << endl;
        cerr << " " << ex.what() << endl;

        return false;
    }

    catch( std::exception& ex )
    {
        cerr << "Caught Error:" << endl;
        cerr << " " << ex.what() << endl;

        return false;
    }

    return true;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems / Hardware Administrator
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions