bool decFuncBlocks()

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;
  }
}