mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-14 02:57:45 +01:00
GH #2129: Add support for AES-GCM ciphers
This commit is contained in:
parent
e19f33351d
commit
943595c937
@ -70,7 +70,11 @@ public:
|
|||||||
const ByteVec& key,
|
const ByteVec& key,
|
||||||
const ByteVec& iv);
|
const ByteVec& iv);
|
||||||
/// Creates a new CipherKeyImpl object using the given cipher
|
/// Creates a new CipherKeyImpl object using the given cipher
|
||||||
/// name, key and initialization vector.
|
/// name, key and initialization vector (IV).
|
||||||
|
///
|
||||||
|
/// The size of the IV must match the cipher's expected
|
||||||
|
/// IV size (see ivSize()), except for GCM mode, which allows
|
||||||
|
/// a custom IV size.
|
||||||
|
|
||||||
CipherKey(const std::string& name);
|
CipherKey(const std::string& name);
|
||||||
/// Creates a new CipherKeyImpl object. Autoinitializes key and
|
/// Creates a new CipherKeyImpl object. Autoinitializes key and
|
||||||
@ -105,6 +109,10 @@ public:
|
|||||||
|
|
||||||
void setIV(const ByteVec& iv);
|
void setIV(const ByteVec& iv);
|
||||||
/// Sets the initialization vector (IV) for the Cipher.
|
/// Sets the initialization vector (IV) for the Cipher.
|
||||||
|
///
|
||||||
|
/// The size of the vector must match the cipher's expected
|
||||||
|
/// IV size (see ivSize()), except for GCM mode, which allows
|
||||||
|
/// a custom IV size.
|
||||||
|
|
||||||
CipherKeyImpl::Ptr impl();
|
CipherKeyImpl::Ptr impl();
|
||||||
/// Returns the impl object
|
/// Returns the impl object
|
||||||
|
@ -156,13 +156,6 @@ inline const CipherKeyImpl::ByteVec& CipherKeyImpl::getIV() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void CipherKeyImpl::setIV(const ByteVec& iv)
|
|
||||||
{
|
|
||||||
poco_assert(iv.size() == static_cast<ByteVec::size_type>(ivSize()));
|
|
||||||
_iv = iv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const EVP_CIPHER* CipherKeyImpl::cipher()
|
inline const EVP_CIPHER* CipherKeyImpl::cipher()
|
||||||
{
|
{
|
||||||
return _pCipher;
|
return _pCipher;
|
||||||
|
@ -50,6 +50,17 @@ public:
|
|||||||
/// no padding is performed, the total amount of data encrypted or decrypted must then be a multiple of
|
/// no padding is performed, the total amount of data encrypted or decrypted must then be a multiple of
|
||||||
/// the block size or an error will occur.
|
/// the block size or an error will occur.
|
||||||
|
|
||||||
|
virtual std::string getTag(std::size_t tagSize = 16) const = 0;
|
||||||
|
/// Returns the GCM tag after encrypting using GCM mode.
|
||||||
|
///
|
||||||
|
/// Must be called after finalize().
|
||||||
|
|
||||||
|
virtual void setTag(const std::string& tag) = 0;
|
||||||
|
/// Sets the GCM tag for authenticated decryption using GCM mode.
|
||||||
|
///
|
||||||
|
/// Must be set before finalize() is called, otherwise
|
||||||
|
/// decryption will fail.
|
||||||
|
|
||||||
virtual std::streamsize transform(
|
virtual std::streamsize transform(
|
||||||
const unsigned char* input,
|
const unsigned char* input,
|
||||||
std::streamsize inputLength,
|
std::streamsize inputLength,
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "Poco/Crypto/CipherImpl.h"
|
#include "Poco/Crypto/CipherImpl.h"
|
||||||
#include "Poco/Crypto/CryptoTransform.h"
|
#include "Poco/Crypto/CryptoTransform.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
|
#include "Poco/Buffer.h"
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
|
||||||
@ -60,8 +61,9 @@ namespace
|
|||||||
~CryptoTransformImpl();
|
~CryptoTransformImpl();
|
||||||
|
|
||||||
std::size_t blockSize() const;
|
std::size_t blockSize() const;
|
||||||
|
|
||||||
int setPadding(int padding);
|
int setPadding(int padding);
|
||||||
|
std::string getTag(std::size_t tagSize) const;
|
||||||
|
void setTag(const std::string& tag);
|
||||||
|
|
||||||
std::streamsize transform(
|
std::streamsize transform(
|
||||||
const unsigned char* input,
|
const unsigned char* input,
|
||||||
@ -110,6 +112,18 @@ namespace
|
|||||||
_iv.empty() ? 0 : &_iv[0],
|
_iv.empty() ? 0 : &_iv[0],
|
||||||
(dir == DIR_ENCRYPT) ? 1 : 0);
|
(dir == DIR_ENCRYPT) ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||||
|
if (_iv.size() != EVP_CIPHER_iv_length(_pCipher) && EVP_CIPHER_mode(_pCipher) == EVP_CIPH_GCM_MODE)
|
||||||
|
{
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
|
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_SET_IVLEN, _iv.size(), NULL);
|
||||||
|
#else
|
||||||
|
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_SET_IVLEN, _iv.size(), NULL);
|
||||||
|
#endif
|
||||||
|
if (rc == 0) throwError();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -144,6 +158,36 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string CryptoTransformImpl::getTag(std::size_t tagSize) const
|
||||||
|
{
|
||||||
|
std::string tag;
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||||
|
Poco::Buffer<char> buffer(tagSize);
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
|
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_GET_TAG, tagSize, buffer.begin());
|
||||||
|
#else
|
||||||
|
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_GET_TAG, tagSize, buffer.begin());
|
||||||
|
#endif
|
||||||
|
if (rc == 0) throwError();
|
||||||
|
tag.assign(buffer.begin(), tagSize);
|
||||||
|
#endif
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CryptoTransformImpl::setTag(const std::string& tag)
|
||||||
|
{
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
|
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast<char*>(tag.data()));
|
||||||
|
#elif OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||||
|
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast<char*>(tag.data()));
|
||||||
|
#else
|
||||||
|
int rc = 0;
|
||||||
|
#endif
|
||||||
|
if (rc == 0) throwError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::streamsize CryptoTransformImpl::transform(
|
std::streamsize CryptoTransformImpl::transform(
|
||||||
const unsigned char* input,
|
const unsigned char* input,
|
||||||
std::streamsize inputLength,
|
std::streamsize inputLength,
|
||||||
|
@ -63,7 +63,7 @@ CipherKeyImpl::CipherKeyImpl(const std::string& name,
|
|||||||
_key(key),
|
_key(key),
|
||||||
_iv(iv)
|
_iv(iv)
|
||||||
{
|
{
|
||||||
// dummy access to Cipherfactory so that the EVP lib is initilaized
|
// dummy access to Cipherfactory so that the EVP lib is initialized
|
||||||
CipherFactory::defaultFactory();
|
CipherFactory::defaultFactory();
|
||||||
_pCipher = EVP_get_cipherbyname(name.c_str());
|
_pCipher = EVP_get_cipherbyname(name.c_str());
|
||||||
|
|
||||||
@ -115,6 +115,7 @@ CipherKeyImpl::Mode CipherKeyImpl::mode() const
|
|||||||
case EVP_CIPH_OFB_MODE:
|
case EVP_CIPH_OFB_MODE:
|
||||||
return MODE_OFB;
|
return MODE_OFB;
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||||
case EVP_CIPH_CTR_MODE:
|
case EVP_CIPH_CTR_MODE:
|
||||||
return MODE_CTR;
|
return MODE_CTR;
|
||||||
|
|
||||||
@ -123,6 +124,7 @@ CipherKeyImpl::Mode CipherKeyImpl::mode() const
|
|||||||
|
|
||||||
case EVP_CIPH_CCM_MODE:
|
case EVP_CIPH_CCM_MODE:
|
||||||
return MODE_CCM;
|
return MODE_CCM;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
throw Poco::IllegalStateException("Unexpected value of EVP_CIPHER_mode()");
|
throw Poco::IllegalStateException("Unexpected value of EVP_CIPHER_mode()");
|
||||||
}
|
}
|
||||||
@ -212,4 +214,11 @@ int CipherKeyImpl::ivSize() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CipherKeyImpl::setIV(const ByteVec& iv)
|
||||||
|
{
|
||||||
|
poco_assert(mode() == MODE_GCM || iv.size() == static_cast<ByteVec::size_type>(ivSize()));
|
||||||
|
_iv = iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
} } // namespace Poco::Crypto
|
||||||
|
@ -69,6 +69,8 @@ namespace
|
|||||||
|
|
||||||
std::size_t blockSize() const;
|
std::size_t blockSize() const;
|
||||||
std::size_t maxDataSize() const;
|
std::size_t maxDataSize() const;
|
||||||
|
std::string getTag(std::size_t) const;
|
||||||
|
void setTag(const std::string&);
|
||||||
|
|
||||||
std::streamsize transform(
|
std::streamsize transform(
|
||||||
const unsigned char* input,
|
const unsigned char* input,
|
||||||
@ -127,6 +129,17 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string RSAEncryptImpl::getTag(std::size_t) const
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RSAEncryptImpl::setTag(const std::string&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::streamsize RSAEncryptImpl::transform(
|
std::streamsize RSAEncryptImpl::transform(
|
||||||
const unsigned char* input,
|
const unsigned char* input,
|
||||||
std::streamsize inputLength,
|
std::streamsize inputLength,
|
||||||
@ -192,6 +205,8 @@ namespace
|
|||||||
~RSADecryptImpl();
|
~RSADecryptImpl();
|
||||||
|
|
||||||
std::size_t blockSize() const;
|
std::size_t blockSize() const;
|
||||||
|
std::string getTag(std::size_t) const;
|
||||||
|
void setTag(const std::string&);
|
||||||
|
|
||||||
std::streamsize transform(
|
std::streamsize transform(
|
||||||
const unsigned char* input,
|
const unsigned char* input,
|
||||||
@ -233,6 +248,17 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string RSADecryptImpl::getTag(std::size_t) const
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RSADecryptImpl::setTag(const std::string&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::streamsize RSADecryptImpl::transform(
|
std::streamsize RSADecryptImpl::transform(
|
||||||
const unsigned char* input,
|
const unsigned char* input,
|
||||||
std::streamsize inputLength,
|
std::streamsize inputLength,
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "Poco/Crypto/CipherKey.h"
|
#include "Poco/Crypto/CipherKey.h"
|
||||||
#include "Poco/Crypto/X509Certificate.h"
|
#include "Poco/Crypto/X509Certificate.h"
|
||||||
#include "Poco/Crypto/CryptoStream.h"
|
#include "Poco/Crypto/CryptoStream.h"
|
||||||
|
#include "Poco/Crypto/CryptoTransform.h"
|
||||||
#include "Poco/StreamCopier.h"
|
#include "Poco/StreamCopier.h"
|
||||||
#include "Poco/Base64Encoder.h"
|
#include "Poco/Base64Encoder.h"
|
||||||
#include "Poco/HexBinaryEncoder.h"
|
#include "Poco/HexBinaryEncoder.h"
|
||||||
@ -188,6 +189,38 @@ void CryptoTest::testEncryptDecryptDESECB()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CryptoTest::testEncryptDecryptGCM()
|
||||||
|
{
|
||||||
|
CipherKey key("aes-256-gcm");
|
||||||
|
|
||||||
|
CipherKey::ByteVec iv(20, 213);
|
||||||
|
key.setIV(iv);
|
||||||
|
|
||||||
|
Cipher::Ptr pCipher = CipherFactory::defaultFactory().createCipher(key);
|
||||||
|
|
||||||
|
for (std::size_t n = 1; n < MAX_DATA_SIZE; n++)
|
||||||
|
{
|
||||||
|
std::stringstream str;
|
||||||
|
CryptoTransform* pEncryptor = pCipher->createEncryptor();
|
||||||
|
CryptoOutputStream encryptorStream(str, pEncryptor);
|
||||||
|
std::string in(n, 'x');
|
||||||
|
encryptorStream << in;
|
||||||
|
encryptorStream.close();
|
||||||
|
assert (encryptorStream.good());
|
||||||
|
|
||||||
|
std::string tag = pEncryptor->getTag();
|
||||||
|
|
||||||
|
CryptoTransform* pDecryptor = pCipher->createDecryptor();
|
||||||
|
pDecryptor->setTag(tag);
|
||||||
|
CryptoInputStream decryptorStream(str, pDecryptor);
|
||||||
|
std::string out;
|
||||||
|
decryptorStream >> out;
|
||||||
|
|
||||||
|
assert (in == out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CryptoTest::testPassword()
|
void CryptoTest::testPassword()
|
||||||
{
|
{
|
||||||
CipherKey key("aes256", "password", "salt");
|
CipherKey key("aes256", "password", "salt");
|
||||||
@ -331,8 +364,9 @@ CppUnit::Test* CryptoTest::suite()
|
|||||||
CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptWithSalt);
|
CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptWithSalt);
|
||||||
CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptWithSaltSha1);
|
CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptWithSaltSha1);
|
||||||
CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptDESECB);
|
CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptDESECB);
|
||||||
|
CppUnit_addTest(pSuite, CryptoTest, testEncryptDecryptGCM);
|
||||||
CppUnit_addTest(pSuite, CryptoTest, testPassword);
|
CppUnit_addTest(pSuite, CryptoTest, testPassword);
|
||||||
CppUnit_addTest(pSuite, CryptoTest,testPasswordSha1);
|
CppUnit_addTest(pSuite, CryptoTest, testPasswordSha1);
|
||||||
CppUnit_addTest(pSuite, CryptoTest, testEncryptInterop);
|
CppUnit_addTest(pSuite, CryptoTest, testEncryptInterop);
|
||||||
CppUnit_addTest(pSuite, CryptoTest, testDecryptInterop);
|
CppUnit_addTest(pSuite, CryptoTest, testDecryptInterop);
|
||||||
CppUnit_addTest(pSuite, CryptoTest, testStreams);
|
CppUnit_addTest(pSuite, CryptoTest, testStreams);
|
||||||
|
@ -33,6 +33,7 @@ public:
|
|||||||
void testEncryptDecryptWithSalt();
|
void testEncryptDecryptWithSalt();
|
||||||
void testEncryptDecryptWithSaltSha1();
|
void testEncryptDecryptWithSaltSha1();
|
||||||
void testEncryptDecryptDESECB();
|
void testEncryptDecryptDESECB();
|
||||||
|
void testEncryptDecryptGCM();
|
||||||
void testStreams();
|
void testStreams();
|
||||||
void testPassword();
|
void testPassword();
|
||||||
void testPasswordSha1();
|
void testPasswordSha1();
|
||||||
|
Loading…
Reference in New Issue
Block a user