31 EVP_CIPHER_CTX* encryptCtx,
34 size_t totalWritten = 0;
35 size_t totalInput = 0;
37 auto outputCursor = transformBufferBlocks<16>(
42 throw std::runtime_error(
"Encryption error: too much plain text");
44 if (EVP_EncryptUpdate(
45 encryptCtx, cipher, &outLen, plain, static_cast<int>(len)) !=
48 throw std::runtime_error(
"Encryption error");
50 totalWritten += outLen;
52 return static_cast<size_t>(outLen);
56 auto numBuffered = totalInput - totalWritten;
57 auto numLeftInOutput = outputCursor.length();
58 if (numBuffered <= numLeftInOutput) {
59 if (EVP_EncryptFinal_ex(encryptCtx, outputCursor.writableData(), &outLen) !=
61 throw std::runtime_error(
"Encryption error");
65 std::array<uint8_t, 16> block = {};
66 if (EVP_EncryptFinal_ex(encryptCtx, block.data(), &outLen) != 1) {
67 throw std::runtime_error(
"Encryption error");
69 outputCursor.push(block.data(), outLen);
74 EVP_CIPHER_CTX* encryptCtx,
84 throw std::runtime_error(
"Encryption error: too much plain text");
86 if (EVP_EncryptUpdate(
87 encryptCtx, cipher, &outLen, plain, static_cast<int>(len)) !=
89 throw std::runtime_error(
"Encryption error");
94 if (EVP_EncryptFinal_ex(
95 encryptCtx, output.
writableData() + numWritten, &outLen) != 1) {
96 throw std::runtime_error(
"Encryption error");
101 EVP_CIPHER_CTX* decryptCtx,
105 if (EVP_CIPHER_CTX_ctrl(
107 EVP_CTRL_GCM_SET_TAG,
109 static_cast<void*
>(tagOut.
begin())) != 1) {
110 throw std::runtime_error(
"Decryption error");
113 size_t totalWritten = 0;
114 size_t totalInput = 0;
116 auto outputCursor = transformBufferBlocks<16>(
121 throw std::runtime_error(
"Decryption error: too much cipher text");
123 if (EVP_DecryptUpdate(
124 decryptCtx, plain, &outLen, cipher, static_cast<int>(len)) !=
126 throw std::runtime_error(
"Decryption error");
128 totalWritten += outLen;
130 return static_cast<size_t>(outLen);
134 auto numBuffered = totalInput - totalWritten;
135 auto numLeftInOutput = outputCursor.length();
136 if (numBuffered <= numLeftInOutput) {
138 EVP_DecryptFinal_ex(decryptCtx, outputCursor.writableData(), &outLen);
142 std::array<uint8_t, 16> block = {};
143 auto res = EVP_DecryptFinal_ex(decryptCtx, block.data(), &outLen);
147 outputCursor.push(block.data(), outLen);
153 EVP_CIPHER_CTX* decryptCtx,
164 throw std::runtime_error(
"Decryption error: too much cipher text");
166 if (EVP_DecryptUpdate(
167 decryptCtx, plain, &outLen, cipher, static_cast<int>(len)) !=
169 throw std::runtime_error(
"Decryption error");
171 numWritten += outLen;
174 auto tagLen = tagOut.
size();
175 if (EVP_CIPHER_CTX_ctrl(
177 EVP_CTRL_GCM_SET_TAG,
179 static_cast<void*>(tagOut.
begin())) != 1) {
180 throw std::runtime_error(
"Decryption error");
182 return EVP_DecryptFinal_ex(
183 decryptCtx, output.
writableData() + numWritten, &outLen) == 1;
187 std::unique_ptr<folly::IOBuf>&& plaintext,
193 EVP_CIPHER_CTX* encryptCtx) {
194 auto inputLength = plaintext->computeChainDataLength();
196 std::unique_ptr<folly::IOBuf>
output;
199 if (plaintext->isShared()) {
203 output->
append(inputLength);
204 input = plaintext.get();
207 input = output.get();
210 if (EVP_EncryptInit_ex(encryptCtx,
nullptr,
nullptr,
nullptr, iv.
data()) !=
212 throw std::runtime_error(
"Encryption error");
215 if (associatedData) {
216 for (
auto current : *associatedData) {
218 throw std::runtime_error(
"too much associated data");
221 if (EVP_EncryptUpdate(
226 static_cast<int>(
current.size())) != 1) {
227 throw std::runtime_error(
"Encryption error");
235 encFunc(encryptCtx, *input, *output);
240 if (tailRoom < tagLen) {
243 if (EVP_CIPHER_CTX_ctrl(
244 encryptCtx, EVP_CTRL_GCM_GET_TAG, tagLen, tag->
writableData()) !=
246 throw std::runtime_error(
"Encryption error");
250 auto lastBuf = output->
prev();
253 if (EVP_CIPHER_CTX_ctrl(
255 EVP_CTRL_GCM_GET_TAG,
257 lastBuf->writableTail() - tagLen) != 1) {
258 throw std::runtime_error(
"Encryption error");
265 std::unique_ptr<folly::IOBuf>&& ciphertext,
270 EVP_CIPHER_CTX* decryptCtx) {
271 auto tagLen = tagOut.
size();
272 auto inputLength = ciphertext->computeChainDataLength();
273 if (inputLength < tagLen) {
276 inputLength -= tagLen;
279 std::unique_ptr<folly::IOBuf>
output;
281 if (ciphertext->isShared()) {
284 output->
append(inputLength);
285 input = ciphertext.get();
289 input = output.get();
292 if (EVP_DecryptInit_ex(decryptCtx,
nullptr,
nullptr,
nullptr, iv.
data()) !=
294 throw std::runtime_error(
"Decryption error");
297 if (associatedData) {
298 for (
auto current : *associatedData) {
300 throw std::runtime_error(
"too much associated data");
303 if (EVP_DecryptUpdate(
308 static_cast<int>(
current.size())) != 1) {
309 throw std::runtime_error(
"Decryption error");
314 auto decrypted = useBlockOps
316 :
decFunc(decryptCtx, *input, *output, tagOut);
bool decFuncBlocks(EVP_CIPHER_CTX *, const folly::IOBuf &, folly::IOBuf &, folly::MutableByteRange)
static std::unique_ptr< IOBuf > create(std::size_t capacity)
void encFunc(EVP_CIPHER_CTX *, const folly::IOBuf &, folly::IOBuf &)
void trimBytes(IOBuf &buf, folly::MutableByteRange trimmed)
constexpr detail::Map< Move > move
constexpr size_type size() const
void advance(std::size_t amount)
std::size_t tailroom() const
constexpr Iter data() const
void transformBuffer(const folly::IOBuf &in, folly::IOBuf &out, Func func)
void prependChain(std::unique_ptr< IOBuf > &&iobuf)
constexpr Iter begin() const
bool decFunc(EVP_CIPHER_CTX *, const folly::IOBuf &, folly::IOBuf &, folly::MutableByteRange)
std::unique_ptr< folly::IOBuf > evpEncrypt(std::unique_ptr< folly::IOBuf > &&plaintext, const folly::IOBuf *associatedData, folly::ByteRange iv, size_t tagLen, bool useBlockOps, size_t headroom, EVP_CIPHER_CTX *encryptCtx)
folly::Optional< std::unique_ptr< folly::IOBuf > > evpDecrypt(std::unique_ptr< folly::IOBuf > &&ciphertext, const folly::IOBuf *associatedData, folly::ByteRange iv, folly::MutableByteRange tag, bool useBlockOps, EVP_CIPHER_CTX *decryptCtx)
void append(std::size_t amount)
void encFuncBlocks(EVP_CIPHER_CTX *, const folly::IOBuf &, folly::IOBuf &)