Improve RSADigestEngine, using Poco::Crypto::DigestEngine to calculate

the hash before signing. That way we can then support RSA signatures
with any hash supported by OpenSSL, not only MD5 and SHA1. It was also
required a new method on DigestEngine to obtain the NID (numeric ID) of
the algorithm, to be used on the OpenSSL RSA_sign call.
This commit is contained in:
Cristian Thiago Moecke
2014-02-21 04:43:05 -08:00
parent 0ad18f3e80
commit 53e6d9efaa
6 changed files with 56 additions and 15 deletions

View File

@@ -67,6 +67,9 @@ public:
const std::string& algorithm() const; const std::string& algorithm() const;
/// Returns the name of the digest algorithm. /// Returns the name of the digest algorithm.
int nid() const;
/// Returns the NID (OpenSSL object identifier) of the digest algorithm.
// DigestEngine // DigestEngine
std::size_t digestLength() const; std::size_t digestLength() const;
void reset(); void reset();

View File

@@ -43,8 +43,7 @@
#include "Poco/Crypto/Crypto.h" #include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/RSAKey.h" #include "Poco/Crypto/RSAKey.h"
#include "Poco/DigestEngine.h" #include "Poco/DigestEngine.h"
#include "Poco/MD5Engine.h" #include "Poco/Crypto/DigestEngine.h"
#include "Poco/SHA1Engine.h"
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <istream> #include <istream>
#include <ostream> #include <ostream>
@@ -58,10 +57,10 @@ class Crypto_API RSADigestEngine: public Poco::DigestEngine
/// This class implements a Poco::DigestEngine that can be /// This class implements a Poco::DigestEngine that can be
/// used to compute a secure digital signature. /// used to compute a secure digital signature.
/// ///
/// First another Poco::DigestEngine (Poco::MD5Engine /// First another Poco::Crypto::DigestEngine is created and
/// or Poco::SHA1Engine) is used to compute a cryptographic /// used to compute a cryptographic hash of the data to be
/// hash of the data to be signed. Then, the hash value is /// signed. Then, the hash value is encrypted, using
/// encrypted, using the RSA private key. /// the RSA private key.
/// ///
/// To verify a signature, pass it to the verify() /// To verify a signature, pass it to the verify()
/// member function. It will decrypt the signature /// member function. It will decrypt the signature
@@ -75,9 +74,19 @@ public:
DIGEST_SHA1 DIGEST_SHA1
}; };
//@ deprecated
RSADigestEngine(const RSAKey& key, DigestType digestType = DIGEST_SHA1); RSADigestEngine(const RSAKey& key, DigestType digestType = DIGEST_SHA1);
/// Creates the RSADigestEngine with the given RSA key, /// Creates the RSADigestEngine with the given RSA key,
/// using the SHA-1 hash algorithm. /// using the MD5 or SHA-1 hash algorithm.
/// Kept for backward compatibility
RSADigestEngine(const RSAKey& key, const std::string &name);
/// Creates the RSADigestEngine with the given RSA key,
/// using the hash algorithm with the given name
/// (e.g., "MD5", "SHA1", "SHA256", "SHA512", etc.).
/// See the OpenSSL documentation for a list of supported digest algorithms.
///
/// Throws a Poco::NotFoundException if no algorithm with the given name exists.
~RSADigestEngine(); ~RSADigestEngine();
/// Destroys the RSADigestEngine. /// Destroys the RSADigestEngine.
@@ -113,12 +122,9 @@ protected:
private: private:
RSAKey _key; RSAKey _key;
Poco::DigestEngine& _engine; Poco::Crypto::DigestEngine _engine;
int _type;
Poco::DigestEngine::Digest _digest; Poco::DigestEngine::Digest _digest;
Poco::DigestEngine::Digest _signature; Poco::DigestEngine::Digest _signature;
Poco::MD5Engine _md5Engine;
Poco::SHA1Engine _sha1Engine;
}; };

View File

