[Botan-devel] Thanks, minor issues & questions on RSA sign/verify padding, binary size

Paul Clark paul at packetship.com
Tue Oct 13 05:06:47 EDT 2009


Firstly, huge thanks to Jack for Botan and in particular the great 
documentation.  After struggling through the documentation for OpenSSL I 
can tell you it's a blessed relief to read well-written tutorial guides 
and reasonably complete Doxygen annotations...  and as an occasional 
technical author myself I know how hard it is to do, and keep up to date!

A couple of minor points from a first-time user:

- I downloaded 1.8.7 but it generates libbotan-1.8.2.so

- The examples of PKCS8::load_key in tutorial.pdf sec. 5.2.2 and api.pdf 
sec. 3.7.2 don't include the RNG parameter (actually, why does a loader 
need an RNG anyway?)

My current application for Botan is to mimic a simple document signing 
system (SHA1+RSA) that was originally developed in OpenSSL, to avoid the 
dependency on libcrypto which gives us horrendous version problems 
between Linux distributions.  Unfortunately when we first created the 
system we did it with SHA1 and RSA primitives ('encrypting' hash with 
public key, 'decrypting' with private key and comparing with actual 
hash) rather than proper sign/verify operations, and we need to retain 
compatibility with the OpenSSL version.

I have this working using sign() for 'encrypt' and verify() for 
'decrypt', but the output of the verify() is still padded to 127 bytes 
when of course the SHA1 should only be 20.  It looks like the last 20 
bytes match the original, so for now I'm just comparing those, but this 
seems rather unsatisfactory.  Is there an operation to remove the 
padding - essentially, to recover the original message?

Here's the relevant bits of my code... 

Signing:

    string text;                // The document text
    string private_key;   // The private key in encrypted PEM format
    string pass_phrase; // Passphrase from user

    Botan::LibraryInitializer botan("thread_safe=true");

    // Get RSA private key
    Botan::DataSource_Memory dsrc(private_key);
    Botan::AutoSeeded_RNG rng;
    Botan::Private_Key *key = Botan::PKCS8::load_key(dsrc, rng, 
pass_phrase);
    Botan::RSA_PrivateKey *pkey = dynamic_cast<Botan::RSA_PrivateKey 
*>(key);
    if (!pkey)
    {
      cerr << "Can't load RSA private key\n";
      return false;
    }

    // Get SHA1 of original text
    Botan::SHA_160 sha1;
    Botan::SecureVector<Botan::byte> digest =
      sha1.process((const Botan::byte *)text.data(), text.size());

    // Encrypt ('sign')
    Botan::SecureVector<Botan::byte> cipher =
      pkey->sign(digest.begin(), digest.size(), rng);

    Text::Base64 base64;
    encoded_sig = base64.encode(cipher.begin(), cipher.size(), 72, 
"\n    ");

(the last part is our own pretty-printing base64 implementation)

Verifying:

    string text;  // Document
    string sig;    // Base-64 encoded signature
    string public_key;  // PEM-encoded public key

    Botan::LibraryInitializer botan("thread_safe=true");

    // Get RSA public key
    Botan::DataSource_Memory dsrc(public_key);
    Botan::Public_Key *key = Botan::X509::load_key(dsrc);
    Botan::RSA_PublicKey *pkey = dynamic_cast<Botan::RSA_PublicKey *>(key);
    if (!pkey)
    {
      cerr << "Can't load RSA public key\n";
      return false;
    }

    // Get sig from base64
    Text::Base64 base64;
    string cipher;
    base64.decode(sig, cipher);

    // Decrypt ('verify')
    Botan::SecureVector<Botan::byte> decrypt =
      pkey->verify((const Botan::byte *)cipher.data(), cipher.size());

    // Get SHA1 of original text
    Botan::SHA_160 sha1;
    Botan::SecureVector<Botan::byte> digest =
      sha1.process((const Botan::byte *)text.data(), text.size());

    // Compare - padding in decrypt seems to be added at the beginning
    if (!memcmp(decrypt.end()-digest.size(), digest.begin(), digest.size()))
      // ... signature is valid ...

It's that last line that is worrying me - it seems arbitrary and prone 
to failure if for some reason the padding should change.  Also I know I 
could simply use "if (decrypt == digest)" if the padding was removed, 
which would be much nicer.

One last question:  On linking statically with libbotan.a my application 
size increases by about 2MB...  The above is all I'm currently using, so 
that seems a bit extreme.  Is there an easy way to shrink the library to 
just include the SHA1/RSA operations at build time or (better, in case 
we want to use it in other applications) initialise it in such a way 
that it doesn't pull in every possible algorithm at load time?

Many thanks again

Paul







More information about the botan-devel mailing list