我用openssl编写了一个用于对称加密的小类,它在PHP中加密和解密,但我似乎无法使用命令行解密输出,或者以相同的方式加密相同的数据。 / p>
我的课程是:
Class SimpleCrypt {
public static function encrypt($password, $data, $enc_method='AES-256-CBC', $hash_method='SHA512') {
self::check_methods($enc_method, $hash_method);
$iv = self::hashIV($password, $hash_method, openssl_cipher_iv_length($enc_method));
$infostr = sprintf('$%s$%s$', $enc_method, $hash_method);
return $infostr . openssl_encrypt($data, $enc_method, $password, false, $iv);
}
public static function decrypt($password, $edata) {
$e_arr = explode('$', $edata);
if( count($e_arr) != 4 ) {
Throw new Exception('Given data is missing crucial sections.');
}
$enc_method = $e_arr[1];
$hash_method = $e_arr[2];
self::check_methods($enc_method, $hash_method);
$iv = self::hashIV($password, $hash_method, openssl_cipher_iv_length($enc_method));
return openssl_decrypt($e_arr[3], $enc_method, $password, false, $iv);
}
private static function hashIV($password, $method, $iv_size) {
$myhash = hash($method, $password, TRUE);
while( strlen($myhash) < $iv_size ) {
$myhash .= hash($method, $myhash, TRUE);
}
return substr($myhash, 0, $iv_size);
}
private static function check_methods($enc, $hash) {
if( ! function_exists('openssl_encrypt') ) {
Throw new Exception('openssl_encrypt() not supported.');
} else if( ! in_array($enc, openssl_get_cipher_methods()) ) {
Throw new Exception('Encryption method ' . $enc . ' not supported.');
} else if( ! in_array(strtolower($hash), hash_algos()) ) {
Throw new Exception('Hashing method ' . $hash . ' not supported.');
}
}
} // -- end class SimpleCrypt -- //
$enc = SimpleCrypt::encrypt('pass', 'test data');
$dec = SimpleCrypt::decrypt('pass', $enc);
echo $enc . "\n" . $dec;
// Output:
// $AES-256-CBC$SHA512$yH0uN95Vya0pTwcoJRFb+g==
// test data
这段代码再现了IV:
php -r 'echo strtoupper(bin2hex(substr(hash("SHA512", "pass", true), 0, openssl_cipher_iv_length("AES-256-CBC"))));'
//output: 5B722B307FCE6C944905D132691D5E4A
但是这段代码给了我一个与输入不相似的乱码输出:
$ echo yH0uN95Vya0pTwcoJRFb+g== | base64 -d | openssl enc -AES-256-CBC -d -nosalt -nopad -k pass -iv 5B722B307FCE6C944905D132691D5E4A
ã`ÈAgè}½5øÍÝEÞ
00000000 e3 60 c8 41 67 e8 7d bd 35 00 f8 cd dd 45 13 de |.`.Ag.}.5....E..|
从命令行编码数据给我:
$ echo "test data" | openssl enc -e -AES-256-CBC -nosalt -k pass -iv 5B722B307FCE6C944905D132691D5E4A | hexdump -C
00000000 ca fc 84 6a 95 51 8f 0e 61 14 96 77 4e 22 dd 39 |...j.Q..a..wN".9|
$ echo "test data" | openssl enc -e -AES-256-CBC -nosalt -k pass -iv 5B722B307FCE6C944905D132691D5E4A | base64
yvyEapVRjw5hFJZ3TiLdOQ==
有谁可以告诉我在PHP代码中我做错了什么?
只是回顾Daniel的回答中的解决方案,我们需要使用-K
参数来openssl而不是-k
或-pass
,并且它需要字符串的十六进制表示。例如:
echo strtoupper(bin2hex('pass'));
//output: 70617373
然后正确的命令是:
echo yH0uN95Vya0pTwcoJRFb+g== | base64 -d | openssl enc -AES-256-CBC -d -nosalt -K 70617373 -iv 5B722B307FCE6C944905D132691D5E4A | hexdump -C
00000000 74 65 73 74 20 64 61 74 61 |test data|
答案 0 :(得分:1)
PHP password
的错误命名的openssl_encrypt()
参数不是密码,它是实际密钥。当使用带有小写openssl enc
的命令行-k
时,OpenSSL将使用密钥派生函数从密码派生密钥。您希望openssl enc
使用大写-K
和密钥的十六进制表示;并确保在openssl_encrypt()
参数中提供足够长的密钥{/ 1}}。
另请参阅PHP manual on openssl_encrypt()中第一个用户提供的注释。