@@ -57,6 +57,10 @@ DigestEngine::~DigestEngine()
EVP_MD_CTX_destroy(_ctx); EVP_MD_CTX_destroy(_ctx);
} }
int DigestEngine::nid() const
{
return EVP_MD_nid(_ctx->digest);
}
std::size_t DigestEngine::digestLength() const std::size_t DigestEngine::digestLength() const
{ {

View File

@@ -36,6 +36,7 @@
#include "Poco/Crypto/RSADigestEngine.h" #include "Poco/Crypto/RSADigestEngine.h"
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/evp.h>
namespace Poco { namespace Poco {
@@ -44,8 +45,13 @@ namespace Crypto {
RSADigestEngine::RSADigestEngine(const RSAKey& key, DigestType digestType): RSADigestEngine::RSADigestEngine(const RSAKey& key, DigestType digestType):
_key(key), _key(key),
_engine(digestType == DIGEST_MD5 ? static_cast<Poco::DigestEngine&>(_md5Engine) : static_cast<Poco::DigestEngine&>(_sha1Engine)), _engine(digestType == DIGEST_MD5 ? "MD5" : "SHA1")
_type(digestType == DIGEST_MD5 ? NID_md5 : NID_sha1) {
}
RSADigestEngine::RSADigestEngine(const RSAKey& key, const std::string &algorithm):
_key(key),
_engine(algorithm)
{ {
} }
@@ -86,7 +92,7 @@ const DigestEngine::Digest& RSADigestEngine::signature()
digest(); digest();
_signature.resize(_key.size()); _signature.resize(_key.size());
unsigned sigLen = static_cast<unsigned>(_signature.size()); unsigned sigLen = static_cast<unsigned>(_signature.size());
RSA_sign(_type, &_digest[0], static_cast<unsigned>(_digest.size()), &_signature[0], &sigLen, _key.impl()->getRSA()); RSA_sign(_engine.nid(), &_digest[0], static_cast<unsigned>(_digest.size()), &_signature[0], &sigLen, _key.impl()->getRSA());
// truncate _sig to sigLen // truncate _sig to sigLen
if (sigLen < _signature.size()) if (sigLen < _signature.size())
_signature.resize(sigLen); _signature.resize(sigLen);
@@ -99,7 +105,7 @@ bool RSADigestEngine::verify(const DigestEngine::Digest& sig)
{ {
digest(); digest();
DigestEngine::Digest sigCpy = sig; // copy becausse RSA_verify can modify sigCpy DigestEngine::Digest sigCpy = sig; // copy becausse RSA_verify can modify sigCpy
int ret = RSA_verify(_type, &_digest[0], static_cast<unsigned>(_digest.size()), &sigCpy[0], static_cast<unsigned>(sigCpy.size()), _key.impl()->getRSA()); int ret = RSA_verify(_engine.nid(), &_digest[0], static_cast<unsigned>(_digest.size()), &sigCpy[0], static_cast<unsigned>(sigCpy.size()), _key.impl()->getRSA());
return ret != 0; return ret != 0;
} }

View File

@@ -149,6 +149,26 @@ void RSATest::testSign()
} }
void RSATest::testSignSha256()
{
std::string msg("Test this sign message");
RSAKey key(RSAKey::KL_2048, RSAKey::EXP_LARGE);
RSADigestEngine eng(key,"SHA256");
eng.update(msg.c_str(), static_cast<unsigned>(msg.length()));
const Poco::DigestEngine::Digest& sig = eng.signature();
std::string hexDig = Poco::DigestEngine::digestToHex(sig);
// verify
std::ostringstream strPub;
key.save(&strPub);
std::string pubKey = strPub.str();
std::istringstream iPub(pubKey);
RSAKey keyPub(&iPub);
RSADigestEngine eng2(key,"SHA256");
eng2.update(msg.c_str(), static_cast<unsigned>(msg.length()));
assert (eng2.verify(sig));
}
void RSATest::testSignManipulated() void RSATest::testSignManipulated()
{ {
std::string msg("Test this sign message"); std::string msg("Test this sign message");
@@ -244,6 +264,7 @@ CppUnit::Test* RSATest::suite()
CppUnit_addTest(pSuite, RSATest, testNewKeys); CppUnit_addTest(pSuite, RSATest, testNewKeys);
CppUnit_addTest(pSuite, RSATest, testSign); CppUnit_addTest(pSuite, RSATest, testSign);
CppUnit_addTest(pSuite, RSATest, testSignSha256);
CppUnit_addTest(pSuite, RSATest, testSignManipulated); CppUnit_addTest(pSuite, RSATest, testSignManipulated);
CppUnit_addTest(pSuite, RSATest, testRSACipher); CppUnit_addTest(pSuite, RSATest, testRSACipher);
CppUnit_addTest(pSuite, RSATest, testRSACipherLarge); CppUnit_addTest(pSuite, RSATest, testRSACipherLarge);

View File

@@ -48,6 +48,7 @@ public:
void testNewKeys(); void testNewKeys();
void testSign(); void testSign();
void testSignSha256();
void testSignManipulated(); void testSignManipulated();
void testRSACipher(); void testRSACipher();
void testRSACipherLarge(); void testRSACipherLarge();