0

我正在使用 PEAR::Mail 向我们的客户发送大量电子邮件。我希望能够使用不同的 SMTP 帐户发送这些电子邮件(因为不同的邮件类型)。我们有大约 6 到 7 个帐户,未来可能还会更多。他们每个人都有不同的密码,我们希望能够将这些密码存储在数据库中,这样它就不会被硬编码,因此您可以使用管理员面板更轻松地添加它们。

我知道我想使用加密来存储密码,但这里不能选择 imo 散列。我希望能够读取这些密码,而不仅仅是比较哈希值。

我想通过在数据库中存储加密密码来做到这一点,但使用某种算法对其进行加密。这就是我有问题的地方——我对此知之甚少。我附上了我的加密测试代码,但我希望您对我应该如何改进它提出意见:

if (!function_exists('hex2bin')) {

    function hex2bin($data) {
        $len = strlen($data);
        return pack('H' . $len, $data);
    }

}

$key = $_GET['key'];
$text = $_GET['text'];
$encr = $_GET['encr'];

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

if ($text != null) {
    echo bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv));
}

if ($encr != null) {
    echo mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, hex2bin($encr), MCRYPT_MODE_ECB);
}
4

2 回答 2

1

ECB 模式是不安全的,IV 被此模式忽略。您应该真正使用 CBC (MCRYPT_MODE_CBC)。

使用 CBC 时,加密需要 IV,解密需要相同的 IV,因此您需要保留此值(但不要对所有加密/解密使用相同的 IV,生成一个随机值,如您的代码例子是正确的)。IV 不需要安全存储(比加密数据更安全),将 IV 预先添加到加密数据是标准程序。

bin2hex($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv));

解密时,您会剥离 IV 并将其传递给 mcrypt_decrypt。

$cipherTextDecoded = hex2bin($encr);
$iv = substr($cipherTextDecoded, 0, $iv_size);
$cipherText = substr($cipherTextDecoded, $iv_size);
mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $cipherText, MCRYPT_MODE_CBC, $iv);

另请注意,您应该使用二进制密钥。$_GET['key']正在返回一个文本字符串,并且由于您没有对其进行十六进制解码,因此您的密钥空间仅限于所有可能的 256 位字符串,而不是所有 256 位二进制值。

此外,它在 PHP 中有点误导,但 256 inMCRYPT_RIJNDAEL_256指的是块大小,而不是加密强度。如果要使用 256 位加密,只需将 256 位密钥传递给mcrypt函数。如果这是我考虑使用的目标MCRYPT_RIJNDAEL_128,这将使加密文本与 AES-128 兼容。如果您需要解密其他系统中的数据(我不太可能知道),那么找到 AES-128 实现比 Rijindael 256 容易得多。

于 2013-08-29T15:32:56.523 回答
0

我创建了一个类,它完成了 Syon 提到的所有事情。我将其附在此处以供将来参考,如果有人想使用它,请随意。

<?php

if (!function_exists('hex2bin')) {
    function hex2bin($data) {
        $len = strlen($data);
        return pack('H' . $len, $data);
    }
}

/**
 * Encipherer - Class used for encoding and decoding
 *
 * @author kelu
 * @version $Id$
 * 
 */
class Encipherer {

    private $key;
    private $iv_size;

    private $mode =         MCRYPT_MODE_CBC;
    private $algorithm =    MCRYPT_RIJNDAEL_256;
    private $rand =         MCRYPT_RAND;

    /**
     * returns singleton
     *
     * @return Encipherer
     */
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new Encipherer;
        }
        return $inst;
    }

    private function __construct($key = '') {
        $this->iv_size = mcrypt_get_iv_size($this->algorithm, $this->mode);
        $this->key = $this->key = hex2bin($key);
    }

    private function __clone()
    {
        return Encipherer::Instance();
    }

    public function setKey($key) {
        $this->key = $this->key = hex2bin($key);
    }

    public function encrypt($text) {
        $iv = mcrypt_create_iv($this->iv_size, $this->rand);
        return bin2hex($iv . mcrypt_encrypt($this->algorithm, $this->key, $text, $this->mode, $iv));
    }

    public function decrypt($text) {
        $cipherTextDecoded = hex2bin($text);
        $iv = substr($cipherTextDecoded, 0, $this->iv_size);
        $cipherText = substr($cipherTextDecoded, $this->iv_size);
        return mcrypt_decrypt($this->algorithm, $this->key, $cipherText, $this->mode, $iv);
    }
}

?>

示例用法:

<?
$enc = Encipherer::Instance();
$enc->setKey('1234qwerty');
$encrypted = $enc->encrypt('secret message');
$decrypted = $enc->decrypt($encrypted);
?>
于 2013-08-30T12:02:29.713 回答