folly::Optional SSLUtil::decryptOpenSSLEncFilePassString()

in wangle/ssl/SSLUtil.cpp [158:206]


folly::Optional<std::string> SSLUtil::decryptOpenSSLEncFilePassString(
    const std::string& filename,
    const std::string& password,
    const EVP_CIPHER* cipher,
    const EVP_MD* digest) {
  // Most of this code adapted from openssl/apps/enc.c
  const std::string magic = "Salted__";
  std::array<unsigned char, EVP_MAX_KEY_LENGTH> key;
  std::array<unsigned char, EVP_MAX_IV_LENGTH> iv;

  // Read encrypted file into string
  std::string fileData;
  if (!folly::readFile(filename.c_str(), fileData)) {
    LOG(ERROR) << "Error reading file: " << filename;
    return folly::none;
  }
  if (fileData.size() < magic.size() + PKCS5_SALT_LEN) {
    LOG(ERROR) << "Not a valid encrypted file.";
    return folly::none;
  }

  // Parse file contents into magic number, salt, and encrypted content
  auto fileMagic = fileData.substr(0, magic.size());
  if (fileMagic.compare(magic) != 0) {
    LOG(ERROR) << "Incorrect magic number in file.";
    return folly::none;
  }
  auto salt = fileData.substr(magic.size(), PKCS5_SALT_LEN);
  auto ciphertext = fileData.substr(magic.size() + PKCS5_SALT_LEN);

  // Construct key and iv from password
  DCHECK_LE(password.size(), std::numeric_limits<int>::max());
  EVP_BytesToKey(
      cipher,
      digest,
      reinterpret_cast<const unsigned char*>(salt.data()),
      reinterpret_cast<const unsigned char*>(password.data()),
      folly::to_narrow(folly::to_signed(password.size())),
      1 /* one round */,
      key.data(),
      iv.data());

  // Decrypt content using key and iv
  return decrypt(
      folly::range(folly::StringPiece(ciphertext)),
      folly::range(key),
      folly::range(iv),
      cipher);
}