[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