A continuación se muestra mi implementación de cifrado en PHP. Se basa en mcrypt y usa AES-128 en modo CTR junto con un RIPEMD-128 HMAC para la verificación de integridad.
Por brevedad, he incorporado las funciones para calcular HMAC, verificar HMAC, directamente en funciones de cifrado / descifrado. Por otro lado, he agregado más comentarios a continuación que el código original, para garantizar que las personas que no están familiarizadas con PHP 1 entiendan lo que sucede.
function encrypt($data, $key, $hmac_key) {
// Get the appropriate IV size for AES-128/CTR
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, 'ctr');
// Create a random IV.
$iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
// Encrypt with AES-128/CTR with the provided key.
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, 'ctr', $iv);
// Base HMAC on the contatenated IV, the encrypted data and the cipher identifier.
$hmac_data = $iv . $encrypted . MCRYPT_RIJNDAEL_128;
// Calculate HMAC using ripemd128 and the supplied HMAC key.
$hmac = hash_hmac('ripemd128', $hmac_data, $hmac_key);
// Concatenate together the IV, encrypted data, and hmac, and base 64 encode them.
return base64_encode($iv . $encrypted . $hmac);
}
function decrypt($encrypted, $key, $hmac_key) {
// Decode from base 64.
$encrypted = base64_decode($encrypted);
// Get the appropriate IV size for AES-128/CTR
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, 'ctr');
// Grab the IV and HMAC from the data.
$iv = substr($encrypted, 0, $ivSize);
$hmac = substr($encrypted, -32);
// Cut out the remaining data, which is the cipher text.
$encrypted = substr($encrypted, $ivSize, -32);
// Base HMAC on the contatenated IV, the encrypted data and the cipher identifier.
$hmac_data = $iv . $encrypted . MCRYPT_RIJNDAEL_128;
// Calculate verification HMAC using ripemd128 and the supplied HMAC key.
$verification_hmac = hash_hmac('ripemd128', $hmac_data, $hmac_key);
$verification = true;
// Refuse to proceed if the two HMACs are of different length.
if (strlen($hmac) !== strlen($verification_hmac)) {
return NULL;
}
// Always iterate over the entire length of the HMACs to avoid timing information.
for($i = 0; $i < strlen($verification_hmac); $i++) {
// Check for strict equality for each character.
if($verification_hmac[$i] !== $verification_hmac[$i]) {
$verification = false;
}
}
// Refuse to proceed if the two HMACs don't match exactly.
if (!$verification) {
return NULL;
}
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, 'ctr', $iv);
return $decrypted;
}
1 : Estoy pensando principalmente en el operador de concatenación, punto (.), que puede no ser del todo obvio.