简单的 PHP 加密/解密 (Mcrypt, AES)

Posted

技术标签:

【中文标题】简单的 PHP 加密/解密 (Mcrypt, AES)【英文标题】:Simple PHP Encryption / Decryption (Mcrypt, AES) 【发布时间】:2014-06-28 09:28:09 【问题描述】:

我正在寻找使用 Mcrypt 的 AES 的简单但加密功能强大的 php 实现。

希望将其归结为一对简单的函数,$garble = encrypt($key, $payload)$payload = decrypt($key, $garble)

【问题讨论】:

一旦我整理好这个,我也会对实现兼容的 javascript 实现非常感兴趣。 php/js 有几个实现:2011/08/matching-php-and-js-encryption。另外,aes-php.html PHP/JavaScript 组合听起来像是 TLS(SSL 继任者)/HTTPS 的典型用例。 我有一堂课一直在玩here。我并不是说它很好用(因此在 codereview 上),但可能会给你灵感 @ilovecode,我有一个类似的课程,但它使用'twofish'。我可能会和你的班级做一些比较。一个直接的区别是我使用 GUID 创建一个“站点参考”。此外,uniqid() 也适用于“盐”。 【参考方案1】:

我最近正在学习这个主题,并将此答案发布为社区 wiki 以分享我的知识,有待更正。

Mcrypt Documentation

据我了解,可以使用 Mcrypt 实现 AES,并使用以下常量作为选项:

MCRYPT_RIJNDAEL_128     // as cipher
MCRYPT_MODE_CBC         // as mode
MCRYPT_MODE_DEV_URANDOM // as random source (for IV)

在加密期间,应使用随机的非秘密初始化向量 (IV) 来随机化每个加密(因此相同的加密永远不会产生相同的乱码)。此 IV 应附加到加密结果中,以便以后在解密期间使用。

为了简单的兼容性,结果应该是 Base 64 编码的。

实施:

<?php

define('IV_SIZE', mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));

function encrypt ($key, $payload) 
  $iv = mcrypt_create_iv(IV_SIZE, MCRYPT_DEV_URANDOM);
  $crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $payload, MCRYPT_MODE_CBC, $iv);
  $combo = $iv . $crypt;
  $garble = base64_encode($iv . $crypt);
  return $garble;


function decrypt ($key, $garble) 
  $combo = base64_decode($garble);
  $iv = substr($combo, 0, IV_SIZE);
  $crypt = substr($combo, IV_SIZE, strlen($combo));
  $payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
  return $payload;



//:::::::::::: TESTING ::::::::::::


$key = "secret-key-is-secret";
$payload = "In 1435 the abbey came into conflict with the townspeople of Bamberg and was plundered.";

// ENCRYPTION
$garble = encrypt($key, $payload);

// DECRYPTION
$end_result = decrypt($key, $garble);

// Outputting Results
echo "Encrypted: ", var_dump($garble), "<br/><br/>";
echo "Decrypted: ", var_dump($end_result);

?>

输出如下所示:

Encrypted: string(152) "4dZcfPgS9DRldq+2pzvi7oAth/baXQOrMmt42la06ZkcmdQATG8mfO+t233MyUXSPYyjnmFMLwwHxpYiDmxvkKvRjLc0qPFfuIG1VrVon5EFxXEFqY6dZnApeE2sRKd2iv8m+DiiiykXBZ+LtRMUCw==" 

Decrypted: string(96) "In 1435 the abbey came into conflict with the townspeople of Bamberg and was plundered."

【讨论】:

