我試圖使用128位AES加密(ECB)加密/解密字符串。我想知道的是我可以如何添加/刪除PKCS7填充。似乎Mcrypt擴展可以處理加密/解密,但填充必須手動添加/刪除。如何從AES加密字符串添加/刪除PKCS7填充?
任何想法?
我試圖使用128位AES加密(ECB)加密/解密字符串。我想知道的是我可以如何添加/刪除PKCS7填充。似乎Mcrypt擴展可以處理加密/解密,但填充必須手動添加/刪除。如何從AES加密字符串添加/刪除PKCS7填充?
任何想法?
讓我們來看看。在RFC 5652(加密消息語法)中描述了PKCS#7。
填充方案本身在6.3. Content-encryption Process部分給出。它基本上是這樣說的:根據需要添加多個字節以填充給定的塊大小(但至少有一個),並且它們中的每一個應具有填充長度作爲值。
因此,看着最後一個解密的字節,我們知道有多少個字節需要去掉。 (也可以檢查它們都具有相同的值。)
我現在可以給你一對PHP函數來做到這一點,但我的PHP有點生疏。所以要麼自己做(然後可以自由地編輯我的答案來添加它),或者查看mcrypt文檔的user-contributed notes - 其中一些是關於填充並提供PKCS#7填充的實現。
那麼,讓我們來看看它first note there詳細:
<?php
function encrypt($str, $key)
{
$block = mcrypt_get_block_size('des', 'ecb');
這得到所使用的算法的塊大小。在你的情況下,你會使用aes
或rijndael_128
而不是des
,我想(我沒有測試它)。 (相反,你可以簡單地採取16
這裏AES,而不是調用函數。)
$pad = $block - (strlen($str) % $block);
此計算填充大小。 strlen($str)
是您的數據長度(以字節爲單位),% $block
給出的餘數爲$block
,即最後一個數據塊的數據字節數。 $block - ...
因此給出了填充該最後一個塊所需的字節數(現在這是一個介於1
和$block
之間的數字)。
$str .= str_repeat(chr($pad), $pad);
str_repeat
產生由相同的字符串的重複,這裏所涉及的character given by$pad
的重複,$pad
倍,即長度$pad
的字符串,填充有$pad
的字符串。 $str .= ...
將此填充字符串追加到原始數據。
return mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);
這裏是加密本身。使用MCRYPT_RIJNDAEL_128
而不是MCRYPT_DES
。
}
現在另一個方向:
function decrypt($str, $key)
{
$str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);
解密。 (你當然會改變算法,如上)。 $ str現在是解密的字符串,包括填充。
$block = mcrypt_get_block_size('des', 'ecb');
這又是塊大小。 (見上文)
$pad = ord($str[($len = strlen($str)) - 1]);
這看起來有點奇怪。最好寫多個步驟:
$len = strlen($str);
$pad = ord($str[$len-1]);
$len
現在填充的字符串的長度,而$str[$len - 1]
是該字符串的最後一個字符。 ord
將其轉換爲數字。因此,$pad
是我們以前用作填充的填充值的數字,這是填充長度。
return substr($str, 0, strlen($str) - $pad);
所以現在我們從字符串切斷最後$pad
字節。 (而不是strlen($str)
我們也可以在這裏寫$len
:substr($str, 0, $len - $pad)
。)。
}
?>
注意,代替使用substr($str, $len - $pad)
,還可以寫substr($str, -$pad)
,如PHP的substr
功能有特殊的處理負的操作數/參數,從字符串末尾數。 (我不知道這是否比首先獲取長度或者手動計算索引效率更高或更低)
如前所述,並且在評論中由rossum指出,而不是簡單地剝離填充像完成在這裏,你應該檢查它是否正確 - 即查看substr($str, $len - $pad)
,並檢查其所有字節是否爲chr($pad)
。這是對腐敗的輕微檢查(儘管如果您使用鏈接模式而不是ECB,並且不是實際MAC的替代品,則此檢查更有效)。
(仍在,告訴你的客戶,他們應該考慮改變比歐洲央行更安全的模式。)
如果你可以給一些代碼做僞代碼或java代碼,那會很棒。我仍然不太明白如何做到這一點,即給定的塊大小是多少,最後解碼的字節是什麼等等。 –
AES的塊大小是128位,即16個字節。當然,您需要一些方法來了解您的消息已經結束......但是,如何簡單地將其中一個註釋中給出的源代碼提供給PHP文檔,會出現什麼問題?我的僞代碼不會好很多。 –
只是在PHP手冊上的代碼沒有很好的記錄,我實際上並沒有明白它在做什麼。如果你可以用一些可能的評論發佈一些Java,那真的很有用。 –
我創建了兩種方法來進行填充和去填充。這些函數使用phpdoc
進行了記錄,並且需要PHP 5.如您將注意到unpad函數包含大量異常處理,爲每個可能的錯誤生成不少於4個不同的消息。
要獲得PHP mcrypt的塊大小,您可以使用mcrypt_get_block_size
,它也定義塊大小爲字節而不是位。
/**
* Right-pads the data string with 1 to n bytes according to PKCS#7,
* where n is the block size.
* The size of the result is x times n, where x is at least 1.
*
* The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
* This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
*
* @param string $plaintext the plaintext encoded as a string containing bytes
* @param integer $blocksize the block size of the cipher in bytes
* @return string the padded plaintext
*/
function pkcs7pad($plaintext, $blocksize)
{
$padsize = $blocksize - (strlen($plaintext) % $blocksize);
return $plaintext . str_repeat(chr($padsize), $padsize);
}
/**
* Validates and unpads the padded plaintext according to PKCS#7.
* The resulting plaintext will be 1 to n bytes smaller depending on the amount of padding,
* where n is the block size.
*
* The user is required to make sure that plaintext and padding oracles do not apply,
* for instance by providing integrity and authenticity to the IV and ciphertext using a HMAC.
*
* Note that errors during uppadding may occur if the integrity of the ciphertext
* is not validated or if the key is incorrect. A wrong key, IV or ciphertext may all
* lead to errors within this method.
*
* The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
* This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
*
* @param string padded the padded plaintext encoded as a string containing bytes
* @param integer $blocksize the block size of the cipher in bytes
* @return string the unpadded plaintext
* @throws Exception if the unpadding failed
*/
function pkcs7unpad($padded, $blocksize)
{
$l = strlen($padded);
if ($l % $blocksize != 0)
{
throw new Exception("Padded plaintext cannot be divided by the block size");
}
$padsize = ord($padded[$l - 1]);
if ($padsize === 0)
{
throw new Exception("Zero padding found instead of PKCS#7 padding");
}
if ($padsize > $blocksize)
{
throw new Exception("Incorrect amount of PKCS#7 padding for blocksize");
}
// check the correctness of the padding bytes by counting the occurance
$padding = substr($padded, -1 * $padsize);
if (substr_count($padding, chr($padsize)) != $padsize)
{
throw new Exception("Invalid PKCS#7 padding encountered");
}
return substr($padded, 0, $l - $padsize);
}
這不以任何方式聖保羅Ebermann的答案無效,它基本上是在代碼& PHPDoc的,而不是作爲描述了同樣的回答。
注意,返回一個填充錯誤,攻擊者可能會導致填充預言攻擊從而徹底打破了CBC(CBC時使用的,而不是歐洲央行或安全認證的密碼)。
只需調用下面的函數,你對數據進行解密
function removePadding($decryptedText){
$strPad = ord($decryptedText[strlen($decryptedText)-1]);
$decryptedText= substr($decryptedText, 0, -$strPad);
return $decryptedText;
}
答案代碼不適用於PHP mcrypt默認使用的空填充。對於PKCS#7/PKCS#5填充,需要檢查填充是否有效。考慮使用錯誤的鍵,$ strPad很可能是錯誤的,可能是一個大於數據長度的值。但是不要返回一個錯誤的填充錯誤,這往往會創建一個填充oracle,而不會執行任何操作。大多數庫支持PKCS#7填充,並將自動添加填充加密和刪除解密填充 - 沒有更多的需要完成。 – zaph
只是一個音符後:如果你可以改變,使用[另一種模式比ECB(它是不安全的)](HTTP://en.wikipedia。組織/維基/ Block_cipher_modes_of_operation)。 –
@Paul不,不能改變,它的客戶系統依賴於什麼。你有什麼可以指導我填充的東西嗎? –
我的意思是AES,修正了它。 –