-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Envelope): Add envelope to crypto #3561
- Loading branch information
Showing
9 changed files
with
535 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
// | ||
// Envelope.h | ||
// | ||
// Library: Crypto | ||
// Package: Envelope | ||
// Module: Envelope | ||
// | ||
// Definition of the Envelope class. | ||
// | ||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. | ||
// and Contributors. | ||
// | ||
// SPDX-License-Identifier: BSL-1.0 | ||
// | ||
|
||
|
||
#ifndef Crypto_Envelope_INCLUDED | ||
#define Crypto_Envelope_INCLUDED | ||
|
||
|
||
#include "Poco/Crypto/Crypto.h" | ||
#include "Poco/Crypto/EVPPKey.h" | ||
#include <vector> | ||
#include <openssl/evp.h> | ||
|
||
|
||
namespace Poco { | ||
namespace Crypto { | ||
|
||
|
||
class Crypto_API Envelope | ||
/// Envelope encrypts/decrypts data using a symmetric key. | ||
/// | ||
/// Encryption and decryption with asymmetric keys is computationally expensive. | ||
/// To alleviate that, Envelope encrypts data using a symmetric session key; | ||
/// the key is then itself asymmetrically encrypted using a public key. | ||
/// It is also possible to encrypt the session key with multiple public keys, | ||
/// so that the message can be sent to multiple recipients. | ||
/// | ||
/// Each recipient decrypts the session with their private key; the session | ||
/// key for the message decryption is the same for each recipient. | ||
{ | ||
public: | ||
using Byte = unsigned char; | ||
using ByteVec = std::vector<Byte>; | ||
using EVPPKeyVec = std::vector<EVPPKey>; | ||
using EVP_PKEYVec = std::vector<EVP_PKEY*>; | ||
using EncKeyVec = std::vector<ByteVec>; | ||
|
||
Envelope() = delete; | ||
|
||
Envelope(const EVPPKey& key, int cipherNID); | ||
/// Creates a new Envelope object. | ||
/// Initialization vector is automatically | ||
/// generated. | ||
|
||
Envelope(const EVPPKeyVec& keys, int cipherNID); | ||
/// Creates a new Envelope object. | ||
/// Initialization vector is automatically | ||
/// generated. | ||
|
||
~Envelope(); | ||
/// Destroys the Envelope. | ||
|
||
const ByteVec& iv() const; | ||
/// Returns the initialization vector. | ||
|
||
void addKey(const EVPPKey& key); | ||
/// Adds the key to the list of private keys. | ||
|
||
const EncKeyVec& keys() const; | ||
/// Returns encrypted symmetric keys. | ||
|
||
int cipherNID() const; | ||
/// Reurns the cipher NID. | ||
|
||
const ByteVec& seal(const std::string& plainText); | ||
/// Encrypts the given text and returns the encrypted text. | ||
|
||
const ByteVec& seal(const ByteVec& plainData); | ||
/// Encrypts the given data and returns the encrypted data. | ||
|
||
const ByteVec& getContent() const; | ||
/// Returns the encrypted content. | ||
|
||
void setContent(const ByteVec& enc); | ||
/// Sets the encrypted content. | ||
|
||
ByteVec open(const EVPPKey& privKey, const ByteVec& encKeys, const ByteVec& iv = ByteVec()); | ||
/// Decrypts the stored encrypted data and returns it. | ||
|
||
std::string openAsString(const EVPPKey& privKey, const ByteVec& encKeys, const ByteVec& iv = ByteVec()); | ||
/// Decrypts the stored encrypted data and returns it. | ||
|
||
static std::string toString(const ByteVec& data); | ||
/// Converts and returns string from ByteVec. | ||
|
||
private: | ||
Envelope(int cipherNID); | ||
Envelope(int cipherNID, const ByteVec& iv); | ||
|
||
int ivSize() const; | ||
int blockSize() const; | ||
void handleErrors(std::string&& msg); | ||
|
||
const EVP_CIPHER* _pCipher; | ||
EVP_CIPHER_CTX* _pCtx; | ||
EVP_CIPHER_CTX* _pDecCtx; | ||
ByteVec _iv; | ||
EVP_PKEYVec _pubKeys; | ||
EncKeyVec _encKeys; | ||
std::vector<int> _encKeysSizes; | ||
ByteVec _encContent; | ||
}; | ||
|
||
|
||
inline int Envelope::ivSize() const | ||
{ | ||
return EVP_CIPHER_iv_length(_pCipher); | ||
} | ||
|
||
|
||
inline const Envelope::ByteVec& Envelope::iv() const | ||
{ | ||
return _iv; | ||
} | ||
|
||
|
||
inline int Envelope::blockSize() const | ||
{ | ||
return EVP_CIPHER_block_size(_pCipher); | ||
} | ||
|
||
|
||
inline const Envelope::EncKeyVec& Envelope::keys() const | ||
{ | ||
return _encKeys; | ||
} | ||
|
||
|
||
inline std::string Envelope::toString(const ByteVec& data) | ||
{ | ||
return std::string(data.begin(), data.end()); | ||
} | ||
|
||
|
||
inline std::string Envelope::openAsString(const EVPPKey& privKey, const ByteVec& encKey, const ByteVec& iv) | ||
{ | ||
return toString(open(privKey, encKey, iv)); | ||
} | ||
|
||
|
||
const Envelope::ByteVec& Envelope::getContent() const | ||
{ | ||
return _encContent; | ||
} | ||
|
||
|
||
void Envelope::setContent(const ByteVec& enc) | ||
{ | ||
_encContent = enc; | ||
} | ||
|
||
|
||
inline int Envelope::cipherNID() const | ||
{ | ||
return EVP_CIPHER_nid(_pCipher); | ||
} | ||
|
||
|
||
} } // namespace Poco::Crypto | ||
|
||
|
||
#endif // Crypto_Envelope_INCLUDED |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// | ||
// Envelope.cpp | ||
// | ||
// Library: Crypto | ||
// Package: Envelope | ||
// Module: Envelope | ||
// | ||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. | ||
// and Contributors. | ||
// | ||
// SPDX-License-Identifier: BSL-1.0 | ||
// | ||
|
||
|
||
#include "Poco/Crypto/Envelope.h" | ||
|
||
|
||
namespace Poco { | ||
namespace Crypto { | ||
|
||
|
||
Envelope::Envelope(int cipherNID): _pCipher(EVP_get_cipherbynid(cipherNID)), | ||
_pCtx(EVP_CIPHER_CTX_new()) | ||
{ | ||
poco_check_ptr(_pCipher); | ||
poco_check_ptr(_pCtx); | ||
if (1 != EVP_CIPHER_CTX_init(_pCtx)) | ||
handleErrors(std::string("Envelope():EVP_CIPHER_CTX_init()")); | ||
_iv.resize(ivSize(), 0); | ||
} | ||
|
||
|
||
Envelope::Envelope(const EVPPKey& key, int cipherNID): | ||
Envelope(cipherNID) | ||
{ | ||
addKey(key); | ||
} | ||
|
||
|
||
Envelope::Envelope(const EVPPKeyVec& keys, int cipherNID): | ||
Envelope(cipherNID) | ||
{ | ||
for (const auto& k : keys) addKey(k); | ||
} | ||
|
||
|
||
Envelope::~Envelope() | ||
{ | ||
for (auto& pK : _pubKeys) | ||
EVP_PKEY_free(pK); | ||
EVP_CIPHER_CTX_free(_pCtx); | ||
} | ||
|
||
|
||
void Envelope::addKey(const EVPPKey& key) | ||
{ | ||
EVP_PKEY* pKey; | ||
_pubKeys.push_back(EVPPKey::duplicate((const EVP_PKEY*)key, &pKey)); | ||
_encKeys.emplace_back(EVP_PKEY_size(_pubKeys.back())); | ||
} | ||
|
||
|
||
const Envelope::ByteVec& Envelope::seal(const ByteVec& plainData) | ||
{ | ||
Byte* pEncKeys[_encKeys.size()] = {}; | ||
int encKeysSizes[_encKeys.size()] = {}; | ||
int i = 0; | ||
for (const auto& k : _encKeys) | ||
pEncKeys[i++] = new Byte[k.size()]; | ||
|
||
int noOfKeys = static_cast<int>(_pubKeys.size()); | ||
if (_encKeys.size() != EVP_SealInit(_pCtx, _pCipher, pEncKeys, encKeysSizes, &_iv[0], &_pubKeys[0], noOfKeys)) | ||
{ | ||
i = 0; | ||
for (; i < _encKeys.size(); ++i) delete [] pEncKeys[i]; | ||
handleErrors(std::string("Envelope::seal():EVP_SealInit()")); | ||
} | ||
i = 0; | ||
for (auto& k : _encKeys) | ||
{ | ||
if (encKeysSizes[i] != k.size()) | ||
k.resize(encKeysSizes[i]); | ||
std::memcpy(&k[0], pEncKeys[i], encKeysSizes[i]); | ||
++i; | ||
} | ||
|
||
i = 0; | ||
for (; i < _encKeys.size(); ++i) delete [] pEncKeys[i]; | ||
|
||
int cipherTextLen = 0, len = 0; | ||
int plainDataSize = static_cast<int>(plainData.size()); | ||
_encContent.resize(plainDataSize + blockSize()); | ||
if (1 != EVP_SealUpdate(_pCtx, &_encContent[0], &len, &plainData[0], plainDataSize)) | ||
handleErrors(std::string("Envelope::seal():EVP_SealUpdate()")); | ||
|
||
cipherTextLen = len; | ||
poco_assert (cipherTextLen < _encContent.size()); | ||
|
||
if(1 != EVP_SealFinal(_pCtx, &_encContent[len], &len)) | ||
handleErrors(std::string("Envelope::seal():EVP_SealFinal()")); | ||
cipherTextLen += len; | ||
poco_assert (cipherTextLen <= _encContent.size()); | ||
_encContent.resize(cipherTextLen); | ||
|
||
return _encContent; | ||
} | ||
|
||
|
||
const Envelope::ByteVec& Envelope::seal(const std::string& plainText) | ||
{ | ||
return seal(ByteVec(plainText.begin(), plainText.end())); | ||
} | ||
|
||
|
||
Envelope::ByteVec Envelope::open(const EVPPKey& privKey, const ByteVec& encKey, const ByteVec& iv) | ||
{ | ||
if (iv.size() > 0) _iv = iv; | ||
int encContentLen = static_cast<int>(_encContent.size()); | ||
int blockSz = blockSize(); | ||
int mod = encContentLen % blockSz; | ||
if (mod || (encContentLen < blockSz)) | ||
{ | ||
throw Poco::InvalidArgumentException( | ||
Poco::format("Envelope::open(): bad encrypted buffer size: %z (must be N x %d)", | ||
_encContent.size(), blockSz)); | ||
} | ||
|
||
int encKeyLen = static_cast<int>(encKey.size()); | ||
EVP_PKEY* pKey = const_cast<EVP_PKEY*>((const EVP_PKEY*)privKey); | ||
if (1 != EVP_OpenInit(_pCtx, _pCipher, &encKey[0], encKeyLen, &_iv[0], pKey)) | ||
handleErrors(std::string("Envelope::open():EVP_OpenInit()")); | ||
|
||
ByteVec plainData(_encContent.size()+blockSz, 0); | ||
int len = 0; | ||
if(1 != EVP_OpenUpdate(_pCtx, &plainData[0], &len, &_encContent[0], encContentLen)) | ||
handleErrors(std::string("Envelope::open():EVP_OpenUpdate()")); | ||
int totalLen = len; | ||
|
||
if(1 != EVP_OpenFinal(_pCtx, &plainData[len], &len)) | ||
handleErrors(std::string("Envelope::open():EVP_OpenFinal()")); | ||
totalLen += len; | ||
plainData.resize(totalLen); | ||
return plainData; | ||
} | ||
|
||
|
||
void Envelope::handleErrors(std::string&& msg) | ||
{ | ||
unsigned long err; | ||
while ((err = ERR_get_error())) | ||
{ | ||
if (!msg.empty()) msg.append("\n"); | ||
msg.append(ERR_error_string(err, 0)); | ||
} | ||
throw CryptoException(msg); | ||
} | ||
|
||
|
||
} } // namespace Poco::Crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.