PHP使用Openssl解密AES Mysql加密

11

我只是在我的 MySQL 表格上进行基本的数据加密。我遵循了这里找到的指南 https://dev.mysql.com/doc/refman/5.6/en/encryption-functions.html#function_aes-encrypt

但是我遇到了一个问题。虽然我知道我可以在 MySQL 查询中使用 aes_decrypt 解密数据,但我也希望php能够自行解密。

我已经让这部分工作正常了。如果 MySQL 像这样完成非常基本的 AES_ENCRYPTION

INSERT INTO tablename (dataset) VALUES (AES_ENCRYPT('testvalue','mysecretphrase'))
我可以使用 PHP 解密这个东西,就像这样。
openssl_decrypt(base64_encode($dR['dataset']), 'aes-128-ecb', 'mysecretphrase')

当我使用MySQL在上面链接中提到的推荐UNHEX(SHA2('mysecretphrase',512))时,遇到了问题。

我尝试使用php的sha*函数,并确认它们都生成与MySQL的sha2()相同的字符串。

openssl_digest('mysecretphrase', 'sha512')
// AND
hash('sha512', 'mysecretphrase')

最后,为了解决mysql使用的UNHEX(),经过一些研究我发现PHP的hex2bin == unhex http://www.php.net/manual/en/function.hex2bin.php

然而,当解密数据时却没有任何结果。这就是它一直失败的地方。我感觉自己可能漏掉了些什么,但这只会返回空结果,而不是解密数据。

openssl_decrypt(base64_encode($dR['dataset']), 'aes-128-ecb', hex2bin(openssl_digest('mysecretphrase', 'sha512')))
任何帮助、指针或提示都将不胜感激。

只要您仅在插入时进行加密,且从不选择多个记录,我建议使用PHP进行加密,因为这对性能或功能没有实际影响。 - twicejr
3个回答

4
我在此回答是因为评论似乎比较贵⋯⋯上面的帖子很明确地告诉了您问题所在,但并没有真正说明如何解决它。openssl_encrypt()和openssl_decrypt()静默地将密钥裁剪为最大16字节长度(至少对于aes-128-ecb),且无法更改。因此,当在MySQL中使用AES_ENCRYPT时,您需要通过创建其子字符串来缩短密钥。
INSERT INTO tablename (dataset) 
VALUES (AES_ENCRYPT('testvalue',SUBSTR( UNHEX(SHA2('mysecretphrase',512)), 1, 16))))

注意上述答案中的l_16列现在与使用子字符串的["data2"]相同了吗?(在php中可能需要进行strtolower())。
如果这引起了您的安全顾虑,您需要找到一种没有此限制的替代加密算法。

4

我曾经遇到了同样的问题,多亏了MIvanIsten的回答,我知道了如何正确地使用MariaDB/MySQL进行加密,并在PHP中进行解密:

加密:

SELECT HEX( AES_ENCRYPT( 'secret data', 
SUBSTR(UNHEX(SHA2('mysecretphrase', 512)), 1, 16) )) AS encrypted;

解密:

openssl_decrypt(
   base64_encode(hex2bin($encrypted_string_from_mysql)), 
   'aes-128-ecb',
   substr(hex2bin(openssl_digest('mysecretphrase', 'sha512')), 1, 16)  
);

3

openssl_encrypt()openssl_decrypt()会将密钥静默截断到最大16字节长度(至少对于aes-128-ecb加密算法)

<?php
    $key1 = hex2bin(openssl_digest('mysecretphrase', 'sha512'));
    $key2 = substr($key1, 0, 16);
    $key3 = substr($key1, 0, 15);
    $method = 'aes-128-ecb';
    $in = 'testvalue';
    $data1 = base64_decode(openssl_encrypt($in, $method, $key1));
    $data2 = base64_decode(openssl_encrypt($in, $method, $key2));
    $data3 = base64_decode(openssl_encrypt($in, $method, $key3));
    var_dump(
        array(
            'key1'=>bin2hex($key1),
            'key2'=>bin2hex($key2),
            'key3'=>bin2hex($key3),
            'data1'=>bin2hex($data1),
            'data2'=>bin2hex($data2),
            'data3'=>bin2hex($data3),
            'data1==data2'=>($data1===$data2),
            'data1==data3'=>($data1===$data3)
        )
    );
?>

结果:

   array(8) {
        ["key1"]=>string(128) "5fe76dfd5b75cf7cf68fae85d26fcc9b7951806ad6daaa71d843c6ec0e0ec9233a828ad9b60986a43d734983c8a0a50d3a0a49ec5ac196cfcc136aa16e0c5f89"
        ["key2"]=>string(32) "5fe76dfd5b75cf7cf68fae85d26fcc9b"
        ["key3"]=>string(30) "5fe76dfd5b75cf7cf68fae85d26fcc"
        ["data1"]=>string(32) "eb69e89312c1f7b9522d0e66346f2029"
        ["data2"]=>string(32) "eb69e89312c1f7b9522d0e66346f2029"
        ["data3"]=>string(32) "664f5a28d241f959beac350f2314b079"
        ["data1==data2"]=>bool(true)
        ["data1==data3"]=>bool(false)
    }

在mysql中,完整长度的键被AES_ENCRYPT()AES_DECRYPT()使用。
SELECT 
    HEX(AES_ENCRYPT('testvalue',UNHEX(SHA2('mysecretphrase',512)))) AS l_full,
    HEX(AES_ENCRYPT('testvalue',SUBSTR(UNHEX(SHA2('mysecretphrase',512)),1,16))) AS l_16,
    HEX(AES_ENCRYPT('testvalue',SUBSTR(UNHEX(SHA2('mysecretphrase',512)),1,15))) AS l_15;

结果:

l_full                           | l_16                             | l_15
---------------------------------|----------------------------------|----------------------------------------
A88DD1EFB377FD31A0EFA55EA29BA8C6 | EB69E89312C1F7B9522D0E66346F2029 | 664F5A28D241F959BEAC350F2314B079

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接