Crypto_Win (compile only, WIP)

This commit is contained in:
Alex Fabijanic 2015-02-09 20:42:31 -06:00
parent 5f9a2cb6c3
commit 06d18d2b9c
10 changed files with 227 additions and 97 deletions

View File

@ -48,7 +48,7 @@ public:
Cipher* createCipher(const CipherKey& key);
/// Creates a Cipher object for the given CipherKey.
//Cipher* createCipher(const RSAKey& key, RSAPaddingMode paddingMode = RSA_PADDING_PKCS1);
Cipher* createCipher(const RSAKey& key, RSAPaddingMode paddingMode = RSA_PADDING_PKCS1);
/// Creates a RSACipher using the given RSA key and padding mode
/// for public key encryption/private key decryption.

View File

@ -57,12 +57,12 @@ public:
/// Returns the name of the digest algorithm.
// DigestEngine
unsigned digestLength() const;
std::size_t digestLength() const;
void reset();
const Poco::DigestEngine::Digest& digest();
protected:
void updateImpl(const void* data, unsigned length);
void updateImpl(const void* data, std::size_t length);
private:
ServiceProvider _sp;

View File

@ -61,7 +61,7 @@ public:
~RSADigestEngine();
/// Destroys the RSADigestEngine.
unsigned digestLength() const;
std::size_t digestLength() const;
/// Returns the length of the digest in bytes.
void reset();
@ -88,16 +88,16 @@ public:
/// Returns true if the signature can be verified, false otherwise.
protected:
void updateImpl(const void* data, unsigned length);
void updateImpl(const void* data, std::size_t length);
private:
RSAKey _key;
Poco::DigestEngine& _engine;
int _type;
RSAKey _key;
Poco::DigestEngine& _engine;
LPSTR _type;
Poco::DigestEngine::Digest _digest;
Poco::DigestEngine::Digest _signature;
Poco::MD5Engine _md5Engine;
Poco::SHA1Engine _sha1Engine;
Poco::MD5Engine _md5Engine;
Poco::SHA1Engine _sha1Engine;
};

View File

@ -28,12 +28,12 @@
#include <ostream>
#include <vector>
/*
struct bignum_st;
struct rsa_st;
typedef struct bignum_st BIGNUM;
typedef struct rsa_st RSA;
*/
namespace Poco {
namespace Crypto {
@ -90,6 +90,8 @@ public:
/// Returns the underlying Windows-specific handle for the public key.
protected:
const ServiceProvider& serviceProvider() const;
void loadPrivateKey(std::istream& istr);
void loadPublicKey(std::istream& istr);
void savePrivateKey(std::ostream& ostr);
@ -99,19 +101,28 @@ private:
ServiceProvider _sp;
HCRYPTKEY _hPrivateKey;
HCRYPTKEY _hPublicKey;
friend class RSACipherImpl;
};
//
// inlines
//
HCRYPTKEY RSAKeyImpl::privateKey() const
inline const ServiceProvider& RSAKeyImpl::serviceProvider() const
{
return _sp;
}
inline HCRYPTKEY RSAKeyImpl::privateKey() const
{
return _hPrivateKey;
}
HCRYPTKEY RSAKeyImpl::publicKey() const
inline HCRYPTKEY RSAKeyImpl::publicKey() const
{
return _hPublicKey;
}

View File

@ -17,9 +17,9 @@
#include "Poco/Crypto/CipherFactory.h"
#include "Poco/Crypto/Cipher.h"
#include "Poco/Crypto/CipherKey.h"
//#include "Poco/Crypto/RSAKey.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/Crypto/CipherImpl.h"
//#include "Poco/Crypto/RSACipherImpl.h"
#include "Poco/Crypto/RSACipherImpl.h"
#include "Poco/Exception.h"
#include "Poco/SingletonHolder.h"
@ -55,12 +55,11 @@ Cipher* CipherFactory::createCipher(const CipherKey& key)
return new CipherImpl(key);
}
// TODO RSA
/*
Cipher* CipherFactory::createCipher(const RSAKey& key, RSAPaddingMode paddingMode)
{
return new RSACipherImpl(key, paddingMode);
}
*/
} } // namespace Poco::Crypto

View File

