正确使用方法 php openssl_encrypt
Correct way to use php openssl_encrypt
我正在一个项目中使用密码学,我需要一些关于如何使用 openssl_encrypt
和 openssl_decrypt
的帮助,我只想知道最基本和正确的方法它。这是我到目前为止得到的:
// To encrypt a string
$dataToEncrypt = 'Hello World';
$cypherMethod = 'AES-256-CBC';
$key = random_bytes(32);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cypherMethod));
$encryptedData = openssl_encrypt($dataToEncrypt, $cypherMethod, $key, $options=0, $iv);
然后我存储 $cypherMethod
、$key
和 $iv
,以便在解密 $encryptedData
时使用。 (我们不详细说明我是如何存储这些值的,谢谢!)
// To decrypt an encrypted string
$decryptedData = openssl_decrypt($encryptedData, $cypherMethod, $key, $options=0, $iv);
首先,上面的示例代码是如何使用 php openssl_encrypt
的正确示例吗?
其次,我生成 $key
和 $iv
的方法是否正确且安全?因为我一直在阅读,所以密钥应该是加密安全的。
最后,AES-256-CBC
不需要 32-byte
值吗?如果是,那为什么openssl_cipher_iv_length()
returns 的长度只有int(16)
?不应该是int(32)
吗?
First off, is the above example code a correct example of how to use php openssl_encrypt?
您对该函数的使用看起来是正确的,但是您可能需要考虑 CBC 以外的操作模式。 CBC 很难正确处理,因为仅在这种模式下加密数据就会遭到已知的攻击,例如臭名昭著的 CBC bit-flipping attack, which allows an attacker to make meaningful changes to the plaintext by modifying the ciphertext. If possible I would use an authenticated encryption mode like GCM if you can (looks like it's supported in PHP 7.1+ (Example #1)).
如果您使用 CBC 模式,请查看 Example #2 in the docs。请注意,在加密后,MAC(消息验证码)将在密文上计算并存储。这个MAC在解密密文之前需要重新计算,如果与存储的MAC不匹配则密文被修改,无效
Second, is my method to generate the $key and $iv correct and secure? Because I keep on reading, keys should be cryptographically secure.
需要使用加密安全随机数生成器生成密钥。幸运的是,大多数操作系统通过 /dev/urandom
提供了一个开箱即用的功能。 does a good job explaining how to read from /dev/urandom
in PHP. openssl_random_pseudo_bytes
should also be cryptographically secure but there are times when this is not the case.
初始化向量 (IV) 必须是随机的,绝不能与相同的密钥重复使用。
Lastly, isn't a 32-byte value required for AES-256-CBC? If yes, then why is it that openssl_cipher_iv_length() returns only int(16) as the length? Shouldn't it be int(32)?
AES 是一种适用于 128 位(16 字节)块的块密码,与密钥大小无关。
下面是openssl_encrypt和openssl_decrypt最基本的使用方法。确保创建 32 字节 secret_key 和 16 字节 secret_iv
function encrypt_decrypt($action, $string)
{
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxx';
$secret_iv = 'xxxxxxxxxxxxxxxxxxxxxxxxx';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if ( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
} else if( $action == 'decrypt' ) {
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
}
return $output;
}
// --- Encrypt --- //
$key = openssl_digest("passkey", 'SHA256', TRUE);
$plaintext = "Data to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
// binary cipher
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
// or replace OPENSSL_RAW_DATA & $iv with 0 & bin2hex($iv) for hex cipher (eg. for transmission over internet)
// or increase security with hashed cipher; (hex or base64 printable eg. for transmission over internet)
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );
// --- Decrypt --- //
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
if (hash_equals($hmac, $calcmac))
echo $original_plaintext."\n";
// --- Encrypt --- //
function encrypt($plaintext, $secret_key = "5fgf5HJ5g27", $cipher = "AES-128-CBC")
{
$key = openssl_digest($secret_key, 'SHA256', TRUE);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
// binary cipher
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
// or replace OPENSSL_RAW_DATA & $iv with 0 & bin2hex($iv) for hex cipher (eg. for transmission over internet)
// or increase security with hashed cipher; (hex or base64 printable eg. for transmission over internet)
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
return base64_encode($iv . $hmac . $ciphertext_raw);
}
// --- Decrypt --- //
function decrypt($ciphertext, $secret_key = "5fgf5HJ5g27", $cipher = "AES-128-CBC")
{
$c = base64_decode($ciphertext);
$key = openssl_digest($secret_key, 'SHA256', TRUE);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len = 32);
$ciphertext_raw = substr($c, $ivlen + $sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
if (hash_equals($hmac, $calcmac))
return $original_plaintext . "\n";
}
我正在一个项目中使用密码学,我需要一些关于如何使用 openssl_encrypt
和 openssl_decrypt
的帮助,我只想知道最基本和正确的方法它。这是我到目前为止得到的:
// To encrypt a string
$dataToEncrypt = 'Hello World';
$cypherMethod = 'AES-256-CBC';
$key = random_bytes(32);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cypherMethod));
$encryptedData = openssl_encrypt($dataToEncrypt, $cypherMethod, $key, $options=0, $iv);
然后我存储 $cypherMethod
、$key
和 $iv
,以便在解密 $encryptedData
时使用。 (我们不详细说明我是如何存储这些值的,谢谢!)
// To decrypt an encrypted string
$decryptedData = openssl_decrypt($encryptedData, $cypherMethod, $key, $options=0, $iv);
首先,上面的示例代码是如何使用 php openssl_encrypt
的正确示例吗?
其次,我生成 $key
和 $iv
的方法是否正确且安全?因为我一直在阅读,所以密钥应该是加密安全的。
最后,AES-256-CBC
不需要 32-byte
值吗?如果是,那为什么openssl_cipher_iv_length()
returns 的长度只有int(16)
?不应该是int(32)
吗?
First off, is the above example code a correct example of how to use php openssl_encrypt?
您对该函数的使用看起来是正确的,但是您可能需要考虑 CBC 以外的操作模式。 CBC 很难正确处理,因为仅在这种模式下加密数据就会遭到已知的攻击,例如臭名昭著的 CBC bit-flipping attack, which allows an attacker to make meaningful changes to the plaintext by modifying the ciphertext. If possible I would use an authenticated encryption mode like GCM if you can (looks like it's supported in PHP 7.1+ (Example #1)).
如果您使用 CBC 模式,请查看 Example #2 in the docs。请注意,在加密后,MAC(消息验证码)将在密文上计算并存储。这个MAC在解密密文之前需要重新计算,如果与存储的MAC不匹配则密文被修改,无效
Second, is my method to generate the $key and $iv correct and secure? Because I keep on reading, keys should be cryptographically secure.
需要使用加密安全随机数生成器生成密钥。幸运的是,大多数操作系统通过 /dev/urandom
提供了一个开箱即用的功能。 /dev/urandom
in PHP. openssl_random_pseudo_bytes
should also be cryptographically secure but there are times when this is not the case.
初始化向量 (IV) 必须是随机的,绝不能与相同的密钥重复使用。
Lastly, isn't a 32-byte value required for AES-256-CBC? If yes, then why is it that openssl_cipher_iv_length() returns only int(16) as the length? Shouldn't it be int(32)?
AES 是一种适用于 128 位(16 字节)块的块密码,与密钥大小无关。
下面是openssl_encrypt和openssl_decrypt最基本的使用方法。确保创建 32 字节 secret_key 和 16 字节 secret_iv
function encrypt_decrypt($action, $string)
{
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxx';
$secret_iv = 'xxxxxxxxxxxxxxxxxxxxxxxxx';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if ( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
} else if( $action == 'decrypt' ) {
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
}
return $output;
}
// --- Encrypt --- //
$key = openssl_digest("passkey", 'SHA256', TRUE);
$plaintext = "Data to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
// binary cipher
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
// or replace OPENSSL_RAW_DATA & $iv with 0 & bin2hex($iv) for hex cipher (eg. for transmission over internet)
// or increase security with hashed cipher; (hex or base64 printable eg. for transmission over internet)
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );
// --- Decrypt --- //
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
if (hash_equals($hmac, $calcmac))
echo $original_plaintext."\n";
// --- Encrypt --- //
function encrypt($plaintext, $secret_key = "5fgf5HJ5g27", $cipher = "AES-128-CBC")
{
$key = openssl_digest($secret_key, 'SHA256', TRUE);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
// binary cipher
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
// or replace OPENSSL_RAW_DATA & $iv with 0 & bin2hex($iv) for hex cipher (eg. for transmission over internet)
// or increase security with hashed cipher; (hex or base64 printable eg. for transmission over internet)
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
return base64_encode($iv . $hmac . $ciphertext_raw);
}
// --- Decrypt --- //
function decrypt($ciphertext, $secret_key = "5fgf5HJ5g27", $cipher = "AES-128-CBC")
{
$c = base64_decode($ciphertext);
$key = openssl_digest($secret_key, 'SHA256', TRUE);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len = 32);
$ciphertext_raw = substr($c, $ivlen + $sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
if (hash_equals($hmac, $calcmac))
return $original_plaintext . "\n";
}