2

我需要在服务器端进行中到强加密,所以我想我会在 PHP 中使用 mcrypt。如果我使用原始字符串开头下面的函数,解密后会变成二进制垃圾。(这不是附加额外垃圾的常见问题,而是我的字符串被更改。)根据文档, mcrypt_encrypt() 应该填充足够的字符以匹配所选算法的块大小,但我怀疑它不起作用。

但是,如果我手动将它填充到 Rijndael 的 128 位(16 字节)块大小,它也不起作用。我可以让它工作的唯一方法是预先添加一些足够长的字符串以(可能)覆盖垃圾块,并在该字符串和我的数据之间添加一个已知的前缀,如“DATA#”。解密后,该块已部分损坏,但我的前缀和之后的所有数据都已正确解密。

$GLOBALS['encryptionmarker'] = 'DATA#';

function encrypt($plain, $key) {
    /*
    // workaround because beginning of decrypted string is being mangled
    // so we simply prefix with some text plus marker
    $prefix = str_pad('', 128, '#', STR_PAD_RIGHT).$GLOBALS['encryptionmarker'];
    $plain = $prefix.$plain;
    */

    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $plain, MCRYPT_MODE_CFB,
        mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB),
        MCRYPT_DEV_URANDOM));

    return $encrypted;
}

function decrypt($encrypted, $key) {
    $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CFB,
        mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB),
        MCRYPT_DEV_URANDOM));

    /*
    // workaround: remove garbage
    $pos = strpos($decrypted, $GLOBALS['encryptionmarker']);
    $decrypted = trim(substr($decrypted, $pos + strlen($GLOBALS['encryptionmarker'])));
    */

    return $decrypted;
}

我的功能有什么问题?为什么我必须像这样为我的数据添加前缀(我认为这是一种肮脏的解决方法,所以我想修复它)?

存储加密数据不是问题;加密后立即解密而不将其存储到数据库会导致相同的错误。

4

2 回答 2

5

您的问题是您正在接收端生成一个新的、不同的、随机的 IV。如您所见,这不起作用。

接收方需要知道发送方使用的 IV;因此您必须将其与加密数据一起发送并将其传递给mcrypt_decrypt().

请注意,您还必须使用mhash()密钥(与加密密钥不同的密钥)在消息上生成 HMAC,并在接收方检查它。如果您不这样做,中间人可以在您检测不到的情况下轻松修改您的部分消息。

于 2009-08-24T13:36:05.943 回答
2

在加密和解密中使用相同的 IV。IV 不是共享秘密,但必须共享。您可以查阅维基百科:IV

$IV = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB),
      MCRYPT_DEV_URANDOM));

IV 必须转移一次。您可能希望为每个数据包增加 IV 的值。但这可以在双方独立完成。

于 2009-08-24T13:42:08.820 回答