@ -580,7 +580,7 @@ void CipherKeyImpl::generateKey(
int keySz = keySize();
int ivSz = ivSize();
int requiredSz = keySz + ivSz;
int availableSz = d.size();
int availableSz = static_cast<int>(d.size());
int k = 1;
Poco::DigestEngine::Digest extraD(d);
while (availableSz < requiredSz)
@ -596,7 +596,7 @@ void CipherKeyImpl::generateKey(
md5.update(&extraD[0], extraD.size());
extraD = md5.digest();
}
availableSz += extraD.size();
availableSz += static_cast<int>(extraD.size());
d.insert(d.end(), extraD.begin(), extraD.end());
}
@ -686,7 +686,7 @@ void CipherKeyImpl::importKey()
HCRYPTKEY hPubPrivKey = 0;
BOOL rc = CreatePrivateExponentOneKey(_sp.handle(), AT_KEYEXCHANGE, &hPubPrivKey);
if (!rc) throw Poco::SystemException("cannot create private key for importing key", GetLastError());
rc = ImportPlainSessionBlob(_sp.handle(), hPubPrivKey, _id, &_key[0], _key.size(), &_hKey);
rc = ImportPlainSessionBlob(_sp.handle(), hPubPrivKey, _id, &_key[0], static_cast<DWORD>(_key.size()), &_hKey);
CryptDestroyKey(hPubPrivKey);
if (!rc) throw Poco::SystemException("cannot import key", GetLastError());
}

View File

@ -37,12 +37,12 @@ DigestEngine::~DigestEngine()
}
unsigned DigestEngine::digestLength() const
std::size_t DigestEngine::digestLength() const
{
DWORD hashLen;
DWORD len = sizeof(hashLen);
if (CryptGetHashParam(_handle, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashLen), &len, 0))
return static_cast<unsigned>(hashLen);
return static_cast<std::size_t>(hashLen);
else
throw Poco::SystemException("Failed to obtain hash size", GetLastError());
}
@ -80,9 +80,9 @@ void DigestEngine::reset()
const Poco::DigestEngine::Digest& DigestEngine::digest()
{
_digest.clear();
unsigned hashLen = digestLength();
std::size_t hashLen = digestLength();
_digest.resize(hashLen);
DWORD len = hashLen;
DWORD len = static_cast<DWORD>(hashLen);
if (!CryptGetHashParam(_handle, HP_HASHVAL, &_digest[0], &len, 0))
throw Poco::SystemException("Failed to obtain hash", GetLastError());
reset();
@ -90,9 +90,9 @@ const Poco::DigestEngine::Digest& DigestEngine::digest()
}
void DigestEngine::updateImpl(const void* data, unsigned length)
void DigestEngine::updateImpl(const void* data, std::size_t length)
{
if (!CryptHashData(_handle, reinterpret_cast<const BYTE*>(data), length, 0))
if (!CryptHashData(_handle, reinterpret_cast<const BYTE*>(data), static_cast<DWORD>(length), 0))
throw Poco::SystemException("Failed to hash data", GetLastError());
}

View File

