2009-08-24 72 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