in fizz/crypto/aead/OpenSSLEVPCipher.cpp [93:143]
bool decFuncBlocks(
EVP_CIPHER_CTX* decryptCtx,
const folly::IOBuf& ciphertext,
folly::IOBuf& output,
folly::MutableByteRange tagOut) {
if (EVP_CIPHER_CTX_ctrl(
decryptCtx,
EVP_CTRL_GCM_SET_TAG,
tagOut.size(),
static_cast<void*>(tagOut.begin())) != 1) {
throw std::runtime_error("Decryption error");
}
size_t totalWritten = 0;
size_t totalInput = 0;
int outLen = 0;
auto outputCursor = transformBufferBlocks<16>(
ciphertext,
output,
[&](uint8_t* plain, const uint8_t* cipher, size_t len) {
if (len > std::numeric_limits<int>::max()) {
throw std::runtime_error("Decryption error: too much cipher text");
}
if (EVP_DecryptUpdate(
decryptCtx, plain, &outLen, cipher, static_cast<int>(len)) !=
1) {
throw std::runtime_error("Decryption error");
}
totalWritten += outLen;
totalInput += len;
return static_cast<size_t>(outLen);
});
// We might end up needing to write more in the final encrypt stage
auto numBuffered = totalInput - totalWritten;
auto numLeftInOutput = outputCursor.length();
if (numBuffered <= numLeftInOutput) {
auto res =
EVP_DecryptFinal_ex(decryptCtx, outputCursor.writableData(), &outLen);
return res == 1;
} else {
// we need to copy nicely - this should be at most one block
std::array<uint8_t, 16> block = {};
auto res = EVP_DecryptFinal_ex(decryptCtx, block.data(), &outLen);
if (res != 1) {
return false;
}
outputCursor.push(block.data(), outLen);
return true;
}
}