MySql AES_DECRYPT & AES_ENCRYPT 密钥在 PHP 中不起作用

MySql AES_DECRYPT & AES_ENCRYPT Key is not working in PHP

在我们的项目中,我们计划将数据以加密格式存储在 mysql 数据库中,我们在我们的项目中使用了 php 和 MqSql。 Mqsql 加密工作正常,我对 MqSql 使用了以下方法

 INSERT INTO emails  SET email= TO_BASE64(AES_ENCRYPT('selvamani.p','3xY4/xrbFETctQS0Rkd1r6MKS4PUXetmjTeuRHkMt2w=', '44Y9/xrbFETcmQS0'));

    SELECT  id, AES_DECRYPT(FROM_BASE64(email), '3xY4/xrbFETctQS0Rkd1r6MKS4PUXetmjTeuRHkMt2w=','44Y9/xrbFETcmQS0') AS decrypt_string  from emails e 

但是我们无法解密 PHP 中的字符串 是由 MqSql 加密的。在php下面我们这样使用

 $stringValue = openssl_encrypt($stringValue, $this->cipher_method,$this->encryption_key, $this->options, $this->encryption_iv);    

    $stringValue = openssl_decrypt(base64_decode($stringValue), $this->cipher_method, $this->encryption_key, $this->options, $this->encryption_iv);     

当使用 AES 使用一个库进行加密,然后使用另一个库进行解密时,请务必确保双方的所有细节都相同。例如。

  • AES 有多种模式(例如 aes-128-cbc、aes_128-ecb、aes-128-gcm、aes-256-cbc、aes_256-ecb、aes-256- gcm 等等)。加密和解密使用相同的模式很重要。

  • 许多 AES encryption/decryption 函数允许您传入密码而不是密钥,并且函数在内部从密码派生出密钥。然而,当从一个库转到另一个库时,这通常会充满问题,因为内部用于密钥派生的方法在不同的实现之间差异很大。因此,最好直接传递密钥(长度正确,适用于您正在使用的 AES 模式),而不是传递密码。

  • 加密和解密函数通常希望将明文、密文、密钥、iv 等输入作为原始字节而非文本传入。请注意这一点,并确保在需要时传入原始字节。同样,加密和解密函数通常以原始字节形式产生输出。请务必相应地处理这些问题。

MySQL 默认使用 aes_128_ecb 模式(参见 https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html)。因此,要在 MySQL 中使用 aes_128_ecb 模式使用密钥 F3229A0B371ED2D9441B830D21A390C3 加密明文 'bill.smith@gmail.com',我们可以这样做:

 select to_base64(aes_encrypt('bill.smith@gmail.com', UNHEX('F3229A0B371ED2D9441B830D21A390C3')));

请注意,密钥是以十六进制编码的字符串形式提供的,其长度与正在使用的模式(128 字节)相符,我们正在使用 UNHEX() 将其转换为原始字节MySQL aes_encrypt() 函数。 aes_encrypt() 函数生成原始字节作为其输出,我们使用 to_base64() 对这些原始字节进行 base64 编码以生成可显示的文本。上面的语句产生以下 base64 编码的密文:

oPN1EIfxX+MFMfcp2jTjjB55QVUURKV8lbfcwhT3MMk=

让我们看看是否可以使用相同的密钥解密它,在命令行上使用 openssl,看看是否会生成我们开始时使用的明文:

echo -n 'oPN1EIfxX+MFMfcp2jTjjB55QVUURKV8lbfcwhT3MMk=' | base64 -d | openssl aes-128-ecb -d -K F3229A0B371ED2D9441B830D21A390C3

再次注意确保所有输入都正确传递。上面的命令产生:

bill.smith@gmail.com

太棒了。我们能够在 MySQL 中加密一些明文,然后在 openssl 中执行相反的操作,并且成功了。现在,让我们看看是否可以解密PHP中的密文。让我们试试这个:

$ciphertextbase64="oPN1EIfxX+MFMfcp2jTjjB55QVUURKV8lbfcwhT3MMk=";
$keyhex='F3229A0B371ED2D9441B830D21A390C3'; 
$ciphertextbytes=base64_decode($ciphertextbase64);
$keybytes=hex2bin($keyhex);
$plaintext = openssl_decrypt($ciphertextbytes, 'aes-128-ecb', $keybytes);
print $plaintext;

再次注意正确传递所有内容的注意事项。但是,在我的系统上,上面的代码片段没有产生任何输出。有什么问题吗?

运行 openssl_get_cipher_methods,在我的系统上,我发现不支持 aes-128-ecb。这并不奇怪,因为 aes-128-ecb 有 已知弱点 。要解决此问题,最好在 MySQL 端使用其他模式进行加密(有关详细信息,请参阅 https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html)。

我们在 Mcrypt_encrypt 和 mcrypt_decrypt

中找到了解决方案

MySql :

SELECT TO_BASE64(AES_ENCRYPT('selvamani', '34/xrbFET445QS0')) AS enc

SELECT AES_DECRYPT(FROM_BASE64("Bdc3RbB4rU3vBrkdIjTFoQ=="),'34/xrbFET445QS0') AS decrypt_string

PHP :

$val = "塞尔瓦马尼"; $key = "34/xrbFET445QS0"; $pad_value = 16-(strlen($val) % 16); $val = str_pad($val, (16*(floor(strlen($val) / 16)+1)), chr($pad_value)); $data = Mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM)); echo base64_encode($data);

$key = "34/xrbFET445QS0"; $val = base64_decode("Bdc3RbB4rU3vBrkdIjTFoQ=="); $val = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM));

echo $val;