简体   繁体   English

mysql和php中的AES加密

[英]AES encryption in mysql and php

There is a function in Mysql AES_encrypt. Mysql AES_encrypt中有一个功能。

SELECT AES_encrypt( "Hello World", "password" ) AS encrypted_value 

This gives the result: 9438eb79863e7009722fc3f0ad4b7198 得到的结果是: 9438eb79863e7009722fc3f0ad4b7198

But when I use the code in php to do AES_encrypt it gives me a different value. 但是,当我使用php中的代码执行AES_encrypt时,它给了我一个不同的值。

The PHP code I got from stackoverflow -- PHP AES encrypt / decrypt 我从stackoverflow获得的PHP代码-PHP AES加密/解密

<?php
base64_encode(
        mcrypt_encrypt(
            MCRYPT_RIJNDAEL_256,
            $sSecretKey, $sValue, 
            MCRYPT_MODE_ECB, 
            mcrypt_create_iv(
                mcrypt_get_iv_size(
                    MCRYPT_RIJNDAEL_256, 
                    MCRYPT_MODE_ECB
                ), 
                MCRYPT_RAND)
            )
        ), "\0"
?>

The result from PHP code is ytip2sEkD87gmRk3IVI09qE7T+RoLr20YK4rJp16NkY= PHP代码的结果为ytip2sEkD87gmRk3IVI09qE7T+RoLr20YK4rJp16NkY=

Is there a method in php or codeigniter so that it returns the same value.? 在php或codeigniter中是否有一个方法,使其返回相同的值? --Thank you. - 谢谢。

There are three problems with the code you are using: 您使用的代码存在三个问题:

  1. As others have mentioned, your PHP code is currently using MCRYPT_RIJNDAEL_256 whereas, as documented under AES_ENCRYPT() : 正如其他人提到的那样,您的PHP代码当前正在使用MCRYPT_RIJNDAEL_256而如AES_ENCRYPT()

    Encoding with a 128-bit key length is used, but you can extend it up to 256 bits by modifying the source. 使用128位密钥长度的编码,但是您可以通过修改源将其扩展到256位。 We chose 128 bits because it is much faster and it is secure enough for most purposes. 我们选择128位是因为它速度更快,并且对于大多数用途来说足够安全。

  2. As others have mentioned, you are applying base64_encode() to convert PHP's binary result to text, whereas the MySQL result appears merely to be a hexadecimal representation of its binary result. 正如其他人提到的,您正在应用base64_encode()将PHP的二进制结果转换为文本,而MySQL结果似乎只是其二进制结果的十六进制表示形式。 You can either use TO_BASE64() in MySQL since v5.6.1 or else bin2hex() in PHP. 从v5.6.1开始,您可以在MySQL中使用TO_BASE64() ,也可以在PHP中使用bin2hex()

  3. As documented under mcrypt_encrypt() : 如在mcrypt_encrypt()mcrypt_encrypt()

    If the size of the data is not n * blocksize, the data will be padded with ' \\0 '. 如果数据的大小不是n *块大小,则将用' \\ 0 '填充数据。

    Whereas MySQL uses PKCS7 padding . 而MySQL使用PKCS7填充

Therefore, to obtain the same results in PHP as you currently show for MySQL: 因此,要在PHP中获得与当前对MySQL相同的结果:

<?php

class MySQL_Function {
  const PKCS7 = 1;

  private static function pad($string, $mode, $blocksize = 16) {
    $len = $blocksize - (strlen($string) % $blocksize);
    switch ($mode) {
      case self::PKCS7:
        $padding = str_repeat(chr($len), $len); break;

      default:
        throw new Exception();
    }
    return $string.$padding;
  }

  public static function AES_ENCRYPT($str, $key_str) {
    return mcrypt_encrypt(
      MCRYPT_RIJNDAEL_128,
      $key_str, self::pad($str, self::PKCS7),
      MCRYPT_MODE_ECB
    );
  }
}

echo bin2hex(MySQL_Function::AES_encrypt( "Hello World", "password" ));

?>

mcrypt_encrypt is deprecated, so here's a solution that's capable of falling back on openssl_encrypt instead. 不建议使用mcrypt_encrypt ,因此这里提供的解决方案可以依靠openssl_encrypt Truthfully, I don't know how all of it works. 说实话,我不知道所有的工作原理。 It's kind of a composite of some solutions I found regarding replicating MySQL's AES_ENCRYPT in mcrypt_encrypt , and then replicating mcrypt_encrypt in openssl_encrypt . 这是一种解决方案,一些我发现关于复制MySQL的复合而成的AES_ENCRYPTmcrypt_encrypt ,然后复制mcrypt_encryptopenssl_encrypt The generation of the key from what would otherwise be used as the salt arguments in AES_ENCRYPT , as well as understanding which cypher to use when, is a little beyond me. 从本来可以用作AES_ENCRYPT的salt参数的密钥的生成以及对何时使用哪个密码的理解都超出了我一点。 But I can say these functions have been time-tested to be functionally identical to their MySql counterparts. 但是我可以说这些功能已经过时间测试,与MySql的功能完全相同。

