mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-02-12 07:47:12 +01:00
169 lines
4.2 KiB
C++
169 lines
4.2 KiB
C++
//
|
|
// 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"
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
#if !defined(EVP_CIPHER_CTX_init)
|
|
#define EVP_CIPHER_CTX_init(a)
|
|
#endif
|
|
#endif
|
|
|
|
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 OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
if (1 != EVP_CIPHER_CTX_init(_pCtx))
|
|
handleErrors(std::string("Envelope():EVP_CIPHER_CTX_init()"));
|
|
#else
|
|
EVP_CIPHER_CTX_init(_pCtx);
|
|
#endif
|
|
_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)
|
|
{
|
|
std::vector<Byte*> pEncKeys(_encKeys.size(), 0);
|
|
std::vector<int> encKeysSizes(_encKeys.size(), 0);
|
|
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[0], &encKeysSizes[0], &_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
|