生活随笔
收集整理的這篇文章主要介紹了
Go加密解密之DES
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、DES簡介 DES(Data Encryption Standard)是對稱加密算法,也就是加密和解密用相同的密鑰。其入口參數(shù)有三個:key、data、mode。key為加密解密使用的密鑰,data為加密解密的數(shù)據(jù),mode為其工作模式。當模式為加密模式時,明文按照64位進行分組,形成明文組,key用于對數(shù)據(jù)加密,當模式為解密模式時,key用于對數(shù)據(jù)解密。實際運用中,密鑰只用到了64位中的56位,這樣才具有高的安全性。DES 的常見變體是三重 DES,使用 168 位的密鑰對資料進行三次加密的一種機制;它通常(但非始終)提供極其強大的安全性。如果三個 56 位的子元素都相同,則三重 DES 向后兼容 DES。
DES加密,涉及到加密模式和填充方式,所以,和其他語言加解密時,應該約定好加密模式和填充方式。(模式定義了Cipher如何應用加密算法。改變模式可以容許一個塊加密程序變?yōu)榱骷用艹绦颉?#xff09;
關于分組加密:分組密碼每次加密一個數(shù)據(jù)分組,這個分組的位數(shù)可以是隨意的,一般選擇64或者128位。另一方面,流加密程序每次可以加密或解密一個字節(jié)的數(shù)據(jù),這就使它比流加密的應用程序更為有用。
在用DES加密解密時,經(jīng)常會涉及到一個概念:塊(block,也叫分組),模式(比如cbc),初始向量(iv),填充方式(padding,包括none,用’\0′填充,pkcs5padding或pkcs7padding)。多語言加密解密交互時,需要確定好這些。比如這么定:
采用3DES、CBC模式、pkcs5padding,初始向量用key充當;另外,對于zero padding,還得約定好,對于數(shù)據(jù)長度剛好是block size的整數(shù)倍時,是否需要額外填充。
二、Go DES加密解密 1、crypto/des包 Go中crypto/des包實現(xiàn)了 Data Encryption Standard (DES) and the Triple Data Encryption Algorithm (TDEA)。查看該包文檔,發(fā)現(xiàn)相當簡單: 定義了DES塊大小(8bytes),定義了一個KeySizeError。另外定義了兩個我們需要特別關注的函數(shù),即
1 func NewCipher(key []byte) (cipher.Block, error)
2 func NewTripleDESCipher(key []byte) (cipher.Block, error)
他們都是用來獲得一個cipher.Block。從名字可以很容易知道,DES使用NewCipher,3DES使用NewTripleDESCipher。參數(shù)都是密鑰(key)
2、crypto/cipher包 那么,cipher這個包是干嘛用的呢?它實現(xiàn)了標準的塊加密模式。我們看一下cipher.Block
2 ????// BlockSize returns the cipher's block size.
5 ????// Encrypt encrypts the first block in src into dst.
6 ????// Dst and src may point at the same memory.
7 ????Encrypt(dst, src []byte)
9 ????// Decrypt decrypts the first block in src into dst.
10 ????// Dst and src may point at the same memory.
11 ????Decrypt(dst, src []byte)
這是一個接口
對稱加密,按塊方式,我們經(jīng)常見到CBC、ECB之類的,這些是加密模式。可以參考:DES加密模式詳解 http://linux.bokee.com/6956594.html Go中定義了一個接口BlockMode代表各種模式
1 type BlockMode interface {
2 ????// BlockSize returns the mode's block size.
5 ????// CryptBlocks encrypts or decrypts a number of blocks. The length of
6 ????// src must be a multiple of the block size. Dst and src may point to
8 ????CryptBlocks(dst, src []byte)
該包還提供了獲取BlockMode實例的兩個方法
1 func NewCBCDecrypter(b Block, iv []byte) BlockMode
2 func NewCBCEncrypter(b Block, iv []byte) BlockMode
即一個CBC加密,一個CBC解密
對于按流方式加密的,定義了一個接口:
2 ????// XORKeyStream XORs each byte in the given slice with a byte from the
3 ????// cipher's key stream. Dst and src may point to the same memory.
4 ????XORKeyStream(dst, src []byte)
同樣也提供了獲取實現(xiàn)該接口的實例
這里,我們只討論CBC模式
3、加密解密 1)DES DES加密代碼如下:
1 func DesEncrypt(origData, key []byte) ([]byte, error) {
2 ?????block, err := des.NewCipher(key)
4 ??????????return nil, err
6 ?????origData = PKCS5Padding(origData, block.BlockSize())
7 ?????// origData = ZeroPadding(origData, block.BlockSize())
8 ?????blockMode := cipher.NewCBCEncrypter(block, key)
9 ?????crypted := make([]byte, len(origData))
10 ??????// 根據(jù)CryptBlocks方法的說明,如下方式初始化crypted也可以
11 ?????// crypted := origData
12 ?????blockMode.CryptBlocks(crypted, origData)
13 ?????return crypted, nil
以上代碼使用DES加密(des.NewCipher),加密模式為CBC(cipher.NewCBCEncrypter(block, key)),填充方式PKCS5Padding,該函數(shù)的代碼如下:
1 func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
2 ?????padding := blockSize - len(ciphertext)%blockSize
3 ?????padtext := bytes.Repeat([]byte{byte(padding)}, padding)
4 ?????return append(ciphertext, padtext...)
可見,數(shù)據(jù)長度剛好是block size的整數(shù)倍時,也進行了填充,如果不進行填充,unpadding會搞不定。 另外,為了方便,初始向量直接使用key充當了(實際項目中,最好別這么做) 。
DES解密代碼如下:
1 func DesDecrypt(crypted, key []byte) ([]byte, error) {
2 ?????block, err := des.NewCipher(key)
4 ??????????return nil, err
6 ?????blockMode := cipher.NewCBCDecrypter(block, key)
7 ?????origData := make([]byte, len(crypted))
8 ?????// origData := crypted
9 ?????blockMode.CryptBlocks(origData, crypted)
10 ?????origData = PKCS5UnPadding(origData)
11 ?????// origData = ZeroUnPadding(origData)
12 ?????return origData, nil
可見,解密無非是調(diào)用cipher.NewCBCDecrypter,最后unpadding,其他跟加密幾乎一樣。相應的PKCS5UnPadding:
1 func PKCS5UnPadding(origData []byte) []byte {
2 ????length := len(origData)
3 ????// 去掉最后一個字節(jié) unpadding 次
4 ????unpadding := int(origData[length-1])
5 ????return origData[:(length - unpadding)]
2)、3DES
加密代碼:
2 func TripleDesEncrypt(origData, key []byte) ([]byte, error) {
3 ?????block, err := des.NewTripleDESCipher(key)
5 ??????????return nil, err
7 ?????origData = PKCS5Padding(origData, block.BlockSize())
8 ?????// origData = ZeroPadding(origData, block.BlockSize())
9 ?????blockMode := cipher.NewCBCEncrypter(block, key[:8])
10 ?????crypted := make([]byte, len(origData))
11 ?????blockMode.CryptBlocks(crypted, origData)
12 ?????return crypted, nil
對比DES,發(fā)現(xiàn)只是換了NewTripleDESCipher。不過,需要注意的是,密鑰長度必須24byte,否則直接返回錯誤。關于這一點,PHP中卻不是這樣的,只要是8byte以上就行;而Java中,要求必須是24byte以上,內(nèi)部會取前24byte(相當于就是24byte)。
另外,初始化向量長度是8byte(目前各個語言都是如此,不是8byte會有問題)。然而,如果你用的Go是1.0.3(或以下),iv可以不等于8byte。其實,在cipher.NewCBCEncrypter方法中有注釋: The length of iv must be the same as the Block’s block size. 可是代碼中的實現(xiàn)卻沒有做判斷。不過,go tips中修正了這個問題,如果iv不等于block size(des為8),則直接panic。所以,對于加解密,一定要測試,保證iv等于block size,否則可能會panic:
1 func NewCBCDecrypter(b Block, iv []byte) BlockMode {
2 ?????if len(iv) != b.BlockSize() {
3 ??????????panic("cipher.NewCBCDecrypter: IV length must equal block size")
5 ?????return (*cbcDecrypter)(newCBC(b, iv))
此處之所有用panic而不是返回error,個人猜測,是由于目前發(fā)布的版本,該方法沒有返回error,修改方法簽名會導致兼容性問題,因此用panic了。
解密代碼:
2 func TripleDesDecrypt(crypted, key []byte) ([]byte, error) {
3 ?????block, err := des.NewTripleDESCipher(key)
5 ??????????return nil, err
7 ?????blockMode := cipher.NewCBCDecrypter(block, key[:8])
8 ?????origData := make([]byte, len(crypted))
9 ?????// origData := crypted
10 ?????blockMode.CryptBlocks(origData, crypted)
11 ?????origData = PKCS5UnPadding(origData)
12 ?????// origData = ZeroUnPadding(origData)
13 ?????return origData, nil
三、和其他語言交互:加解密 這次,我寫了PHP、Java的版本,具體代碼放在github上。這里說明一下,Java中,默認模式是ECB,且沒有用”\0″填充的情況,只有NoPadding和PKCS5Padding;而PHP中(mcrypt擴展),默認填充方式是”\0″,而且,當數(shù)據(jù)長度剛好是block size的整數(shù)倍時,默認不會填充”\0″,這樣,如果數(shù)據(jù)剛好是block size的整數(shù)倍且結(jié)尾字符是”\0″,會有問題。
綜上,跨語言加密解密,應該使用PKCS5Padding填充。
轉(zhuǎn)載于:https://www.cnblogs.com/mafeng/p/6208296.html
總結(jié)
以上是生活随笔 為你收集整理的Go加密解密之DES 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。