if (!function_exists('mysql_aes_key')) {
    /**
     * @param string $key
     * @return string
     */
    function mysql_aes_key($key)
    {
        $new_key = str_repeat(chr(0), 16);
        for ($i = 0, $len = strlen($key); $i < $len; $i++) {
            $new_key[$i % 16] = $new_key[$i % 16] ^ $key[$i];
        }
        return $new_key;
    }
}

if (!function_exists('aes_encrypt')) {
    /**
     * @param string $val
     * @param string $cypher
     * @param bool $mySqlKey
     * @return string
     * @throws \BadFunctionCallException
     */
    function aes_encrypt($val, $cypher = null, $mySqlKey = true)
    {
        $salt = getenv('SALT') ?: '1234567890abcdefg';
        $key = $mySqlKey ? mysql_aes_key($salt) : $salt;

        if (function_exists('mcrypt_encrypt')) {
            $cypher = (!$cypher || $cypher == strtolower('aes-128-ecb')) ? MCRYPT_RIJNDAEL_128 : $cypher;
            $pad_value = 16 - (strlen($val) % 16);
            $val = str_pad($val, (16 * (floor(strlen($val) / 16) + 1)), chr($pad_value));
            return @mcrypt_encrypt($cypher, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM));
        } elseif (function_exists('openssl_encrypt')) {
            //TODO: Create a more comprehensive map of mcrypt <-> openssl cyphers
            $cypher = (!$cypher || $cypher == MCRYPT_RIJNDAEL_128) ? 'aes-128-ecb' : $cypher;
            return openssl_encrypt($val, $cypher, $key, true);
        }

        throw new \BadFunctionCallException('No encryption function could be found.');
    }
}

if (!function_exists('aes_decrypt')) {
    /**
     * @param string $val
     * @param string $cypher
     * @param bool $mySqlKey
     * @return string
     * @throws \BadFunctionCallException
     */
    function aes_decrypt($val, $cypher = null, $mySqlKey = true)
    {
        $salt = getenv('SALT') ?: '1234567890abcdefg';
        $key = $mySqlKey ? mysql_aes_key($salt) : $salt;

        if (function_exists('mcrypt_decrypt')) {
            $cypher = (!$cypher || $cypher == strtolower('aes-128-ecb')) ? MCRYPT_RIJNDAEL_128 : $cypher;
            $val = @mcrypt_decrypt($cypher, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM));
            return rtrim($val, chr(0)."..".chr(16));
        } elseif (function_exists('openssl_decrypt')) {
            //TODO: Create a more comprehensive map of mcrypt <-> openssl cyphers
            $cypher = (!$cypher || $cypher == MCRYPT_RIJNDAEL_128) ? 'aes-128-ecb' : $cypher;
            return openssl_decrypt($val, $cypher, $key, true);
        }

        throw new \BadFunctionCallException('No decryption function could be found.');
    }
}

So... 所以...

putenv('SALT=1234567890abcdefg');
aes_encrypt('some_value') === SELECT AES_ENCRYPT('some_value', '1234567890abcdefg')
aes_decrypt('some_encrypted_value') === SELECT AES_DECRYPT('some_encrypted_value', '1234567890abcdefg')

I tested these by encrypting a value with the php function, and decrypting it with the MySQL one, and visa-versa. 我用php函数加密了一个值,然后用MySQL解密了一个值,反之亦然,对它们进行了测试。

The MySQL AES_encrypt uses a 128-bit key length - Reference here MySQL AES_encrypt使用128位密钥长度- 此处参考

Whereas your PHP code uses 256-bit key lengths. 而您的PHP代码使用256位密钥长度。

To fix the problem you should be able to uses 'MCRYPT_RIJNDAEL_128' instead of 256. 要解决此问题,您应该可以使用“ MCRYPT_RIJNDAEL_128”而不是256。

The accepted answer works but is a lot of code, Here's the one liner 可接受的答案有效,但是有很多代码,这是一个衬里

function aes_encrypt_str($val,$key){
    return mcrypt_encrypt(MCRYPT_RIJNDAEL_128,$key, $val,MCRYPT_MODE_ECB,mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,MCRYPT_MODE_ECB),MCRYPT_RAND));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM