GO的DES/3DES加密算法的实现及通信透彻解析

GO的DES/3DES加密算法的实现及通信透彻解析

前位语:

各位老铁万福金安,相信各位之所以找到这篇文章,肯定是因为项目遇到了关于des/des3的相关问题.不要着急,建议耐下性子花上半个小时,理解完本篇文章,你的问题将迎刃而解.

前景提要:

最近因工作需要,接触到des加密算法; 但是因为des加密容易被暴力破解,所以项目中用到的是3des加密算法,也就是des三重加密.

这里还有要提的是, 因为之前的项目是c++服务, 所以这里的情况就是加密方用的c++, 解密方用的是GO;所以这里我们也会讲到des在各个语言的通信.

一、DES介绍

DES(Data Encryption Standard)是对称加密算法, DES三个入口参数: key、data、mode.

key: 加密/解密的密钥,项目中自己设计的一串字符串. 因为des加密为对称加密, 所以加解密用的密钥key是同一个.

data: 加密时为明文数据(源数据). 解密时为密文数据, 需要将其还原.

mode: 工作模式. 是加密算法底层实现的模式, 按64位进行明文分组.这里大致介绍下两种工作模式.

MODE: ECB

  • 概念
    ECB(电子密本方式)就是将8个字节一段, 进行DES加密/解密得到密文/明文. 最后一段不足8个字节, 按照需求补足8个字节计算.之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响.
    这里值得一提的就是, 你加密/解密的数据可能 (总字节长度/8字节), 不能整除, 按8字节分段处理过程中, 会有一段剩余. 这个时候会有填充方式的概念(padding, 包括none,用’\0’填充,pkcs5padding或pkcs7padding), 下面介绍des多语言通信时会再介绍.

  • 特点
    1 简单, 有利于并行计算,误差不会被传送.
    2 不能隐藏明文的模式;在密文中出现明文消息的重复.
    3 可能对明文进行主动攻击;加密消息块相互独立成为被攻击的弱点.
    4 GO的DES默认隐藏了ECB模式,因为认为其不安全. 但是3des三重加密算法下安全性也是可靠的.小编这里就是老项目用c++做的3des的ECB模式加密, 所以用go的3des-ECB解密.

MODE: CBC

  • 概念
    CBC(密文分组链接方式)有向量的概念,它的实现机制使加密的各段数据有了联系.

    • 加密步骤
      1 首先跟ecb方式一样, 按8字节进行数据分组, 最后一段不足的用padding方式补齐补位.
      2 第一组数据与初始化向量异运算/后运算的结果进行DES加密得到第一组密文
      3 第二组数据与第一组密文异运算/后运算进行DES加密,得到第二组密文,以此类推
      4 拼接各组密文,得到密文结果
    • 解密步骤
      解密是加密的逆过程
  • 特点
    1 不容易主动攻击,安全性高于ECB,每个密文块都依赖上一个密文块,所以一个解密有问题就会影响所有密文块.
    2 发送方和接收方除了key密钥之外, 还需要知道初始向量的值.
    3 加密过程是串行的, 相对并行模式ECB较慢.

使用方法

go get -u github.com/forgoer/openssl

DES

密钥key: 必须为8字节(最好是8位英文+字母的组合)
DES-ECB:

openssl.DesECBEncrypt(src, key, openssl.PKCS7_PADDING)
openssl.DesECBDecrypt(src, key, openssl.PKCS7_PADDING)

DES-CBC:

openssl.DesCBCEncrypt(src, key, iv, openssl.PKCS7_PADDING)
openssl.DesCBCDecrypt(src, key, iv, openssl.PKCS7_PADDING)

注:
这里如果多语言进行通信, 需要注意的就是key为8字节, 一致即可, 补齐方式通信双方定义好.

二、3DES加密原理

简介

3DES(Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称. 原理就是对每个数据块进行了三次DES加密算法, 由于计算机能力增强, 原版DES密钥(key)的长度变得容易被暴力破解, 所以3DES通过一种相对简单的办法, 即增加密钥key值的长度(变为24字节)避免类似的攻击.

3DES是DES向AES过渡的加密算法. 具体实现如下:
> 假设: 
==Encry()--代表加密  
Decry()代表解密  
k1,k2,k3代码24字节的密钥分为3段  
src代表明文 
c代表密文==
过程就是这样的:
3DES加密: c = Encryk3(Decryk2(Encryk1(src))   加密(解密(加密))
3DES解密: src = Decryk1(Encryk2(Decryk3(c))   解密(加密(解密))
使用方法
3DES

密钥key: 长度为24字节(最好是24位英文+字母的组合)
3DES-ECB:

openssl.Des3ECBEncrypt(src, key, openssl.PKCS7_PADDING)
openssl.Des3ECBDecrypt(src, key, openssl.PKCS7_PADDING)

3DES-CBC:

openssl.Des3CBCEncrypt(src, key, iv, openssl.PKCS7_PADDING)
openssl.Des3CBCDecrypt(src, key, iv, openssl.PKCS7_PADDING)

注: 这里很多小伙伴会说key不足24字节怎么办, 或者多出24字节怎么办, 这里说下

1.24位密钥,不足24位的右补0x00;
2.加密内容8位补齐,补齐方式为:少1位补一个0x01,少2位补两个0x02,…
3.本身已8位对齐的,后面补八个0x08。

下面是GO的key密钥不足24字节的补齐代码

func ZeroPadding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{0}, padding)
	return append(ciphertext, padtext...)
}

如果超出24字节, 建议直接截取, 如果多语言通信, 建议双方商量好.

注意点:
  • 在CBC模式下, 会有向量的问题也需要注意, 这里建议key值和初始向量用同一个值

  • 需要注意的是,密钥长度必须24byte,否则直接返回错误。关于这一点,PHP中却不是这样的,只要是8byte以上就行;而Java中,要求必须是24byte以上,内部会取前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.
    可是代码中的实现却没有做判断。不过,go tips中修正了这个问题,如果iv不等于block size(des为8),则直接panic。所以,对于加解密,一定要测试,保证iv等于block size,否则可能会panic

三、多语言通信

  • 了解概念
    在多语言进行通信时, 应先了解几个概念:

    • 模式: 是CBC还是ECB, 加/解密及不同之处上面已经提到过
    • key: 密钥, 如果是DES, 密钥长度必须为8字节, 3DES必须为24字节. 不足或超过, 用相同的填充方式填充或切片.
    • iv: 初始向量, 只有在CBC模式才会用到此值, 建议跟key值相同.
    • padding: 填充方式, src原始串在加密解密过程中是分组运算的, 8个字节一组, 所以是总长度/8, 这个时候可能会有一组不足8字节, 这里多语言情况下, 填充方式要一样. 还有数据长度刚好是8的整数倍时, 是否要额外填充
  • 链接
    这里小编找到了大佬写的其他语言和GO语言的版本. 具体代码看这里
    GitHub

  • 这里说明一下,Java中,默认模式是ECB,且没有用”\0″填充的情况,只有NoPadding和PKCS5Padding;而PHP中(mcrypt扩展),默认填充方式是”\0″,而且,当数据长度刚好是block size的整数倍时,默认不会填充”\0″,这样,如果数据刚好是block size的整数倍且结尾字符是”\0″,会有问题。

综上,跨语言加密解密,应该使用PKCS5Padding填充.

上一篇:android -------- DES加密解密算法


下一篇:常见的几种加密算法及python实现