<?php
if (PHP_VERSION_ID < 70000) exit;
$res = openssl_pkey_new([
'digest_alg' => 'sha256',
'private_key_bite' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA
]);
openssl_pkey_export($res, $privateKey);
$publicKey = openssl_pkey_get_details($res)['key'];
$message = 'Prime Numbers Rock!';
$aesKey = random_bytes(32);
// Basically a poor-man's HKDF by just using HMAC
$keyE = hash_hmac('sha256', 'Encryption Key', $aesKey, true);
$keyA = hash_hmac('sha256', 'Authentication Key', $aesKey, true);
$iv = random_bytes(16);
$ciphertext = openssl_encrypt($message, 'aes-256-ctr', $keyE, OPENSSL_RAW_DATA, $iv);
$mac = hash_hmac('sha256', $iv .$ciphertext, $keyA, true);
$combined = $mac . $iv . $ciphertext;
$rsaCipher = '';
openssl_public_encrypt($aesKey, $rsaCipher, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
$sendMe = $rsaCipher . $combined;
var_dump(base64_encode($sendMe));
## DECRYPTION ##
$rsaPart = mb_substr($sendMe, 0, 256, '8bit'); // Assuming 2048-bit RSA
$aesPart = mb_substr($sendMe, 256, null, '8bit');
$mac = mb_substr($aesPart, 0, 32, '8bit');
$iv = mb_substr($aesPart, 32, 16, '8bit');
$cipher = mb_substr($aesPart, 48, null, '8bit');
$aesKey = '';
openssl_private_decrypt($rsaPart, $aesKey, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
$keyE = hash_hmac('sha256', 'Encryption Key', $aesKey, true);
$keyA = hash_hmac('sha256', 'Authentication Key', $aesKey, true);
$calc = hash_hmac('sha256', $iv . $cipher, $keyA, true);
if (!hash_equals($calc, $mac)) {
throw new Exception('MAC validation failure');
}
$decrypted = openssl_decrypt($cipher, 'aes-256-ctr', $keyE, OPENSSL_RAW_DATA, $iv);
var_dump($decrypted); // string(19) "Prime Numbers Rock!"
preferences:
28.83 ms | 409 KiB | 5 Q