phalcon/cphalcon · error · EncryptionFailed
Could not encrypt data
Error message
Could not encrypt data
What it means
Crypt's encrypt path calls openssl_encrypt(); a false return is converted to EncryptionFailed('Could not encrypt data'). OpenSSL refuses to encrypt when the key length does not match the cipher (e.g., a 13-byte string with aes-256 requiring 32), or when GCM/CCM is used with invalid tag/length parameters - Phalcon surfaces it as this exception.
Source
Thrown at phalcon/Encryption/Crypt.zep:924
iv,
authTag,
authData,
authTagLength
);
let this->authTag = authTag;
} else {
let encrypted = openssl_encrypt(
padded,
cipher,
encryptKey,
OPENSSL_RAW_DATA,
iv
);
}
if (false === encrypted) {
throw new EncryptionFailed();
}
/**
* Store the tag with encrypted data and return it. In the non AEAD
* mode this is an empty string
*/
return encrypted . authTag;
}
/**
* Initialize available cipher algorithms.
*
* @return static
* @throws Exception
*/
protected function initializeAvailableCiphers() -> <static>
{
var available, cipher;View on GitHub (pinned to b7419de9cd)
Solutions
- Derive an exact-length key: 32 bytes for aes-256-* - e.g. hash('sha256', $secret, true) - or generate with random_bytes(32) and store verbatim.
- Validate key length at boot: if (strlen($key) !== 32) throw ... next to your Crypt setup.
- For GCM/CCM confirm setAuthData() was called and the tag length (if set) is 4..16.
- Catch EncryptionFailed where user data is encrypted and degrade gracefully (log, reject the operation) - never retry with a different key silently.
Example fix
// before
$crypt->setKey(getenv('APP_SECRET')); // arbitrary length, e.g. 19 chars
$crypt->encrypt($data); // openssl_encrypt false -> throws
// after
$crypt->setKey(substr(hash('sha256', getenv('APP_SECRET'), true), 0, 32));
$crypt->encrypt($data); Defensive patterns
Strategy: try-catch
Validate before calling
$required = ['aes-128' => 16, 'aes-192' => 24, 'aes-256' => 32];
$prefix = substr($cipher, 0, 7);
if (isset($required[$prefix]) && strlen($key) !== $required[$prefix]) {
throw new \RuntimeException("Key for {$cipher} must be {$required[$prefix]} bytes");
}
$crypt->setKey($key);
$crypt->encrypt($data); Try / catch
try {
$stored = $crypt->encrypt($data);
} catch (\Phalcon\Encryption\Crypt\Exception\EncryptionFailed $e) {
// wrong key length or AEAD misconfiguration - fail the write, alert
$logger->error('Encryption failed: ' . $e->getMessage());
throw new \RuntimeException('Could not secure payload', 0, $e);
} Prevention
- Always derive exact-length keys (hash('sha256', $secret, true) or random_bytes(32)).
- Validate key length at boot next to your Crypt DI setup.
- Never store plaintext as a fallback when encryption fails - surface the error instead.
When it happens
Trigger: setKey($passphrase) with an arbitrary-length string while the cipher expects an exact key size; AEAD mode with an incompatible auth tag setup; extremely rare OpenSSL build issues with the chosen cipher (usually caught earlier by the availability check).
Common situations: Passing human passwords directly as keys; env key values that lost bytes (encoding, quoting) so their length no longer matches; mixing key derivation on one side but not the other; truncated keys after config serialization.
Related errors
- Could not decrypt data
- Decryption key cannot be empty
- Encryption key cannot be empty
- Cannot calculate Random Pseudo Bytes
- The {} algorithm '{}' is not supported on this system.
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/fcaefa3a7b568686.
Report an issue: GitHub.