Skip to content

Commit

Permalink
Refactor OpenSSLEVPCipher::evpDecrypt
Browse files Browse the repository at this point in the history
Summary: There are lots of common code between `OpenSSLEVPCipher::EVPDecrypt` and `AEGISCipher::doDecrypt`. This diff pull out the common code into CryptoUtils::decryptHelper from OPenSSLEVPCipher.

Reviewed By: mingtaoy

Differential Revision: D54312990

fbshipit-source-id: 06c190a11ec9fd23ab995cb76d24eeda0dad57d6
  • Loading branch information
Huilin Chen authored and facebook-github-bot committed Mar 8, 2024
1 parent 07e99d9 commit b0551ad
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 61 deletions.
44 changes: 44 additions & 0 deletions fizz/crypto/aead/CryptoUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,48 @@ std::unique_ptr<folly::IOBuf> encryptHelper(
return output;
}

/**
* AeadImpl has the following requirements:
* * void AeadImpl::init(folly::ByteRange iv, const folly::IOBuf*
* associatedData, size_t ciphertextLength)
* - initializes a decryption context with `iv` and associated data.
* Associated data can be null.
* * bool AeadImpl::decryptAndFinal(folly::IOBuf& ciphertext, folly::IOBuf&
* plaintext, folly::MutableByteRange tagOut)
* - decrypts `ciphertextLength` bytes of `ciphertext`. The implementation
* must write the plaintext to `plaintext`. `plaintext` is guaranteed to be
* writable for `ciphertextLength` bytes. Return whether the decryption was
* successful.
*/
template <class AeadImpl>
folly::Optional<std::unique_ptr<folly::IOBuf>> decryptHelper(
AeadImpl&& impl,
std::unique_ptr<folly::IOBuf>&& ciphertext,
const folly::IOBuf* associatedData,
folly::ByteRange iv,
folly::MutableByteRange tagOut,
bool inPlace) {
auto inputLength = ciphertext->computeChainDataLength();
impl.init(iv, associatedData, inputLength);

folly::IOBuf* input;
std::unique_ptr<folly::IOBuf> output;
// If not in-place, allocate buffers. Otherwise in and out are same.
if (!inPlace) {
output = folly::IOBuf::create(inputLength);
output->append(inputLength);
input = ciphertext.get();
} else {
output = std::move(ciphertext);
input = output.get();
}

bool decrypted = impl.decryptAndFinal(*input, *output, tagOut);

if (!decrypted) {
return folly::none;
}
return output;
}

} // namespace fizz
134 changes: 73 additions & 61 deletions fizz/crypto/aead/OpenSSLEVPCipher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,74 +174,86 @@ folly::Optional<std::unique_ptr<folly::IOBuf>> evpDecrypt(
bool useBlockOps,
EVP_CIPHER_CTX* decryptCtx,
bool inPlace) {
auto inputLength = ciphertext->computeChainDataLength();

folly::IOBuf* input;
std::unique_ptr<folly::IOBuf> output;
// If not in-place, allocate buffers. Otherwise in and out are same.
if (!inPlace) {
output = folly::IOBuf::create(inputLength);
output->append(inputLength);
input = ciphertext.get();
} else {
output = std::move(ciphertext);
input = output.get();
}
struct AeadImpl {
EVP_CIPHER_CTX* decryptCtx;
bool useBlockOps;

if (EVP_DecryptInit_ex(decryptCtx, nullptr, nullptr, nullptr, iv.data()) !=
1) {
throw std::runtime_error("Decryption error");
}
AeadImpl(EVP_CIPHER_CTX* d, bool u) : decryptCtx(d), useBlockOps(u) {}

if (associatedData) {
for (auto current : *associatedData) {
if (current.size() > std::numeric_limits<int>::max()) {
throw std::runtime_error("too much associated data");
}
int len;
if (EVP_DecryptUpdate(
decryptCtx,
nullptr,
&len,
current.data(),
static_cast<int>(current.size())) != 1) {
void init(
folly::ByteRange iv,
const folly::IOBuf* associatedData,
size_t /*ciphertextLength*/) {
if (EVP_DecryptInit_ex(
decryptCtx, nullptr, nullptr, nullptr, iv.data()) != 1) {
throw std::runtime_error("Decryption error");
}
}
}

bool decrypted;
if (useBlockOps) {
struct Impl {
EVP_CIPHER_CTX* decryptCtx;
bool decryptUpdate(
uint8_t* plain,
const uint8_t* cipher,
size_t len,
int* outLen) {
return EVP_DecryptUpdate(
decryptCtx, plain, outLen, cipher, static_cast<int>(len)) ==
1;
}
bool setExpectedTag(int tagSize, unsigned char* tag) {
return EVP_CIPHER_CTX_ctrl(
decryptCtx,
EVP_CTRL_GCM_SET_TAG,
tagSize,
static_cast<void*>(tag)) == 1;
if (associatedData) {
for (auto current : *associatedData) {
if (current.size() > std::numeric_limits<int>::max()) {
throw std::runtime_error("too much associated data");
}
int len;
if (EVP_DecryptUpdate(
decryptCtx,
nullptr,
&len,
current.data(),
static_cast<int>(current.size())) != 1) {
throw std::runtime_error("Decryption error");
}
}
}
bool decryptFinal(unsigned char* outm, int* outLen) {
return EVP_DecryptFinal_ex(decryptCtx, outm, outLen) == 1;
}

bool decryptAndFinal(
folly::IOBuf& ciphertext,
folly::IOBuf& plaintext,
folly::MutableByteRange tagOut) {
if (useBlockOps) {
struct EVPDecImpl {
EVP_CIPHER_CTX* decryptCtx;

explicit EVPDecImpl(EVP_CIPHER_CTX* d) : decryptCtx(d) {}
bool decryptUpdate(
uint8_t* plain,
const uint8_t* cipher,
size_t len,
int* outLen) {
return EVP_DecryptUpdate(
decryptCtx,
plain,
outLen,
cipher,
static_cast<int>(len)) == 1;
}
bool setExpectedTag(int tagSize, unsigned char* tag) {
return EVP_CIPHER_CTX_ctrl(
decryptCtx,
EVP_CTRL_GCM_SET_TAG,
tagSize,
static_cast<void*>(tag)) == 1;
}
bool decryptFinal(unsigned char* outm, int* outLen) {
return EVP_DecryptFinal_ex(decryptCtx, outm, outLen) == 1;
}
};
return decFuncBlocks<16>(
EVPDecImpl{decryptCtx}, ciphertext, plaintext, tagOut);
} else {
return decFunc(decryptCtx, ciphertext, plaintext, tagOut);
}
};
decrypted = decFuncBlocks<16>(Impl{decryptCtx}, *input, *output, tagOut);
} else {
decrypted = decFunc(decryptCtx, *input, *output, tagOut);
}
if (!decrypted) {
return folly::none;
}
return output;
}
};

return decryptHelper(
AeadImpl{decryptCtx, useBlockOps},
std::move(ciphertext),
associatedData,
iv,
tagOut,
inPlace);
}

} // namespace
Expand Down

0 comments on commit b0551ad

Please sign in to comment.