如何从MySQL中解密Cakephp3加密数据?

5uzkadbs  于 2022-11-24  发布在  PHP
关注(0)|答案(3)|浏览(155)

我有一个非常具体的要求,其中一些列需要使用aes_encrypt / aes_decrypt加密。我们需要使用eas在SQL级别加密信息,以便可以使用另一个应用程序读取信息,或者使用查询和aes_encrypt / aes_decrypt直接从MySQL读取信息。
我们的应用程序是使用CakePHP 3开发的,数据库是MySQL 5.6.25。
我找到并仔细地按照这一选定答案上的说明去做:Encyption/Decryption of Form Fields in CakePHP 3
现在,数据被加密保存在数据库中...问题是,我们仍然需要能够在MySQL上使用aes_decrypt来解密信息,但它返回NULL。
在CakePHP 3上,配置/应用程序.php:

'Security' => ['salt' => '1234567890']

然后使用以下方式加密:

Security::encrypt($value, Security::salt());

数据保存在MySQL中,但aes_decrypt()返回NULL

SELECT AES_DECRIPT(address_enc, '1234567890') FROM address;

如何设置CakePHP 3正确加密信息,以便稍后在MySQL中使用aes_decrypt()解密?

[编辑]
我的MYSQL表:

CREATE TABLE IF NOT EXISTS `address` (
`id` int(11) NOT NULL,
  `address` varchar(255) DEFAULT NULL,
  `address_enc` blob,
  `comment` varchar(255) DEFAULT NULL,
  `comment_enc` blob
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

注:地址和备注仅供测试使用。
然后,在CakePHP上,我创建了一个自定义数据库类型:

源代码/数据库/类型/加密类型.php

<?php
namespace App\Database\Type;

use Cake\Database\Driver;
use Cake\Database\Type;
use Cake\Utility\Security;

class CryptedType extends Type
{
    public function toDatabase($value, Driver $driver)
    {
        return Security::encrypt($value, Security::salt());
    }

    public function toPHP($value, Driver $driver)
    {
        if ($value === null) {
            return null;
        }
        return Security::decrypt($value, Security::salt());
    }
}

源代码/配置/引导程序.php

注册自定义类型。

use Cake\Database\Type;
Type::map('crypted', 'App\Database\Type\CryptedType');

源文件/模型/表/地址表.php

最后,将可加密列Map到已注册的类型,就这样,从现在开始,一切都将自动处理。

use Cake\Database\Schema\Table as Schema;

class AddressTable extends Table
{
    // ...

    protected function _initializeSchema(Schema $table)
    {
        $table->columnType('address_enc', 'crypted');
        $table->columnType('comment_enc', 'crypted');
        return $table;
    }

    // ...
}
ki0zmccv

ki0zmccv1#

您真的需要这样做吗?

我不打算讨论在数据库中存储加密数据的利弊,但尝试在SQL级别解密是否是一个好主意,这是一个应该问的问题。
因此,问问你自己是否真的 * 需要 * 这样做,也许在应用程序级别实现解密会更好,这可能会使复制 * 确切 * Security::decrypt()所做的事情更容易,这不仅是解密,而且是完整性检查。
看看Security::decrypt()的内部功能。

*http://github.com/cakephp/cakephp/blob/3.1.7/src/Utility/Security.php#L201
*http://github.com/cakephp/cakephp/blob/3.1.7/src/Utility/Crypto/OpenSsl.php#L77
*http://github.com/cakephp/cakephp/blob/3.1.7/src/Utility/Crypto/Mcrypt.php#L89

在您的其他应用程序中重新实现它应该非常容易。
小心,你的手指可能会被烫伤!
我绝不是一个加密Maven,所以考虑以下只是一个基本的例子,让事情开始,并通知自己可能的概念,特别是安全相关的问题!
在不知道自己在做什么的情况下处理数据的加密/解密是一个非常糟糕的主意-我怎么强调都不为过!

在SQL级别解密数据

也就是说,使用您链接到的我的糟糕(原文如此)答案中的示例代码,即使用Security::encrypt()Security::salt()作为加密密钥,默认情况下将为您留下一个在AES-256-CBC模式下加密的值,使用从与其自身连接的salt派生的加密密钥(其SHA 256表示形式的前32个字节)。
但这还不是全部,此外,加密的值会得到一个HMAC哈希,初始化向量会被挂起,这样就不会得到可以直接传递给AES_DECRYPT()的“普通”加密数据。
因此,如果您希望在MySQL级别解密此数据(无论出于何种原因),则首先必须设置正确的块加密模式

SET block_encryption_mode = 'aes-256-cbc';

稀疏HMAC散列(前64个字节)和初始化向量(后16个字节)

SUBSTRING(`column` FROM 81)

并且使用hash('sha256', Security::salt() . Security::salt())前32个字节作为加密密钥,并使用来自加密值的初始化向量进行解密,

SUBSTRING(`column`, 65, 16)

所以最后你会得到这样的结果

SET block_encryption_mode = 'aes-256-cbc';
SELECT
    AES_DECRYPT(
        SUBSTRING(`column` FROM 81), -- the actual encryted data
        'the-encryption-key-goes-here',
        SUBSTRING(`column`, 65, 16) -- the intialization vector
    )
FROM table;

最后,您可能还希望转换值(CAST(AES_DECRYPT(...) AS CHAR)),并删除可能的零填充(不确定AES_DECRYPT()是否自动执行此操作)。

数据完整性检查

需要注意的是,加密值前面的HMAC哈希有一个特定的用途,它用于确保完整性,因此如果直接删除它,您将失去完整性。为了保留它,您还必须在SQL级别实现(定时攻击安全)HMAC 256生成/比较。这将我们带回到最初的问题,您真的需要在SQL级别解密吗?

x3naxklr

x3naxklr2#

[解决方案]针对这一特定需求(我们需要使用eas在SQL级别加密信息,以便使用其他应用程序或使用查询和aes_encrypt / aes_decryp直接从MySQL读取信息)的解决方案是在CakePHP中创建自定义数据库类型,而不是使用CakePHP加密方法,我们实现了PHP Mcrypt。
现在信息从我们的CakePHP 3应用程序保存到数据库中,并使用eas_decrypt和aes_encrypt在MySQL/phpMyAdmin级别读取数据。

mccptt67

mccptt673#

对于任何努力使用MYSQL解密的人:这通常适用于使用对称AES加密/解密的任何人-特别是在尝试使用AES_DECRYPT解密时。
例如,如果您使用的是aes-128-ecb,并且加密数据的长度为16个字节且没有填充,则需要在尝试解密之前向加密数据添加填充字节。(因为mySQL需要PKCS 7填充)。因为MySQL使用PKCS 7,您需要再添加16个字节,在本例中,这些填充字节为0x 10101010101010101010101010101010101010101010。我们取左边的16个字节,因为当我们加密0x 1010101010101010101010101010101010时,我们得到32个字节,而我们只需要前16个字节。

aes_decrypt(concat(<ENCRYPTED_BYTES>, left(aes_encrypt(<PAD BYTES>, <KEY>), 16)), <KEY>)

相关问题