搜索
您的当前位置:首页正文

Go 实现 DES 加密和解密

来源:知库网

DES加密算法,为对称加密算法中的一种。是以64比特的明文为一个单位来进行加密,超过64比特的数据,要求按固定的64比特的大小分组,分组有很多模式。DES使用的密钥长度为64比特,但由于每隔7个比特设置一个奇偶校验位,因此其密钥长度实际为56比特。奇偶校验为最简单的错误检测码,即根据一组二进制代码中1的个数是奇数或偶数来检测错误。

加密模式

  • ECB模式 全称Electronic Codebook模式,译为电子密码本模式
  • CBC模式 全称Cipher Block Chaining模式,译为密文分组链接模式
  • CFB模式 全称Cipher FeedBack模式,译为密文反馈模式
  • OFB模式 全称Output Feedback模式,译为输出反馈模式。
  • CTR模式 全称Counter模式,译为计数器模式。

填充方式

当明文长度不为分组长度的整数倍时,需要在最后一个分组中填充一些数据使其凑满一个分组长度。

  • NoPadding
    API或算法本身不对数据进行处理,加密数据由加密双方约定填补算法。例如若对字符串数据进行加解密,可以补充\0或者空格,然后trim
  • PKCS5Padding
    加密前:数据字节长度对8取余,余数为m,若m>0,则补足8-m个字节,字节数值为8-m,即差几个字节就补几个字节,字节数值即为补充的字节数,若为0则补充8个字节的8
    解密后:取最后一个字节,值为m,则从数据尾部删除m个字节,剩余数据即为加密前的原文。
    加密字符串为为AAA,则补位为AAA55555;加密字符串为BBBBBB,则补位为BBBBBB22;加密字符串为CCCCCCCC,则补位为CCCCCCCC88888888。
  • PKCS7Padding
    PKCS7Padding 的填充方式和PKCS5Padding 填充方式一样。只是加密块的字节数不同。PKCS5Padding明确定义了加密块是8字节,PKCS7Padding加密快可以是1-255之间。

以下是go 实现的DES加密和解密代码:

本代码采用CBC加密模式,填充方式采用PKCS5Padding

package main
​
import (
 "crypto/des"
 "bytes"
 "crypto/cipher"
 "fmt"
 "encoding/base64"
)
​
//DES加密方法
func MyDESEncrypt (origData,key []byte){
 //将字节秘钥转换成block快
 block,_ := des.NewCipher(key)
 //对明文先进行补码操作
 origData = PKCS5Padding(origData,block.BlockSize())
 //设置加密方式
 blockMode := cipher.NewCBCEncrypter(block,key)
 //创建明文长度的字节数组
 crypted := make([]byte, len(origData))
 //加密明文,加密后的数据放到数组中
 blockMode.CryptBlocks(crypted,origData)
 //将字节数组转换成字符串
 fmt.Println(base64.StdEncoding.EncodeToString(crypted))
​
}
​
//实现明文的补码
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
 //计算出需要补多少位
 padding := blockSize - len(ciphertext)%blockSize
 //Repeat()函数的功能是把参数一 切片复制 参数二count个,然后合成一个新的字节切片返回
 // 需要补padding位的padding值
 padtext := bytes.Repeat([]byte{byte(padding)}, padding)
 //把补充的内容拼接到明文后面
 return append(ciphertext,padtext...)
}
​
//解密
func MyDESDecrypt(data string, key []byte) {
 //倒叙执行一遍加密方法
 //将字符串转换成字节数组
 crypted,_ := base64.StdEncoding.DecodeString(data)
 //将字节秘钥转换成block快
 block, _ := des.NewCipher(key)
 //设置解密方式
 blockMode := cipher.NewCBCDecrypter(block,key)
 //创建密文大小的数组变量
 origData := make([]byte, len(crypted))
 //解密密文到数组origData中
 blockMode.CryptBlocks(origData,crypted)
 //去补码
 origData = PKCS5UnPadding(origData)
 //打印明文
 fmt.Println(string(origData))
}
​
//去除补码
func PKCS5UnPadding(origData []byte) []byte {
 length := len(origData)
 // 去掉最后一个字节 unpadding 次
 unpadding := int(origData[length-1])
 //解密去补码时需取最后一个字节,值为m,则从数据尾部删除m个字节,剩余数据即为加密前的原文
 return origData[:(length - unpadding)]
}
​
func main () {
​
 //定义明文
 data := []byte("hello world")
​
 //密钥
 key := []byte("12345678")
​
 //加密
 MyDESEncrypt(data,key)
​
 //解密
 MyDESDecrypt("CyqS6B+0nOGkMmaqyup7gQ==",key)
}

其中解密只需把加密过程倒叙走一遍。

屏幕快照 2018-05-16 下午11.13.08.png

关于明文补码和去补码操作:

加密前明文补码规则 (cipher.NewCBCEncrypter 调用前操作):

加密前:数据字节长度对8取余,余数为m,若m>0,则补足8-m个字节,字节数值为8-m,即差几个字节就补几个字节,字节数值即为补充的字节数,若为0则补充8个字节的8

对应的明文补码代码部分:

//实现明文的补码
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
 //计算出需要补多少位
 padding := blockSize - len(ciphertext)%blockSize
 //Repeat()函数的功能是把参数一 切片复制 参数二count个,然后合成一个新的字节切片返回
 // 需要补padding位的padding值
 padtext := bytes.Repeat([]byte{byte(padding)}, padding)
 //把补充的内容拼接到明文后面
 return append(ciphertext,padtext...)
}

解密后去除补码规则(cipher.NewCBCDecrypter调用解密完成后):

解密后:取最后一个字节,值为m,则从数据尾部删除m个字节,剩余数据即为加密前的原文。

对应的去补码代码部分:

//去除补码
func PKCS5UnPadding(origData []byte) []byte {
 length := len(origData)
 // 去掉最后一个字节 unpadding 次
 unpadding := int(origData[length-1])
 //解密去补码时需取最后一个字节,值为m,则从数据尾部删除m个字节,剩余数据即为加密前的原文
 return origData[:(length - unpadding)]
}
Top