为了账号安全,请及时绑定邮箱和手机立即绑定

DES--------Golang对称加密之模式问题实战

标签:
Go


1. 背景

近期项目在对接第三方产品,传输过程中涉及到数据加密, 数据加密流程为:

发送数据DES加密

DES加密后的数据进行base64编码

发送,接受数据

接受读取的数据进行base64解码

base64解码完的数据机型DES解密

由于采用golang对接,文档且无说明情况下,默认采用CBC模式加解密,导致很长时间对接不上。

后通过对方Java Demo代码查看得知采用ECB加密模式,Java默认DES算法使用DES/ECB/PKCS5Padding工作方式,在GO语言中因为ECB的脆弱性,DES的ECB模式是故意不放出来的,但实际情况中有时我们并不需要那么安全。

DES介绍

DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位,产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行"异或"运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用 16 个循环,使用异或,置换,代换,移位操作四种基本运算。

DES常见加密模式

CBC(加密分组链接模式)

密文分组链接方式,这是golang和.NET封装的DES算法的默认模式,它比较麻烦,加密步骤如下:

首先将数据按照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的方式。

PKCS7Padding(PKCS5Padding)填充方式:为.NET和JAVA的默认填充方式,对加密数据字节长度对8取余为r,如r大于0,则补8-r个字节,字节为8-r的值;如果r等于0,则补8个字节8。比如:

加密字符串为为AAA,则补位为AAA55555;加密字符串为BBBBBB,则补位为BBBBBB22;加密字符串为CCCCCCCC,则补位为CCCCCCCC88888888。

ECB(电子密码本模式)

电子密本方式,这是JAVA封装的DES算法的默认模式,就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,则补足8个字节(注意:这里就涉及到数据补位了)进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。

CFB(加密反馈模式)

加密反馈模式克服了需要等待8个字节才能加密的缺点,它采用了分组密码作为流密码的密钥流生成器;

OFB(输出反馈模式)

与CFB模式不同之处在于, 加密位移寄存器与密文无关了,仅与加密key和加密算法有关;

做法是不再把密文输入到加密移位寄存器,而是把输出的分组密文(Oi)输入到一位寄存器;

DES加密之golang的CBC和ECB模式代码实现

CBC和ECB模式加密

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...)

}

CBC和ECB模式解密

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)]

}

总结

以需求驱动技术,技术本身没有优略之分,只有业务之分。

©著作权归作者所有:来自51CTO博客作者asd1123509133的原创作品,如需转载,请注明出处,否则将追究法律责任


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消