0

There is a function in Mysql AES_encrypt.

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

This gives the result: 9438eb79863e7009722fc3f0ad4b7198

But when I use the code in php to do AES_encrypt it gives me a different value.

The PHP code I got from stackoverflow -- PHP AES encrypt / decrypt

<?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=

Is there a method in php or codeigniter so that it returns the same value.? --Thank you.

4

4 回答 4

6

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():

    Encoding with a 128-bit key length is used, but you can extend it up to 256 bits by modifying the source. We chose 128 bits because it is much faster and it is secure enough for most purposes.

  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. You can either use TO_BASE64() in MySQL since v5.6.1 or else bin2hex() in PHP.

  3. As documented under mcrypt_encrypt():

    If the size of the data is not n * blocksize, the data will be padded with '\0'.

    Whereas MySQL uses PKCS7 padding.

Therefore, to obtain the same results in PHP as you currently show for 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" ));

?>
于 2013-06-11T10:05:20.227 回答
4

mcrypt_encrypt is deprecated, so here's a solution that's capable of falling back on openssl_encrypt instead. 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. 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. But I can say these functions have been time-tested to be functionally identical to their MySql counterparts.

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.

于 2018-04-19T17:07:42.473 回答
0

The MySQL AES_encrypt uses a 128-bit key length - Reference here

Whereas your PHP code uses 256-bit key lengths.

To fix the problem you should be able to uses 'MCRYPT_RIJNDAEL_128' instead of 256.

于 2013-06-11T09:06:47.793 回答
-1

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));
}
于 2014-02-21T01:53:51.853 回答