@ -16,6 +16,7 @@
#include "Poco/Crypto/RSACipherImpl.h"
#include "Poco/Crypto/CryptoTransform.h"
#include "Poco/Error.h"
#include "Poco/Exception.h"
@ -29,43 +30,79 @@ namespace
{
void throwError()
{
unsigned long err;
std::string msg;
while ((err = ERR_get_error()))
{
if (!msg.empty())
msg.append("; ");
msg.append(ERR_error_string(err, 0));
}
throw Poco::IOException(msg);
DWORD err = Error::last();
std::string errStr = Error::getMessage(err);
throw Poco::IOException(errStr);
}
/*
int mapPaddingMode(RSAPaddingMode paddingMode)
{
switch (paddingMode)
{
case RSA_PADDING_PKCS1:
return RSA_PKCS1_PADDING;
return BCRYPT_PAD_PKCS1;
case RSA_PADDING_PKCS1_OAEP:
return RSA_PKCS1_OAEP_PADDING;
case RSA_PADDING_SSLV23:
return RSA_SSLV23_PADDING;
return BCRYPT_PAD_OAEP;
//case RSA_PADDING_SSLV23: ???
// return RSA_SSLV23_PADDING;
case RSA_PADDING_NONE:
return RSA_NO_PADDING;
return BCRYPT_PAD_NONE;
default:
poco_bugcheck();
return RSA_NO_PADDING;
return BCRYPT_PAD_NONE;
// BCRYPT_PAD_PSS ???
//
// ???
// #if (NTDDI_VERSION >= NTDDI_WINBLUE)
// #define BCRYPT_PAD_PKCS1_OPTIONAL_HASH_OID 0x00000010 //BCryptVerifySignature
// #endif
}
}
*/
std::size_t rsaBlockSize(const ServiceProvider& rsa)
{
BYTE* pbData = NULL;
DWORD dwDataLen = 0;
// ??? (from documentation) "This function must not be used on a thread of a multithreaded program." ???
if (CryptGetProvParam(rsa.handle(), PP_SESSION_KEYSIZE, NULL, &dwDataLen, 0))
{
std::vector<BYTE> data(dwDataLen);
pbData = &data[0];
if (CryptGetProvParam(rsa.handle(), PP_SESSION_KEYSIZE, pbData, &dwDataLen, 0))
{
// ??? what is in pbData? DWORD? BYTE? TODO: check at runtime
}
else // !CryptGetProvParam
{
DWORD err = Error::last();
std::string errStr = "[RSAEncryptImpl::blockSize()]: ";
errStr += Error::getMessage(err);
switch (err)
{
case ERROR_INVALID_HANDLE: case ERROR_INVALID_PARAMETER:
case ERROR_MORE_DATA: case NTE_BAD_FLAGS:
case NTE_BAD_TYPE: case NTE_BAD_UID:
throw Poco::InvalidArgumentException(errStr);
default:
throw Poco::SystemException(errStr);
}
}
} // !CryptGetProvParam length
else
{
throw Poco::SystemException("Cannot obtain length for block size value.");
}
return static_cast<std::size_t>(dwDataLen);
}
class RSAEncryptImpl: public CryptoTransform
{
public:
RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
RSAEncryptImpl(const ServiceProvider& rsa, RSAPaddingMode paddingMode);
~RSAEncryptImpl();
std::size_t blockSize() const;
@ -80,15 +117,17 @@ namespace
std::streamsize finalize(unsigned char* output, std::streamsize length);
private:
const RSA* _pRSA;
RSAPaddingMode _paddingMode;
std::streamsize _pos;
unsigned char* _pBuf;
DWORD encrypt(unsigned char* output, std::streamsize outputLength, BOOL isFinal);
const ServiceProvider& _rsa;
RSAPaddingMode _paddingMode;
std::streamsize _pos;
unsigned char* _pBuf;
};
RSAEncryptImpl::RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
_pRSA(pRSA),
RSAEncryptImpl::RSAEncryptImpl(const ServiceProvider& rsa, RSAPaddingMode paddingMode) :
_rsa(rsa),
_paddingMode(paddingMode),
_pos(0),
_pBuf(0)
@ -105,12 +144,13 @@ namespace
std::size_t RSAEncryptImpl::blockSize() const
{
return RSA_size(_pRSA);
return rsaBlockSize(_rsa);
}
std::size_t RSAEncryptImpl::maxDataSize() const
{
// ??? same as openssl?
std::size_t size = blockSize();
switch (_paddingMode)
{
@ -127,12 +167,27 @@ namespace
return size;
}
DWORD RSAEncryptImpl::encrypt(unsigned char* output, std::streamsize outputLength, BOOL isFinal)
{
DWORD n = static_cast<DWORD>(_pos + 1);
if (!CryptEncrypt(_rsa.handle(), NULL, isFinal, 0, NULL, &n, 0))
throwError();
poco_assert(n > _pos);
poco_assert_dbg(n <= maxDataSize());
std::vector<BYTE> data(n);
n = static_cast<DWORD>(_pos + 1);
std::memcpy(&data[0], _pBuf, n);
if (!CryptEncrypt(_rsa.handle(), NULL, isFinal, 0, &data[0], &n, n))
throwError();
poco_assert(n <= outputLength);
std::memcpy(output, &data[0], n);
return n;
}
std::streamsize RSAEncryptImpl::transform(
const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength)
std::streamsize RSAEncryptImpl::transform(const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength)
{
// always fill up the buffer before writing!
std::streamsize maxSize = static_cast<std::streamsize>(maxDataSize());
@ -148,14 +203,13 @@ namespace
if (missing == 0)
{
poco_assert (outputLength >= rsaSize);
int n = RSA_public_encrypt(static_cast<int>(maxSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
if (n == -1)
throwError();
//int n = 0;
//int n = RSA_public_encrypt(static_cast<int>(maxSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
DWORD n = encrypt(output, outputLength, FALSE);
rc += n;
output += n;
outputLength -= n;
_pos = 0;
}
else
{
@ -179,8 +233,9 @@ namespace
int rc = 0;
if (_pos > 0)
{
rc = RSA_public_encrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
if (rc == -1) throwError();
//rc = RSA_public_encrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
//if (rc == -1) throwError();
rc = encrypt(output, length, TRUE);
}
return rc;
}
@ -189,7 +244,7 @@ namespace
class RSADecryptImpl: public CryptoTransform
{
public:
RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
RSADecryptImpl(const ServiceProvider& rsa, RSAPaddingMode paddingMode);
~RSADecryptImpl();
std::size_t blockSize() const;
@ -205,15 +260,17 @@ namespace
std::streamsize length);
private:
const RSA* _pRSA;
RSAPaddingMode _paddingMode;
std::streamsize _pos;
unsigned char* _pBuf;
DWORD decrypt(unsigned char* output, std::streamsize outputLength, BOOL isFinal);
const ServiceProvider& _rsa;
RSAPaddingMode _paddingMode;
std::streamsize _pos;
unsigned char* _pBuf;
};
RSADecryptImpl::RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
_pRSA(pRSA),
RSADecryptImpl::RSADecryptImpl(const ServiceProvider& rsa, RSAPaddingMode paddingMode) :
_rsa(rsa),
_paddingMode(paddingMode),
_pos(0),
_pBuf(0)
@ -230,7 +287,24 @@ namespace
std::size_t RSADecryptImpl::blockSize() const
{
return RSA_size(_pRSA);
return rsaBlockSize(_rsa);
}
DWORD RSADecryptImpl::decrypt(unsigned char* output, std::streamsize outputLength, BOOL isFinal)
{
DWORD n = static_cast<DWORD>(_pos + 1);
if (!CryptDecrypt(_rsa.handle(), NULL, isFinal, 0, NULL, &n))
throwError();
poco_assert(n > _pos);
//poco_assert_dbg(n <= maxDataSize());
std::vector<BYTE> data(n);
n = static_cast<DWORD>(_pos + 1);
std::memcpy(&data[0], _pBuf, n);
if (!CryptDecrypt(_rsa.handle(), NULL, isFinal, 0, &data[0], &n))
throwError();
poco_assert(n <= outputLength);
std::memcpy(output, &data[0], n);
return n;
}
@ -253,7 +327,8 @@ namespace
std::streamsize missing = rsaSize - _pos;
if (missing == 0)
{
int tmp = RSA_private_decrypt(static_cast<int>(rsaSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
//int tmp = RSA_private_decrypt(static_cast<int>(rsaSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
DWORD tmp = decrypt(output, outputLength, FALSE);
if (tmp == -1)
throwError();
rc += tmp;
@ -283,7 +358,8 @@ namespace
int rc = 0;
if (_pos > 0)
{
rc = RSA_private_decrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
//rc = RSA_private_decrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
rc = decrypt(output, length, TRUE);
if (rc == -1)
throwError();
}
@ -306,13 +382,13 @@ RSACipherImpl::~RSACipherImpl()
CryptoTransform* RSACipherImpl::createEncryptor()
{
return new RSAEncryptImpl(_key.impl()->getRSA(), _paddingMode);
return new RSAEncryptImpl(_key.impl()->serviceProvider(), _paddingMode);
}
CryptoTransform* RSACipherImpl::createDecryptor()
{
return new RSADecryptImpl(_key.impl()->getRSA(), _paddingMode);
return new RSADecryptImpl(_key.impl()->serviceProvider(), _paddingMode);
}

View File

@ -14,10 +14,11 @@
//
#include "
// TODO: this is still OpenSSL code
#include "Poco/Crypto/RSADigestEngine.h"
#include "Poco/Format.h"
#include "Poco/Error.h"
#include "Poco/Base64Encoder.h"
#include <sstream>
namespace Poco {
@ -27,7 +28,7 @@ namespace Crypto {
RSADigestEngine::RSADigestEngine(const RSAKey& key, DigestType digestType):
_key(key),
_engine(digestType == DIGEST_MD5 ? static_cast<Poco::DigestEngine&>(_md5Engine) : static_cast<Poco::DigestEngine&>(_sha1Engine)),
_type(digestType == DIGEST_MD5 ? NID_md5 : NID_sha1)
_type(digestType == DIGEST_MD5 ? szOID_RSA_MD5 : szOID_ECDSA_SHA1)
{
}
@ -37,7 +38,7 @@ RSADigestEngine::~RSADigestEngine()
}
unsigned RSADigestEngine::digestLength() const
std::size_t RSADigestEngine::digestLength() const
{
return _engine.digestLength();
}
@ -66,27 +67,70 @@ const DigestEngine::Digest& RSADigestEngine::signature()
if (_signature.empty())
{
digest();
_signature.resize(_key.size());
unsigned sigLen = static_cast<unsigned>(_signature.size());
RSA_sign(_type, &_digest[0], static_cast<unsigned>(_digest.size()), &_signature[0], &sigLen, _key.impl()->getRSA());
// truncate _sig to sigLen
if (sigLen < _signature.size())
_signature.resize(sigLen);
std::string begin = "-----BEGIN RSA PUBLIC KEY-----\n";
//TODO: base64 encode data and pass to CryptImportKey API
std::string sig(_digest.begin(), _digest.end());
std::string end = "\n-----END RSA PUBLIC KEY-----";
std::ostringstream ostr;
Base64Encoder encoder(ostr);
encoder << sig;
encoder.close();
begin.append(ostr.str()).append(end);
_signature.assign(begin.begin(), begin.end());
}
return _signature;
return _signature;
}
bool RSADigestEngine::verify(const DigestEngine::Digest& sig)
{
digest();
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());
return ret != 0;
DWORD cbData = 0;
BYTE* pbData = NULL;
if (CryptExportKey(_key.impl()->privateKey(), 0, PRIVATEKEYBLOB, 0/*???*/,
NULL, &cbData))
{
std::vector<BYTE> pkData(cbData);
pbData = &pkData[0];
if (CryptExportKey(_key.impl()->publicKey(), 0, PRIVATEKEYBLOB, 0/*???*/,
pbData, &cbData))
{
// TODO: base64-decode pbData
}
else // !CryptExportKey
{
DWORD err = Error::last();
std::string errStr = Error::getMessage(err);
switch (err)
{
case ERROR_INVALID_HANDLE: case ERROR_INVALID_PARAMETER:
case NTE_BAD_DATA: case NTE_BAD_FLAGS:
case NTE_BAD_KEY: case NTE_BAD_KEY_STATE:
case NTE_BAD_PUBLIC_KEY: case NTE_BAD_TYPE:
case NTE_BAD_UID: case NTE_NO_KEY:
throw Poco::InvalidArgumentException(errStr);
default:
throw Poco::SystemException("Cannot export public key.");
}
}
}
else // !CryptExportKey length
{
throw Poco::SystemException("Cannot obtain key export length.");
}
return false;
}
void RSADigestEngine::updateImpl(const void* data, unsigned length)
void RSADigestEngine::updateImpl(const void* data, std::size_t length)
{
_engine.update(data, length);
}

View File

@ -36,7 +36,7 @@ RSAKeyImpl::RSAKeyImpl(const X509Certificate& cert):
_hPrivateKey(0),
_hPublicKey(0)
{
DWORD rc = CryptImportPublicKeyInfo(_sp.handle(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert.system().pCertInfo->SubjectPublicKeyInfo, &_hPublicKey);
DWORD rc = CryptImportPublicKeyInfo(_sp.handle(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert.system()->pCertInfo->SubjectPublicKeyInfo, &_hPublicKey);
if (!rc) throw Poco::SystemException("Cannot import public key from certificate");
}
@ -110,9 +110,9 @@ RSAKeyImpl::~RSAKeyImpl()
int RSAKeyImpl::size() const
{
DWORD keyLength;
BYTE keyLength;
DWORD size = sizeof(keyLength);
if (!CryptGetKeyParam(_hKey, KP_KEYLEN, &keyLength, &size, 0))
if (!CryptGetKeyParam(_hPrivateKey, KP_KEYLEN, &keyLength, &size, 0))
throw Poco::SystemException("Cannot obtain key length");
return static_cast<int>(keyLength);
}