日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Go加密解密之DES

發(fā)布時(shí)間:2025/7/25 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go加密解密之DES 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、DES簡(jiǎn)介

DES(Data Encryption Standard)是對(duì)稱加密算法,也就是加密和解密用相同的密鑰。其入口參數(shù)有三個(gè):key、data、mode。key為加密解密使用的密鑰,data為加密解密的數(shù)據(jù),mode為其工作模式。當(dāng)模式為加密模式時(shí),明文按照64位進(jìn)行分組,形成明文組,key用于對(duì)數(shù)據(jù)加密,當(dāng)模式為解密模式時(shí),key用于對(duì)數(shù)據(jù)解密。實(shí)際運(yùn)用中,密鑰只用到了64位中的56位,這樣才具有高的安全性。DES 的常見變體是三重 DES,使用 168 位的密鑰對(duì)資料進(jìn)行三次加密的一種機(jī)制;它通常(但非始終)提供極其強(qiáng)大的安全性。如果三個(gè) 56 位的子元素都相同,則三重 DES 向后兼容 DES。

DES加密,涉及到加密模式和填充方式,所以,和其他語(yǔ)言加解密時(shí),應(yīng)該約定好加密模式和填充方式。(模式定義了Cipher如何應(yīng)用加密算法。改變模式可以容許一個(gè)塊加密程序變?yōu)榱骷用艹绦颉?#xff09;

關(guān)于分組加密:分組密碼每次加密一個(gè)數(shù)據(jù)分組,這個(gè)分組的位數(shù)可以是隨意的,一般選擇64或者128位。另一方面,流加密程序每次可以加密或解密一個(gè)字節(jié)的數(shù)據(jù),這就使它比流加密的應(yīng)用程序更為有用。

在用DES加密解密時(shí),經(jīng)常會(huì)涉及到一個(gè)概念:塊(block,也叫分組),模式(比如cbc),初始向量(iv),填充方式(padding,包括none,用’\0′填充,pkcs5padding或pkcs7padding)。多語(yǔ)言加密解密交互時(shí),需要確定好這些。比如這么定:

采用3DES、CBC模式、pkcs5padding,初始向量用key充當(dāng);另外,對(duì)于zero padding,還得約定好,對(duì)于數(shù)據(jù)長(zhǎng)度剛好是block size的整數(shù)倍時(shí),是否需要額外填充。

二、Go DES加密解密

1、crypto/des包

Go中crypto/des包實(shí)現(xiàn)了 Data Encryption Standard (DES) and the Triple Data Encryption Algorithm (TDEA)。查看該包文檔,發(fā)現(xiàn)相當(dāng)簡(jiǎn)單:
定義了DES塊大小(8bytes),定義了一個(gè)KeySizeError。另外定義了兩個(gè)我們需要特別關(guān)注的函數(shù),即

1func NewCipher(key []byte) (cipher.Block, error)
2func NewTripleDESCipher(key []byte) (cipher.Block, error)

他們都是用來(lái)獲得一個(gè)cipher.Block。從名字可以很容易知道,DES使用NewCipher,3DES使用NewTripleDESCipher。參數(shù)都是密鑰(key)

2、crypto/cipher包

那么,cipher這個(gè)包是干嘛用的呢?它實(shí)現(xiàn)了標(biāo)準(zhǔn)的塊加密模式。我們看一下cipher.Block

1type Block interface {
2????// BlockSize returns the cipher's block size.
3????BlockSize() int
4?
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)
8?
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)
12}

這是一個(gè)接口

對(duì)稱加密,按塊方式,我們經(jīng)常見到CBC、ECB之類的,這些是加密模式。可以參考:DES加密模式詳解 http://linux.bokee.com/6956594.html
Go中定義了一個(gè)接口BlockMode代表各種模式

1type BlockMode interface {
2????// BlockSize returns the mode's block size.
3????BlockSize() int
4?
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
7????// the same memory.
8????CryptBlocks(dst, src []byte)
9}

該包還提供了獲取BlockMode實(shí)例的兩個(gè)方法

1func NewCBCDecrypter(b Block, iv []byte) BlockMode
2func NewCBCEncrypter(b Block, iv []byte) BlockMode

即一個(gè)CBC加密,一個(gè)CBC解密

對(duì)于按流方式加密的,定義了一個(gè)接口:

1type Stream interface {
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)
5}

同樣也提供了獲取實(shí)現(xiàn)該接口的實(shí)例

這里,我們只討論CBC模式

3、加密解密

1)DES
DES加密代碼如下:

1func DesEncrypt(origData, key []byte) ([]byte, error) {
2?????block, err := des.NewCipher(key)
3?????if err != nil {
4??????????return nil, err
5?????}
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方法的說(shuō)明,如下方式初始化crypted也可以
11?????// crypted := origData
12?????blockMode.CryptBlocks(crypted, origData)
13?????return crypted, nil
14}

以上代碼使用DES加密(des.NewCipher),加密模式為CBC(cipher.NewCBCEncrypter(block, key)),填充方式PKCS5Padding,該函數(shù)的代碼如下:

1func 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...)
5}

可見,數(shù)據(jù)長(zhǎng)度剛好是block size的整數(shù)倍時(shí),也進(jìn)行了填充,如果不進(jìn)行填充,unpadding會(huì)搞不定。
另外,為了方便,初始向量直接使用key充當(dāng)了(實(shí)際項(xiàng)目中,最好別這么做)

DES解密代碼如下:

1func DesDecrypt(crypted, key []byte) ([]byte, error) {
2?????block, err := des.NewCipher(key)
3?????if err != nil {
4??????????return nil, err
5?????}
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
13}

可見,解密無(wú)非是調(diào)用cipher.NewCBCDecrypter,最后unpadding,其他跟加密幾乎一樣。相應(yīng)的PKCS5UnPadding:

1func PKCS5UnPadding(origData []byte) []byte {
2????length := len(origData)
3????// 去掉最后一個(gè)字節(jié) unpadding 次
4????unpadding := int(origData[length-1])
5????return origData[:(length - unpadding)]
6}

2)、3DES

加密代碼:

1// 3DES加密
2func TripleDesEncrypt(origData, key []byte) ([]byte, error) {
3?????block, err := des.NewTripleDESCipher(key)
4?????if err != nil {
5??????????return nil, err
6?????}
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
13}

對(duì)比DES,發(fā)現(xiàn)只是換了NewTripleDESCipher。不過(guò),需要注意的是,密鑰長(zhǎng)度必須24byte,否則直接返回錯(cuò)誤。關(guān)于這一點(diǎn),PHP中卻不是這樣的,只要是8byte以上就行;而Java中,要求必須是24byte以上,內(nèi)部會(huì)取前24byte(相當(dāng)于就是24byte)。

另外,初始化向量長(zhǎng)度是8byte(目前各個(gè)語(yǔ)言都是如此,不是8byte會(huì)有問題)。然而,如果你用的Go是1.0.3(或以下),iv可以不等于8byte。其實(shí),在cipher.NewCBCEncrypter方法中有注釋:
The length of iv must be the same as the Block’s block size.
可是代碼中的實(shí)現(xiàn)卻沒有做判斷。不過(guò),go tips中修正了這個(gè)問題,如果iv不等于block size(des為8),則直接panic。所以,對(duì)于加解密,一定要測(cè)試,保證iv等于block size,否則可能會(huì)panic:

1func NewCBCDecrypter(b Block, iv []byte) BlockMode {
2?????if len(iv) != b.BlockSize() {
3??????????panic("cipher.NewCBCDecrypter: IV length must equal block size")
4?????}
5?????return (*cbcDecrypter)(newCBC(b, iv))
6}

此處之所有用panic而不是返回error,個(gè)人猜測(cè),是由于目前發(fā)布的版本,該方法沒有返回error,修改方法簽名會(huì)導(dǎo)致兼容性問題,因此用panic了。

解密代碼:

1// 3DES解密
2func TripleDesDecrypt(crypted, key []byte) ([]byte, error) {
3?????block, err := des.NewTripleDESCipher(key)
4?????if err != nil {
5??????????return nil, err
6?????}
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
14}

三、和其他語(yǔ)言交互:加解密

這次,我寫了PHP、Java的版本,具體代碼放在github上。這里說(shuō)明一下,Java中,默認(rèn)模式是ECB,且沒有用”\0″填充的情況,只有NoPadding和PKCS5Padding;而PHP中(mcrypt擴(kuò)展),默認(rèn)填充方式是”\0″,而且,當(dāng)數(shù)據(jù)長(zhǎng)度剛好是block size的整數(shù)倍時(shí),默認(rèn)不會(huì)填充”\0″,這樣,如果數(shù)據(jù)剛好是block size的整數(shù)倍且結(jié)尾字符是”\0″,會(huì)有問題。

綜上,跨語(yǔ)言加密解密,應(yīng)該使用PKCS5Padding填充。

轉(zhuǎn)載于:https://www.cnblogs.com/mafeng/p/6208296.html

總結(jié)

以上是生活随笔為你收集整理的Go加密解密之DES的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。