你能指出这与mcrypt_encrypt中的PHP示例代码有什么不同吗? @owlstead:好吧,我们在这里定义了一对简单的、可重用的函数。在这里,MCRYPT_DEV_URANDOM 用作 IV 源,而不是 MCRYPT_RAND(据称更好)。我仍在尝试确定对密钥进行哈希处理是否重要,甚至可能对它们进行加盐。我也想让它与一个通用的 AES JavaScript 库互操作,虽然我不确定也没有选择一个。 MCRYPT_DEV_URANDOMMCRYPT_RANDOM 好 - 在我看来 - 比MCRYPT_RANDOM 好,所以没关系,尤其是对于 IV。密钥应该是随机生成的(在示例中使用十六进制)。如果要使用密码,则必须添加 PBKDF,例如 bcrypt。密码不是钥匙。没有“通用 AES 库”之类的东西。浏览器中的 JavaScript 加密至少可以说是一项有争议的技术。 请注意,似乎还没有RNCryptor 的 PHP 端口。 @owlstead:我意识到你是对的,我必须将密码加密成密钥。在我找到 bcrypt 的最佳方法之后,我会尽快添加它。来自 PHP 5.5+ 的password_hash() 看起来很棒,但不确定对于早期版本的 PHP 是否有另一种方便的方法来执行此操作。明天可能会更新这个。谢谢!【参考方案2】:

简单易用

$text= 'Hi, i am sentence';
$secret = 'RaNDoM cHars!@#$%%^';

$encrypted = simple_encrypt($text,           $secret);
$decrypted = simple_decrypt($encrypted_text, $secret);

代码:

function simple_encrypt($text_to_encrypt, $salt)     
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,  pack('H*', $salt), $text_to_encrypt, MCRYPT_MODE_CBC, $iv =  mcrypt_create_iv($iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND))));


function simple_decrypt($encrypted, $salt)   
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, pack('H*', $salt), base64_decode($encrypted), MCRYPT_MODE_CBC, $iv = mcrypt_create_iv($iv_size=mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND))); 

【讨论】:

【参考方案3】:

添加清除控制字符 (�) 的功能。

function clean($string) 
return preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $string);

echo "Decrypted: ", clean($end_result);

Sentrapedagang.com

【讨论】:

【参考方案4】:

Mycrypt 类

尝试使用这个类。这里。您需要传递的只是键和字符串。

class MCrypt

    const iv = 'fedcba9876543210';

    /**
 * @param string $str
 * @param bool $isBinary whether to encrypt as binary or not. Default is: false
 * @return string Encrypted data
 */
public static function encrypt($str, $key="0123456789abcdef", $isBinary = false)

    $iv = self::iv;
    $str = $isBinary ? $str : utf8_decode($str);
    $td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
    mcrypt_generic_init($td, $key, $iv);
    $encrypted = mcrypt_generic($td, $str);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $isBinary ? $encrypted : bin2hex($encrypted);


/**
 * @param string $code
 * @param bool $isBinary whether to decrypt as binary or not. Default is: false
 * @return string Decrypted data
 */
public static function decrypt($code, $key="0123456789abcdef", $isBinary = false)

    $code = $isBinary ? $code : self::hex2bin($code);
    $iv = self::iv;
    $td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
    mcrypt_generic_init($td, $key, $iv);
    $decrypted = mdecrypt_generic($td, $code);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $isBinary ? trim($decrypted) : utf8_encode(trim($decrypted));


private static function hex2bin($hexdata)

    $bindata = '';
    for ($i = 0; $i < strlen($hexdata); $i += 2) 
        $bindata .= chr(hexdec(substr($hexdata, $i, 2)));
    
    return $bindata;

   

如何使用

 $var = json_encode(['name'=>['Savatar', 'Flash']]);
 $encrypted = MCrypt::encrypt();
 $decrypted = MCrypt::decrypt($encrypted);

【讨论】:

我没有看到更改加密数据的字符编码的相关性。如果我想加密我的诗歌,比如说,俄语、汉语和希伯来语押韵,会发生什么?我认为您应该将特定于上下文的字符编码处理排除在密码学的范围之外。

以上是关于简单的 PHP 加密/解密 (Mcrypt, AES)的主要内容,如果未能解决你的问题,请参考以下文章

在 Javascript 中使用 Crypto-js 加密,在 PHP 中使用 mcrypt 解密?

使用php mcrypt加密解密

使用php mcrypt加密解密

80分求DES加密解密算法实现的PHP源代码

使用 MCRYPT 在 PHP 中加密/解密...结果不一致

PHP 使用 openssl 解密数据(使用 mcrypt 加密)