不能在php mcrypt中使用常量IV键和生成的ENCRYPT_KEY

时间:2014-06-22 10:31:56

标签: php mcrypt

我知道常量IV键是错误的,必须生成随机密钥。然而,我需要这个,因为我被指派这样做。我已经在网上搜索了如何处理这个但是失败了。我的代码如下,任何建议都会得到很大的赞赏。

这里是整个代码和函数

define('ENCRYPTION_KEY', 'ITU2NjNhI0tOc2FmZExOTQ==');    //Encryption KEY

 // Encrypt Function
 function mc_encrypt($encrypt, $key)
 {
    //Do Not Put ENCRYPTION_KEY here
    $encrypt = serialize($encrypt);
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
    //$iv = ('AAAAAAAAAAAAAAAAAAAAAA==');

    $key = pack('H*', $key);
    $mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
    $passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv);
    $encoded = base64_encode($passcrypt).'|'.base64_encode($iv);

    return $encoded; //return base64_encode($encoded).':'.$iv;
 }

// Decrypt Function
function mc_decrypt($decrypt, $key)
{
    $decrypt = explode('|', $decrypt);
    $decoded = base64_decode($decrypt[0]);
    $iv = base64_decode($decrypt[1]);

if(strlen($iv) !== mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC))
{ 
    return false; 
}

$key = pack('H*', $key);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
$mac = substr($decrypted, -64);
$decrypted = substr($decrypted, 0, -64);
$calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));

if($calcmac !== $mac)
{ 
    return false; 
}

$decrypted = unserialize($decrypted);

return $decrypted;
}

echo '<h1>Sample Encryption</h1>';

$data = 'Patrick';
$encrypted_data = mc_encrypt($data, ENCRYPTION_KEY);
echo '<h2>Example #1: String Data</h2>';
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, ENCRYPTION_KEY) . '</br>';

如果我使用它我会收到错误

警告:pack():在第24行的C:\ xampp \ htdocs \ sample1 \ test.php中输入H:非法的十六进制数字I

当我使用

$iv = ('AAAAAAAAAAAAAAAAAAAAAA==');

而不是这个

$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);

虽然他们都有

define('ENCRYPTION_KEY', 'd0a7e7997b6d5fcd55f4b5c32611b87cd923e88837b63bf2941ef819dc8ca282');    //Encryption KEY

这是错误

Warning: mcrypt_encrypt(): The IV parameter must be as long as the blocksize in C:\xampp\htdocs\sample1\test.php on line 26

1 个答案:

答案 0 :(得分:2)

这是在PHP 5.3.18上运行和测试的代码。 Demonstration at Viper-7

1)它使用所需的base64编码的'AAAAAAAAAAAAAAAAAAAAAA =='作为IV('salt'),当转换回字符串时,它是16字节的二进制零。因为我们需要32个字节,所以我只需将它与自身连接起来就可以得到所需的长度。

2)提供了两个密钥:

1)base64编码:'ITU2NjNhI0tOc2FmZExOTQ ==',这是一个16字节长的“典型”高质量密码字符串。这需要转换为加密函数的十六进制字符串。

2)十六进制文字:'d0a7e7997b'......

请注意:提供的密钥(以十六进制字符串为单位)彼此不相等

这不会影响例程,只需要知道必须使用相同的密钥来加密/解密。

例程:

 // Encrypt Function - $key must be a Hexadecimal String
 function mc_encrypt($encrypt, $key) {
    //Do Not Put ENCRYPTION_KEY here
    $encrypt = serialize($encrypt);

    // $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
    $iv = base64_decode(ENCRYPTION_IV); // convert back to binary string
    $actualIV = $iv . $iv; // As it is 16 bytes of binary characters just double it

    $key = pack('H*', $key); // convert key back to binary string
    $mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
    $passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $actualIV);
    $encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
    return $encoded;
 }

请注意,'$ actualIV'只是获得所需32个字节的“技巧”。但是,如果使用不同的16字节IV,它将起作用。

警告:当使用相同的密钥加密时,使用不同的(随机)IV非常重要,否则相同的消息会加密到相同的密文。为了在例程中使用16字节IV,我很想生成随机IV,并且只使用当前使用的连接到自身的前16个字节。

即。替换此代码:

$iv = base64_decode(ENCRYPTION_IV); // convert back to binary string

with:

$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$iv = substr($iv, 0, 16);

CBC模式和'填充Oracle攻击' 如果你只使用PHP,这看起来好像不是问题。可能存在在不同系统上解密的问题。此链接说明了问题:Cryptography/DES-PHP-Block-Padding-in-mcrypt.html

// Decrypt Function - - $key must be a Hexadecimal String
function mc_decrypt($decrypt, $key) {
    $decrypt = explode('|', $decrypt);
    $decoded = base64_decode($decrypt[0]);
    $iv = base64_decode($decrypt[1]);

    $actualIV = $iv . $iv; // make it long enough and match the original IV used.
    if(strlen($actualIV) !== mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)){ return false; }

    $key = pack('H*', $key);
    $decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $actualIV));
    $mac = substr($decrypted, -64);
    $decrypted = substr($decrypted, 0, -64);
    $calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
    if($calcmac!==$mac) { return false; }
    $decrypted = unserialize($decrypted);
    return $decrypted;
}

请注意,'$ iv'与自身连接以获得所需的32个字节。

定义键:

define('ENCRYPTION_B64KEY', 'ITU2NjNhI0tOc2FmZExOTQ==');    //Encryption KEY
define('ENCRYPTION_IV', 'AAAAAAAAAAAAAAAAAAAAAA==');
define('ENCRYPTION_HEXKEY', 'd0a7e7997b6d5fcd55f4b5c32611b87cd923e88837b63bf2941ef819dc8ca282');    //Encryption KEY

使用两个提供的密钥的示例:

echo '<h1>Sample Encryption</h1>';

$data = 'Patrick';
echo '<h2>Example #1: Using base64 encoded key (ENCRYPTION_B64KEY)</h2>';

$b64HexKey = bin2hex(base64_decode(ENCRYPTION_B64KEY));
$encrypted_data = mc_encrypt($data, $b64HexKey);
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, $b64HexKey) . '</br>';

echo '<h2>Example #2 using Hexadecimal Key (ENCRYPTION_HEXKEY)</h2>';

$hexKey = ENCRYPTION_HEXKEY;
$encrypted_data = mc_encrypt($data, $hexKey);
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, $hexKey) . '</br>';

以上输出:

Sample Encryption

Example #1: Using base64 encoded key (ENCRYPTION_B64KEY)

Data to be Encrypted: Patrick
Encrypted Data: /7qKjoPnNiGveTHo0NnkXfSLFIHE72De1q85QWI/d16j4BzLaqIR7jpap0J2wCdHYgK+IS4Zf1OpZorK9iGnPErkh+owjkoEo/dejHxUaVxOS03+Uqti8i13aGeB6wAU|AAAAAAAAAAAAAAAAAAAAAA==
Decrypted Data: Patrick
Example #2 using Hexadecimal Key (ENCRYPTION_HEXKEY)

Data to be Encrypted: Patrick
Encrypted Data: iAyCpfnOHUeHKHT+BIra2TZbRlLJfXKAO5pRGbmKvLyTOlzr9L6IBRI8ZuDsGVdZym26Qd89hKZxnVPbBSsOktCaztF9akZA8iPa3r0jvgISFldRDdHx8CZyd+GfR9BV|AAAAAAAAAAAAAAAAAAAAAA==
Decrypted Data: Patrick