在最近的項目中,使用nginx+lua來進行安全管理,其中要用到des算法;根據luajit官方的推薦,採用是lua-resty-nettle,但在使用過程當中發現,lua-resty-nettle採用的是0補位,而JDK中實現的是PKCS5Padding;html
繼續尋找新的類庫,因爲團隊對c並不熟悉,考慮到後續的維護方便,優先選擇純lua的實現,這時lua-lockbox進入到咱們的視野;但在使用過程當中發現雖然java和lua代碼採用相同的分塊模式(ECB),相同的補位(java是PKCS5Padding,lua是PKCS7Padding),但lua加密的數據沒法用java解密。報錯信息爲:java
javax.crypto.BadPaddingException: Given final block not properly padded;nginx
錯誤信息很明細,lua補位不正確;直接看源碼pkcs7.lua,發現其補位邏輯以下: local Stream = require("lockbox.util.stream");算法
local PKCS7Padding = function(blockSize,byteCount)安全
local paddingCount = blockSize - ((byteCount -1) % blockSize) + 1;ui
local bytesLeft = paddingCount;加密
local stream = function()lua
if bytesLeft > 0 thenrest
bytesLeft = bytesLeft - 1;code
return paddingCount;
else
return nil;
end
end
return stream;
end
return PKCS7Padding; 那麼PKCS5Padding究竟是如何補位的呢?具體可參考以下資料:
PKCS #7: Cryptographic Message Syntax Standard :An RSA Laboratories Technical Note, Version 1.5. Revised November 1, 1993. PKCS #5: Password-Based Encryption Standard: An RSA Laboratories Technical Note, Version 1.5. Revised November 1, 1993. f
閱讀上面的資料,能夠發現PKCS #7 填充字符串由一個字節序列組成,每一個字節填充該字節序列的長度。 假定塊長度爲 8,數據長度爲 9,則填充用八位字節數等於 7,數據等於 FF FF FF FF FF FF FF FF FF: 數據: FF FF FF FF FF FF FF FF FF PKCS7 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
而根據lua-lockbox的補位邏輯,補位結果爲: lua-lockbox補位:FF FF FF FF FF FF FF FF FF 09 09 09 09 09 09 09 09 09 所以lua-lockbox對於PKCS7Padding的實現有誤,修改代碼爲: local paddingCount = blockSize - byteCount% blockSize; 加密的補位問題解決了,但又發現另一個問題,解密時,lua-lockbox沒有去掉補位數據,從上面的pkcs7.lua代碼能夠看到,lua-lockbox並無實現該邏輯,採用臨時解決方案,修改ecb.lua或cbc.lua,將其解密的finish方法修改成: local data=Stream.toArray(outputQueue.pop) local paddingByte=data[#data]
local realLength=#data-paddingByte--若是有padding,計算去除padding後的長度 local padded=true for i=#data,realLength+1,-1 do if(data[i]~=paddingByte) then padded=false end end print("realLength is "..realLength) local paddedBytes=Array.slice(data,1,realLength) if padded then Array.writeToQueue(outputQueue,paddedBytes) end --paddingStream = padding(blockCipher.blockSize,inputQueue.getHead()); --public.update(paddingStream); return public;
目前的解決辦法比較粗糙,後續有時間進行完善;
PKCS#5/7區別
在PKCS5Padding中,明肯定義Block的大小是8位,而PKCS7Padding定義中,塊的大小是不肯定的,能夠在1-255之間(塊長度超出255的尚待研究),填充值的算法都是同樣的: value=k - (l mod k) ,K=塊大小,l=數據長度,若是l=8, 則須要填充額外的8個byte的8 DES填充方式
DES是對64位數據的加密算法,如數據位數不足64位的倍數,須要填充,補充到64位的倍數。
NoPadding API或算法自己不對數據進行處理,加密數據由加密雙方約定填補算法。例如若對字符串數據進行加解密,能夠補充\0或者空格,而後trim
PKCS5Padding 加密前:數據字節長度對8取餘,餘數爲m,若m>0,則補足8-m個字節,字節數值爲8-m,即差幾個字節就補幾個字節,字節數值即爲補充的字節數,若爲0則補充8個字節的8 解密後:取最後一個字節,值爲m,則從數據尾部刪除m個字節,剩餘數據即爲加密前的原文
SSL3Padding SSL3.0協議定義的填補算法
參考資料
http://www.open-open.com/solution/view/1320502797546 http://www.cnblogs.com/AloneSword/p/3491466.html