PHP openssl 库中 DES3 方法的问题
Problems with DES3 method in PHP openssl library
我有一个 Web 服务,我可以在其中发送 "TripleDES, ECB mode, key size 192 and padding Zeros" 格式的加密数据。提供者向我展示了原始值和预期结果的示例:
原始字符串 = IA000001
加密字符串(发送到网络服务)= aVR5J/0Lph0=
;
在 PHP 中,openssl_encrypt()
函数可以很好地处理此字符串,但会引发 data not multiple of block length
SSL 错误。
我做了一个脚本来显示所有问题(带评论):
<?php
$key = '1234567890123456ABCDEFGH';
$expected_result = 'aVR5J/0Lph0=';
function test_results($expected_value, $return_value) {
echo openssl_error_string() . "\n";
$compare = var_export($return_value == $expected_value, 1);
echo "'$return_value' == '$expected_value' => {$compare}\n" ;
}
echo "Function value == Expected Value => same strings?\n";
// This works with $data == 'IA000001'
$data = 'IA000001';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_ZERO_PADDING);
test_results($expected_result, $resultado_function); // true
// but if I change string value (i.e. $data == 'IA000001T')
// openssl function fail:
// error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:data not multiple of block length
$data = 'IA000001T';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_ZERO_PADDING);
// if change options to OPENSSL_RAW_DATA, errors gone, but strings aren't equals
$data = 'IA000001';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_RAW_DATA);
test_results($expected_result, $resultado_function); // false
// results are encoded in base64? not equal, but almost equal
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_RAW_DATA);
$decoded_result = base64_encode($resultado_function);
test_results($expected_result, $decoded_result); // false but...
// Compare the firsts 11 chars:
// aVR5J/0Lph0=
// aVR5J/0Lph05HiLWyHnDqg==
// ^-- Until this char, the strings are equal.
我做错了什么?块大小?未编码密钥或数据?
注意:我无法控制 Web 服务的实现。
我不是加密大师,但最近从 mcrypt 切换到 openssl 时不得不解决类似的问题。我相信您的数据的长度需要能被八整除(即 8 个字符的块)。该字符串的长度为 9 个字符,而不是 8 个或 16 个字符,因此您会收到此错误。
您可以通过用空字符填充它来达到所需的长度(即 8 的倍数)来克服这个问题。
我把加密代码封装成一个函数来更好的封装逻辑:
$key = '1234567890123456ABCDEFGH';
$expected_result = 'aVR5J/0Lph0=';
function test_results($expected_value, $return_value) {
echo openssl_error_string() . "\n";
$compare = var_export($return_value == $expected_value, 1);
echo "'$return_value' == '$expected_value' => {$compare}\n" ;
}
function encrypt($text, $key) {
$block_size = 8;
if (strlen($text) % $block_size) {
$text = str_pad($text, strlen($text) + $block_size - strlen($text) % $block_size, "[=10=]");
}
return base64_encode(@openssl_encrypt($text, 'DES3', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING));
}
foreach (['IA000001', 'IA000001T'] as $data) {
$resultado_function = encrypt($data, $key);
test_results($expected_result, $resultado_function);
}
输出:
'aVR5J/0Lph0=' == 'aVR5J/0Lph0=' => true
'aVR5J/0Lph21RT9SWL7RSg==' == 'aVR5J/0Lph0=' => false
我有一个 Web 服务,我可以在其中发送 "TripleDES, ECB mode, key size 192 and padding Zeros" 格式的加密数据。提供者向我展示了原始值和预期结果的示例:
原始字符串 = IA000001
加密字符串(发送到网络服务)= aVR5J/0Lph0=
;
在 PHP 中,openssl_encrypt()
函数可以很好地处理此字符串,但会引发 data not multiple of block length
SSL 错误。
我做了一个脚本来显示所有问题(带评论):
<?php
$key = '1234567890123456ABCDEFGH';
$expected_result = 'aVR5J/0Lph0=';
function test_results($expected_value, $return_value) {
echo openssl_error_string() . "\n";
$compare = var_export($return_value == $expected_value, 1);
echo "'$return_value' == '$expected_value' => {$compare}\n" ;
}
echo "Function value == Expected Value => same strings?\n";
// This works with $data == 'IA000001'
$data = 'IA000001';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_ZERO_PADDING);
test_results($expected_result, $resultado_function); // true
// but if I change string value (i.e. $data == 'IA000001T')
// openssl function fail:
// error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:data not multiple of block length
$data = 'IA000001T';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_ZERO_PADDING);
// if change options to OPENSSL_RAW_DATA, errors gone, but strings aren't equals
$data = 'IA000001';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_RAW_DATA);
test_results($expected_result, $resultado_function); // false
// results are encoded in base64? not equal, but almost equal
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_RAW_DATA);
$decoded_result = base64_encode($resultado_function);
test_results($expected_result, $decoded_result); // false but...
// Compare the firsts 11 chars:
// aVR5J/0Lph0=
// aVR5J/0Lph05HiLWyHnDqg==
// ^-- Until this char, the strings are equal.
我做错了什么?块大小?未编码密钥或数据?
注意:我无法控制 Web 服务的实现。
我不是加密大师,但最近从 mcrypt 切换到 openssl 时不得不解决类似的问题。我相信您的数据的长度需要能被八整除(即 8 个字符的块)。该字符串的长度为 9 个字符,而不是 8 个或 16 个字符,因此您会收到此错误。
您可以通过用空字符填充它来达到所需的长度(即 8 的倍数)来克服这个问题。
我把加密代码封装成一个函数来更好的封装逻辑:
$key = '1234567890123456ABCDEFGH';
$expected_result = 'aVR5J/0Lph0=';
function test_results($expected_value, $return_value) {
echo openssl_error_string() . "\n";
$compare = var_export($return_value == $expected_value, 1);
echo "'$return_value' == '$expected_value' => {$compare}\n" ;
}
function encrypt($text, $key) {
$block_size = 8;
if (strlen($text) % $block_size) {
$text = str_pad($text, strlen($text) + $block_size - strlen($text) % $block_size, "[=10=]");
}
return base64_encode(@openssl_encrypt($text, 'DES3', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING));
}
foreach (['IA000001', 'IA000001T'] as $data) {
$resultado_function = encrypt($data, $key);
test_results($expected_result, $resultado_function);
}
输出:
'aVR5J/0Lph0=' == 'aVR5J/0Lph0=' => true
'aVR5J/0Lph21RT9SWL7RSg==' == 'aVR5J/0Lph0=' => false