【问题标题】:PHP: mcrypt mangles beginning of string to garbagePHP:mcrypt 将字符串开头变成垃圾
【发布时间】:2010-11-22 05:48:40
【问题描述】:

我需要在服务器端进行中到强加密,所以我想我会在 PHP 中使用 mcrypt。如果我使用原始字符串开头下面的函数,解密后会变成二进制垃圾。 (这不是获得附加 additional 垃圾的常见问题,而是我的字符串 altered。)根据文档,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;
}

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

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

【问题讨论】:

    标签: php encryption cryptography mcrypt


    【解决方案1】:

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

    接收者需要知道发送者使用的IV;所以你必须将它与加密数据一起发送并传递给mcrypt_decrypt()

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

    【讨论】:

    • 谢谢,不分享 IV 真的是问题的全部。但我有一个小问题:为什么我能够正确解码前 30 个字节之后的所有内容?密钥只有 32 字节长,因为我不能再使用密钥(PHP 会抛出错误);我的消息的一部分是否不受解密保护?我认为我不需要 mhash,因为我只需要加密来保护数据库中的(关键)临时数据? (10分钟后删除;只有读取权限重要,没有读取权限的操作不重要)
    • 这是因为 CFB 的工作方式——IV 只需要解密第一个块。要解密第二个块,需要第一个块的密文(你正在传输它,以及所有后续块,很好)。这就是为什么 HMAC 是一个好主意的原因 - 攻击者可以随意翻转您消息的 任何 位,并且无法察觉 - 所以如果他能猜到您在说什么(例如,“admin=0”),他可以让你说他想说的任何话(例如,“admin=1”)。
    • 好的,所以 IV 仅对保护第一个块很重要(对于 Rijndael 256 应该是 16 个字节?),因此可以通过将 IV 作为某种盐添加来安全地存储哈希值以进行检查操纵?但是,如果我不需要那种额外的保护,我也可以使用空 IV(或者如果可能的话,根本不使用 IV)并且仍然不会牺牲除第一个块之外的所有块的任何安全性,因为第一个块之后的所有内容块总是可以用我选择的任何随机 IV 解密?
    • 否 - 需要 IV 才能解密第一个块。提供完整性保护的 HMAC 是另一个单独的值。如果您使用固定的 IV,那么您将删除整个消息中的所有白化 - 它不会比 ECB 模式更好!您一开始就走在正确的轨道上 - 为每条消息生成一个带有 mcrypt_create_iv 的新 IV,并将其与加密消息一起发送。
    • 听起来我应该在使用 mcrypt 之前阅读一些关于密码学的知识......我将按照建议实现我的功能,并阅读我使用的算法,也许它会有所帮助。 ;) 到目前为止谢谢!
    【解决方案2】:

    在加密和解密中使用相同的 IV。 IV 不是共享秘密,但必须共享。您可以咨询Wikipedia: IV

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

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

    【讨论】:

    • 啊,是的。 caf 比我快 :|
    猜你喜欢
    • 2013-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    • 2015-01-28
    • 1970-01-01
    • 2021-11-05
    相关资源
    最近更新 更多