因爲採用golang對接,文檔且無說明狀況下,默認採用CBC模式加解密,致使很長時間對接不上。
後經過對方Java Demo代碼查看得知採用ECB加密模式,Java默認DES算法使用DES/ECB/PKCS5Padding工做方式,在GO語言中由於ECB的脆弱性,DES的ECB模式是故意不放出來的,但實際狀況中有時咱們並不須要那麼安全。git
DES 使用一個 56 位的密鑰以及附加的 8 位奇偶校驗位,產生最大 64 位的分組大小。這是一個迭代的分組密碼,使用稱爲 Feistel 的技術,其中將加密的文本塊分紅兩半。使用子密鑰對其中一半應用循環功能,而後將輸出與另外一半進行"異或"運算;接着交換這兩半,這一過程會繼續下去,但最後一個循環不交換。DES 使用 16 個循環,使用異或,置換,代換,移位操做四種基本運算。github
密文分組連接方式,這是golang和.NET封裝的DES算法的默認模式,它比較麻煩,加密步驟以下:golang
- 首先將數據按照8個字節一組進行分組獲得D1D2......Dn(若數據不是8的整數倍,就涉及到數據補位了)
- 第一組數據D1與向量I異或後的結果進行DES加密獲得第一組密文C1(注意:這裏有向量I的說法,ECB模式下沒有使用向量I)
- 第二組數據D2與第一組的加密結果C1異或之後的結果進行DES加密,獲得第二組密文C2
- 以後的數據以此類推,獲得Cn
- 按順序連爲C1C2C3......Cn即爲加密結果。
數據補位通常有NoPadding和PKCS7Padding(JAVA中是PKCS5Padding)填充方式,PKCS7Padding和PKCS5Padding實際只是協議不同,根據相關資料說明:PKCS5Padding明肯定義了加密塊是8字節,PKCS7Padding加密快能夠是1-255之間。可是封裝的DES算法默認都是8字節,因此能夠認爲他們同樣。數據補位實際是在數據不滿8字節的倍數,才補充到8字節的倍數的填充過程。算法
NoPadding填充方式:算法自己不填充,好比.NET的padding提供了有None,Zeros方式,分別爲不填充和填充0的方式。安全
加密字符串爲爲AAA,則補位爲AAA55555;加密字符串爲BBBBBB,則補位爲BBBBBB22;加密字符串爲CCCCCCCC,則補位爲CCCCCCCC88888888。app
電子密本方式,這是JAVA封裝的DES算法的默認模式,就是將數據按照8個字節一段進行DES加密或解密獲得一段8個字節的密文或者明文,最後一段不足8個字節,則補足8個字節(注意:這裏就涉及到數據補位了)進行計算,以後按照順序將計算所得的數據連在一塊兒便可,各段數據之間互不影響。ide
加密反饋模式克服了須要等待8個字節才能加密的缺點,它採用了分組密碼做爲流密碼的密鑰流生成器;編碼
與CFB模式不一樣之處在於, 加密位移寄存器與密文無關了,僅與加密key和加密算法有關;
作法是再也不把密文輸入到加密移位寄存器,而是把輸出的分組密文(Oi)輸入到一位寄存器;加密
func DesECBEncrypt(data, key []byte)([]byte, error) { block, err := des.NewCipher(key) if err != nil { return nil, err } bs := block.BlockSize() data = PKCS5Padding(data, bs) if len(data)%bs != 0 { return nil, errors.New("Need a multiple of the blocksize") } out := make([]byte, len(data)) dst := out for len(data) > 0 { block.Encrypt(dst, data[:bs]) data = data[bs:] dst = dst[bs:] } return out, nil } func DesCBCEncrypt(origData, key []byte) ([]byte, error) { block, err := des.NewCipher(key) if err != nil { return nil, err } origData = PKCS5Padding(origData, block.BlockSize()) // origData = ZeroPadding(origData, block.BlockSize()) blockMode := cipher.NewCBCEncrypter(block, key) crypted := make([]byte, len(origData)) // 根據CryptBlocks方法的說明,以下方式初始化crypted也能夠 // crypted := origData blockMode.CryptBlocks(crypted, origData) return crypted, nil } func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) }
func DesECBDecrypt(data, key []byte)([]byte, error) { block, err := des.NewCipher(key) if err != nil { return nil, err } bs := block.BlockSize() if len(data)%bs != 0 { return nil, errors.New("crypto/cipher: input not full blocks") } out := make([]byte, len(data)) dst := out for len(data) > 0 { block.Decrypt(dst, data[:bs]) data = data[bs:] dst = dst[bs:] } out = PKCS5UnPadding(out) return out, nil } func DesCBCDecrypt(crypted, key []byte) ([]byte, error) { block, err := des.NewCipher(key) if err != nil { return nil, err } blockMode := cipher.NewCBCDecrypter(block, key) //origData := make([]byte, len(crypted)) origData := crypted blockMode.CryptBlocks(origData, crypted) //origData = PKCS5UnPadding(origData) origData = PKCS5UnPadding(origData) return origData, nil } func PKCS5UnPadding(origData []byte) []byte { length := len(origData) unpadding := int(origData[length-1]) return origData[:(length - unpadding)] }