這個章節來講講另外一種毛 ,關於填充模式(Padding)
前面加密章節有提到,加密是透過 區塊(block) 進行加密,會將明文排列成特定的形狀(如:正方形、長方形等),但並不是每次都可以切割初剛好的區塊,明文不能完全符合形狀,就需要添加字母來填滿形狀,而如果用無意義的字母來填充則更可以阻礙一些密碼分析
我們常用的填充的方式就包括ZeroPadding、PKCS5Padding與PKCS7Padding,就來介紹有哪些填充方式
不填充,如果加密內容不是8字節整數倍加密則會報錯
所有需要填充的地方都以0填充。
範例如下:Block 大小為 8 Byte,需要填充 4 Byte(以十六進位表示)
| DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 00 |
每個填充字節的值是用於填充的字節數,即是說,若需要填充 N 個字節,則每個填充字節值都是 N 。 填充的字節數取決於算法可以處理的最小數據塊的字節數量
01
02 02
03 03 03
04 04 04 04
05 05 05 05 05
etc.
範例如下:Block 大小為 8 Byte,需要填充 4 Byte(以十六進位表示)
| DD DD DD DD DD DD DD DD | DD DD DD DD 04 04 04 04 |
PKCS#5 和PKCS#7運算方式都相同 的唯一區別是PKCS5 只能用來填充 8 Byte (64bit)的Block,除此之外可以混用。
範例如下:Block 大小為 8 Byte,需要填充 4 Byte(以十六進位表示)
| DD DD DD DD DD DD DD DD | DD DD DD DD 04 04 04 04 |
最大的差異式兩個針對 BlockSize 不同
PKCS#5只對於8 Byte(BlockSize=8)進行填充,填充內容為 0x01- 0x08;
但是PKCS#7不僅僅是對 8 Byte填充,其BlockSize範圍是 1-255 Byte。
所以,PKCS#5可以向上轉換為PKCS#7,但是PKCS#7不一定可以轉換到PKCS#5
用PKCS#7填充加密的密文,用PKCS#5解出來是錯誤的
因此很多人說 PKCS#5 = PKCS#7 論調就是錯的,只有運算方式相同,但使用限制就大大的不同
因此,從本質上講,PKCS#5 Padding 是 PKCS#7 子集
嚴格來說,PKCS#5 Padding 不能用於AES 因為 AES 最小的128bit 是 16 Byte。
只有在使用 RC2 / RC5和 DES/3DES 演算法的情況,這些算法 BlockSize=64bits=8bytes 這時考慮使用 PKCS#5 Padding
在 AES 上使用 PKCS#5 ,會硬生將AES 16 Byte 改採用 8 Byte 方式填充,雖然可以運作
但還是極力不建議在 AES上使用 PKCS#5 ,而是使用 PKCS#7
請注意,PKCS#5和PKCS#7都不是用來描述填充機制的標準。填充部分只是所定義功能的一小部分。
PKCS#5 是基於密碼加密標準(Password-based Encryption Standard)RFC 2898
PKCS#7 密碼訊息語法標準(Cryptographic Message Syntax Standard)RFC 2315
詳細可見 PKCS (Public Key Cryptography Standards)
當然還有其他填充模式,有興趣的讀者可以在深入研究
ISO 10126
ISO 97971
填充模式,真的是很容易讓人搞的暈頭轉向的議題,如果 Padding 設定錯誤,是無法解密最容易遇到是跨平台溝通
所以都要確保雙方使用的 Padding 模式都是相同的
像是 JAVA 預設就只有 PKCS#5
, 沒有 PKCS#7,需要另外實作
在 PKCS#5 PKCS#7 真的是眾說紛紜,我也從使用至今看了很多資料,爬過很多文
才有點小小心得,也不敢說絕對正確
以下是我的建議
在 DES/3DES/RC2/RC4使用 PKCS#5 (不過這些演算法嚴格來說都被棄用了)
AES 使用 PKCS#7
下下策就是使用 ZeroBytePadding
https://en.wikipedia.org/wiki/PKCS
https://zh.wikipedia.org/wiki/%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81%E5%AD%A6%E6%A0%87%E5%87%86
https://en.wikipedia.org/wiki/Padding_(cryptography)
RFC2898[https://tools.ietf.org/html/rfc2898]
...... with a 128-bit block size, the padding string consists of 16-(||M|| mod 16) octets each with value 16-(||M|| mod 16).
根據文件說法,PKCS5是有支援到128-bit(16 bytes)的,所以Android AES才能使用PKCS5,且這樣如果block size <= 16 bytes的話就像相容於PKCS7了