MySql AES_DECRYPT & AES_ENCRYPT 密钥在 PHP 中不起作用
Posted
技术标签:
【中文标题】MySql AES_DECRYPT & AES_ENCRYPT 密钥在 PHP 中不起作用【英文标题】:MySql AES_DECRYPT & AES_ENCRYPT Key is not working in PHP 【发布时间】:2021-08-16 08:26:47 【问题描述】:在我们的项目中,我们计划将数据以加密格式存储在 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);
【问题讨论】:
您的意思是“不能”而不是“能够”吗?帖子有点不清楚,您实际上并没有问过问题,而且这与 PHP 的关系不是很明显……您是否也有一些相关的 PHP 代码与我们分享? 感谢您纠正错字,但您还需要澄清我所询问的其他内容 @ADyson 你现在可以检查吗?希望你能理解 谢谢。但是,我们看不到您传递给函数的任何值,只有变量。这让你很难确切地知道你做了什么。 无论如何,下面的答案对您没有帮助吗?很详细。 【参考方案1】:当使用 AES 使用一个库进行加密,然后使用不同的库进行解密时,重要的是要确保双方的所有细微之处都相同。例如。
AES 有多种模式(例如 aes-128-cbc、aes_128-ecb、aes-128-gcm、aes-256-cbc、aes_256-ecb、aes-256-gcm 等等)。对加密和解密使用相同的模式很重要。
许多 AES 加密/解密函数允许您传入密码而不是密钥,并且该函数在内部从密码派生密钥。然而,当从一个库转移到另一个库时,这通常充满了问题,因为内部用于密钥派生的方法在不同的实现之间差异很大。因此,最好直接传递密钥(长度正确,适合您使用的 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;
再次,请注意正确传递所有内容时所采取的措施。但是,在我的系统上,上面的代码 sn-p 不会产生任何输出。有什么问题?
在我的系统上运行openssl_get_cipher_methods,我看到不支持aes-128-ecb。这并不奇怪,因为 aes-128-ecb 有 known weaknesses。为了解决这个问题,最好在 MySQL 端使用一些其他模式进行加密(有关更多信息,请参阅https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html)。
【讨论】:
smashingmagazine.com/2012/05/…. 【参考方案2】:我们在 Mcrypt_encrypt 和 mcrypt_decrypt 中得到了解决方案
MySql:
SELECT TO_BASE64(AES_ENCRYPT('selvamani', '34/xrbFET445QS0')) AS 编码
SELECT AES_DECRYPT(FROM_BASE64("Bdc3RbB4rU3vBrkdIjTFoQ=="),'34/xrbFET445QS0') AS decrypt_string
PHP:
$val = "selvamani"; $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));
回声 $val;
【讨论】:
@jethan 请提供另一个答案,供您编辑以上是关于MySql AES_DECRYPT & AES_ENCRYPT 密钥在 PHP 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 中 AES_DECRYPT 加密,如何在瀚高数据库中使用
不能 AES_DECRYPT (MySQL) 使用 openssl_encrypt (PHP) 加密的字符串