2009-08-24 69 views
2

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

但是,如果我手动将它填充到R​​ijndael的128位(16字节)的块大小,它也不起作用。我可以使这个工作的唯一方法是在字符串和我的数据之间添加一个足够长的字符串(可能)覆盖garbaged块并添加一个已知的前缀,如“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; 
} 

我的功能出了什么问题?为什么我必须将数据加上前缀(我认为这是一个肮脏的解决方法,所以我想修复它)?

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

回答

5

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

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

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

+0

谢谢,没有分享IV真的是完整的问题。但是我有一个小问题:为什么我能够正确解码第一个〜30个字节后的所有内容?由于我不能再使用任何更长的密钥,因此密钥长度只有32字节(PHP会引发错误)。是我的消息不受解密保护的一部分?我想我不需要mhash,因为我只需要加密来保护数据库中的(临界)临时数据? (10分钟后删除;仅读取访问事项,不读取访问操作不) – Energiequant 2009-08-24 15:16:37

+0

这是因为CFB的工作原理 - 只需要解密第一个块。为了解密第二个块,第一个块的密文是需要的(并且你正在传输该块,并且所有后续块都很好)。这就是为什么HMAC是一个好主意 - 攻击者可以随意翻转任何*位的消息,无法察觉 - 所以如果他能猜出你在说什么(例如“admin = 0”),他可以让你说不管他想要什么(例如“admin = 1”)。 – caf 2009-08-24 15:25:38

+0

好的,所以IV只对保护第一块(对于Rijndael 256应该是16字节)很重要,所以人们可以通过添加IV作为某种盐来检查操作,从而安全地存储散列。但是如果我不需要额外的保护,我也可以使用一个空IV(或者根本没有IV),并且不会牺牲除第一个之外的所有块的任何安全性,因为在第一个之后的所有块块总是可以用我选择的随机IV来解密? – Energiequant 2009-08-24 15:50:43

2

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

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

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

+0

啊,是的。 caf比我快:| – tuergeist 2009-08-24 13:42:43