phacility/phabricator · critical · Exception

Failed to openssl_encrypt() data: %s

Error message

Failed to openssl_encrypt() data: %s

What it means

PhabricatorFileAES256StorageFormat::encryptData() calls openssl_encrypt() with the fixed cipher 'aes-256-cbc'; PHP returns false on failure and this exception surfaces openssl_error_string(). In this format every file gets a 256-bit (32-byte) key and 128-bit (16-byte) IV, and the per-file key material is itself encrypted with a keyring master key (base64-decoded material) — so failures almost always mean key or IV material of the wrong length (e.g. keyring material not exactly 32 bytes after base64 decode), or an OpenSSL build that does not provide aes-256-cbc.

Source

Thrown at src/applications/files/format/PhabricatorFileAES256StorageFormat.php:145

    $inner_key = $payload['key.base64'];
    $inner_key = base64_decode($inner_key);
    $inner_key = new PhutilOpaqueEnvelope($inner_key);

    return array($inner_key, $inner_iv);
  }

  private function encryptData(
    $data,
    PhutilOpaqueEnvelope $key,
    PhutilOpaqueEnvelope $iv) {

    $method = 'aes-256-cbc';
    $key = $key->openEnvelope();
    $iv = $iv->openEnvelope();

    $result = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
    if ($result === false) {
      throw new Exception(
        pht(
          'Failed to openssl_encrypt() data: %s',
          openssl_error_string()));
    }

    return $result;
  }

  private function decryptData(
    $data,
    PhutilOpaqueEnvelope $key,
    PhutilOpaqueEnvelope $iv) {

    $method = 'aes-256-cbc';
    $key = $key->openEnvelope();
    $iv = $iv->openEnvelope();

    $result = openssl_decrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Read the exception message: openssl_error_string() names the concrete cause (e.g. wrong key length vs cipher not found)
  2. Verify key material lengths: aes-256-cbc needs exactly a 32-byte key and a 16-byte IV after base64 decoding keyring values
  3. Confirm the cipher exists on this host: php -r 'var_dump(in_array("aes-256-cbc", openssl_get_cipher_methods(true)));'
  4. If keys were rotated or format settings changed, re-encode files with the storage format migration tooling rather than forcing writes/reads

Example fix

// before
$key_material = 'a1b2c3...'; // 64 hex chars = 64 bytes, wrong for aes-256

// after: keyring material must decode to exactly 32 raw bytes (256 bits)
$key_material = base64_encode(openssl_random_pseudo_bytes(32));
$iv          = openssl_random_pseudo_bytes(16);
Defensive patterns

Strategy: validation

Validate before calling

if (strlen($key->openEnvelope()) !== 32 || strlen($iv->openEnvelope()) !== 16) {
  // aes-256-cbc requires a 32-byte key and 16-byte IV: reject before
  // calling openssl_encrypt()/openssl_decrypt()
}

Try / catch

catch Exception from encryptData/decryptData, log openssl_error_string() verbatim, and fail closed — never fall back to storing or serving plaintext.

Prevention

When it happens

Trigger: Writing or reading (newWriteIterator/newReadIterator, and the master-key wrap in formatStorageProperties) files through the AES-256 format when the keyring master key material has the wrong length, per-file key/IV storage properties are corrupted, or the PHP OpenSSL extension rejects the aes-256-cbc cipher.

Common situations: Keyring keys entered as hex strings or with stray whitespace instead of exact raw/base64 32-byte material; corrupted iv.base64/payload.base64 storage properties; PHP/OpenSSL builds or configurations where the cipher alias is unavailable.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/ff4bbc71f035c1df. Report an issue: GitHub.