Go语言的DES加密(CBC模式, ECB模式) ---- 与java加密互通
问题场景:
业务需要对接接口, 采用DES加密方式加密, 于是google一下go的DES加密方式,
go的DES的默认隐藏了ECB模式, 因为go认为ECB不安全, 所以不建议使用,就隐藏了,
然而接口却需要采用ECB模式(吐槽写文档的人, 并没有写明使用了ECB模式,
这让我耗费了大量的时间来猜测他的加密模式)
ECB
- 概念
ECB(电子密本方式)就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。 - 特点
- 简单,有利于并行计算,误差不会被传送;
- 不能隐藏明文的模式;在密文中出现明文消息的重复
- 可能对明文进行主动攻击;加密消息块相互独立成为被攻击的弱点
CBC
- 概念
CBC(密文分组链接方式)有向量的概念, 它的实现机制使加密的各段数据之间有了联系。 - 加密步骤:
- 首先将数据按照8个字节一组进行分组得到D1D2......Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
- 第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1(初始化向量I为全零)
- 第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2
- 之后的数据以此类推,得到Cn
- 按顺序连为C1C2C3......Cn即为加密结果。
- 解密是加密的逆过程:
- 首先将数据按照8个字节一组进行分组得到C1C2C3......Cn
- 将第一组数据进行解密后与初始化向量I进行异或得到第一组明文D1(注意:一定是先解密再异或)
- 将第二组数据C2进行解密后与第一组密文数据进行异或得到第二组数据D2
- 之后依此类推,得到Dn
- 按顺序连为D1D2D3......Dn即为解密结果。
- 特点
- 不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
每个密文块依赖于所有的信息明文消息中一个改变会影响所有密文块 - 发送方和接收方都需要知道初始化向量
- 加密过程是串行的,无法被并行化(在解密时,从两个邻接的密文块中即可得到一个平文块。因此,解密过程可以被并行化。
代码
//ECB加密
func EncryptDES_ECB(src, key string) string {
data := []byte(src)
keyByte := []byte(key)
block, err := des.NewCipher(keyByte)
if err != nil {
panic(err)
}
bs := block.BlockSize()
//对明文数据进行补码
data = PKCS5Padding(data, bs)
if len(data)%bs != 0 {
panic("Need a multiple of the blocksize")
}
out := make([]byte, len(data))
dst := out
for len(data) > 0 {
//对明文按照blocksize进行分块加密
//必要时可以使用go关键字进行并行加密
block.Encrypt(dst, data[:bs])
data = data[bs:]
dst = dst[bs:]
}
return fmt.Sprintf("%X", out)
}
//ECB解密
func DecryptDES_ECB(src, key string) string {
data, err := hex.DecodeString(src)
if err != nil {
panic(err)
}
keyByte := []byte(key)
block, err := des.NewCipher(keyByte)
if err != nil {
panic(err)
}
bs := block.BlockSize()
if len(data)%bs != 0 {
panic("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 string(out)
}
//CBC加密
func EncryptDES_CBC(src, key string) string {
data := []byte(src)
keyByte := []byte(key)
block, err := des.NewCipher(keyByte )
if err != nil {
panic(err)
}
data = PKCS5Padding(data , block.BlockSize())
//获取CBC加密模式
iv := keyByte //用密钥作为向量(不建议这样使用)
mode := cipher.NewCBCEncrypter(block, iv)
out := make([]byte, len(data))
mode .CryptBlocks(out, data)
return fmt.Sprintf("%X", out)
}
//CBC解密
func DecryptDES_CBC(src, key string) string {
keyByte := []byte(key)
data, err := hex.DecodeString(src)
if err != nil {
panic(err)
}
block, err := des.NewCipher(keyByte)
if err != nil {
panic(err)
}
iv := keyByte //用密钥作为向量(不建议这样使用)
mode := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(data))
mode.CryptBlocks(plaintext, data)
plaintext = PKCS5UnPadding(plaintext)
return string(plaintext)
}
//明文补码算法
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
//明文减码算法
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}