赞
踩
对称密钥算法(Symmetric-key algorithm),又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。
对称加密的特点是,在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。
这一个或一组密钥需要在两个或多个成员之间共享,以便维持专属的通讯联系。
对称加密的优点是速度快,缺点是需要共享密钥,安全性不足。
常见的对称加密算法有 AES、SM4、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。
对称加密算法可分为两大类型:
分组加密: 先将明文切分成一个个固定大小的块,再对每个块进行加密,这种方式被称为分组加密或块加密,有的资料称呼为"分组密码"或"块密码"。
流加密: 将密钥扩展到与密文等长后,用扩展后的密钥与明文按比特位做异或运算。
相比分组加密,流加密具有速度快,消耗少的优点,在网络通信的某些特定场景比较有优势。然而流加密的发展落后于分组加密,其安全性、可扩展性、使用灵活性上,目前认为还是比不上分组加密的,同时某些分组加密算法可以兼具流加密的部分特点。因此对称加密的主流仍然是分组加密。
常见的流加密算法如RC4、ChaCha20等等,它们的安全强度主要取决于扩展后密钥的随机性。
无线网络通信中常常使用RC4; TLS通信协议的最新版本TLS 1.3中,出现了支持ChaCha20的密码套件。
流加密不是本篇的学习重点,这里只简单了解一下,接下来开始学习分组加密,后文提到对称加密时,一般都是特指分组加密。
分组加密的基本流程如下所述:
分组加密有三个重点:
使用分组加密算法对明文进行分组时,有时需要事先对明文字节数组进行填充,使其长度变为块长度的整数倍。这就是分组加密的填充算法,或者说填充规则。
但并不是所有的分组加密算法都需要做明文填充,这取决于分组模式,事实上只有ECB、CBC、PCBC等分组模式需要填充明文。
目前主流的分组加密填充规则是PKCS7Padding。
假定分组加密的块长度为BlockSize, 明文字节数组长度为SrcSize, 则按下面的公式计算padding。padding即是明文需要补位的字节数,也是补位的每个字节的数值,解密时通过最后一个字节的数值判断需要去除多少个填充字节。
padding = BlockSize - SrcSize % BlockSize
举例说明:
假设BlockSize为16,那么:
如果padding为1,就在明文尾部填充1个1;
如果padding为13,就在明文尾部填充13个13;
如果padding为16,就在明文尾部填充16个16;
padding为16代表明文长度正好是16的整数倍,但此时仍然在明文尾部补充16个16,这样在解密时就仍然是通过最后一个字节的数值来判断需要去掉多少个填充的字节,而不需要对明文长度正好是16整数倍的情况做特殊处理。
PKCS5是PKCS7的子集,BlockSize值固定为8,其他规则一样。
目前PKCS5基本不再使用,因为主流的AES与SM4的BlockSize都是16。
由于 X0R 和加法运算很相似,因此一般用 + 和O组合而成的符号®来表示 X0R。
举例: 一枚棋子,翻转两遍,还是那枚棋子
由于两个相同的数进行 XOR 运算的结果一定为 0 , 因此如果将 A ㊉B的结果再与B进行XOR运算,则结果会变回 A。
只要选择一个合适的 B,仅仅使用 XOR 就可以实现一个高强度的密码。
对于密码技术来说,“是否可以预测” 是非常重要的一点。能够产生不可预测的比特序列,对于密码技术的贡献是巨大的。这种不可预测的比特序列就称为随机数。
只要通过暴力破解法对密钥空间进行遍历,无论什么密文总有一天也都能够被破解。然而,一次性密码本( one-time pad )却是一个例外。即便用暴力破解法遍历整个密钥空间,一次性密码本也绝对无法被破译。
一次性密码本是一种非常简单的密码,它的原理是 “将明文与一串随机的比特序列进行
X0R 运算”。如果将硬币的正面设为 0, 反面设为 1,则通过不断掷硬币就能够产生这样一串随机的比特序列。
解密就是加密的反向运算。也就是说,用密文和密钥进行 XOR 运算,就可以得到明文。
模式( mode )。
(1 ) 将输入的数据等分为左右两部分。
(2) 将输人的右侧直接发送到输出的右侧。
(3) 将输入的右侧发送到轮函数。
(4) 轮函数根据右侧数据和子密钥,计算出一串看上去是随机的比特序列。
(5) 将上一步得到的比特序列与左侧数据进行 XOR 运算,并将结果作为加密后的左侧。
但是,这样一来 “右侧” 根本就没有被加密,因此我们需要用不同的子密钥对一轮的处理重复若干次,并在每两轮处理之间将左侧和右侧的数据对调。
Feistel 网络的解密操作只要按照相反的顺序来使用子密钥就可以完成了,而 Feistel 网络本身的结构,在加密和解密时都是完全相同的
三重 DES( triple-DES )是为了增加 DES 的强度,将 DES 重复 3 次所得到的一种密码算法,也称为 TDEA ( Triple Date Encryption Algorithm ),通常缩写为 3DES。
DES 和 AES 都属于分组密码,它们只能加密固定长度的明文。如果需要加密任意长度的明文,就需要对分组密码进行迭代,而分组密码的迭代方法就称为分组密码的 “模式”。
分组之后,接下来分组加密算法要解决的问题就是: 如何将分组后的各个块组织起来,协同实现明文整体的加解密。这个问题就是分组密码工作模式要解决的问题。常见的分组密码工作模式(简称分组模式或加密模式)有:
其中CBC、CTR、GCM是较为常用的分组模式,他们都需要一个随机初始化向量IV。
ECB 模式的全称是 Electronic CodeBook 模式。在 ECB 模式中,将明文分组加密之后的结果将直接成为密文分组
当最后一个明文分组的内容小于分组长度时,需要用一些特定的数据进行填充( padding )。
总结:
当加密第一个明文分组时,由于不存在 “前一个密文分组”,因此需要事先准备一个长度为—个分组的比特序列来代替 “前一个密文分组”,这个比特序列称为初始化向量( InitializationVector ), 通常缩写为 IV。一般来说,每次加密时都会随机产生一个不同的比特序列来作为初始化向量。
确保互联网安全的通信协议之一 SS1/TLS, 就是使用CBC 模式来确保通信的机密性的,如使用CBC 模式三重 DES 的 3DES_EDE_CBC 以及 CBC 模式 256 比特 AES 的 AES_256_CBC 等。
CFB 模式的全称是 Cipher FeedBack 模式( 密文反馈模式 )
在 CFB 模式中,前一个密文分组会被送回到密码算法的输人端。所谓反馈,这里指的就是返回输入端的意思。
在生成第一个密文分组时,由于不存在前一个输出的数据,因此需要使用初始化向量( IV )来代替,这一点和 CBC 模式是相同的
CTR 模式的全称是 CcmnTeR 模式( 计数器模式 )。CTR 模式是一种通过将逐次累加的计数器进行加密来生成密钥流的流密码
AES的BlockSize是16字节(128位),密码支持128/192/256位,其块加密过程:
SM4是我国国家标准的商用密码体系中提供的一种分组密码算法,可以参考国标GB/T 32907-2016。
SM4的BlockSize为16字节128位,密钥长度也是16字节128位,不支持其他长度。SM4的块加密的计算轮次固定为32轮,块加密和块解密使用相同的轮密钥,只是块解密时将轮密钥逆序使用即可。
SM4的块加密过程:
对称加密算法的密钥和IV通常都要求使用一个伪随机数,最好是密码学安全的伪随机数。有时直接用某个PRNG或CSPRNG生成,有时则使用密钥派生算法派生。
import ( ... "crypto/rand" ... ) func GetRandomBytes(len int) ([]byte, error) { if len < 0 { return nil, errors.New("len must be larger than 0") } buffer := make([]byte, len) n, err := rand.Read(buffer) if err != nil { return nil, err } if n != len { return nil, fmt.Errorf("buffer not filled. Requested [%d], got [%d]", len, n) } return buffer, nil }
上面获取伪随机数的语句n, err := rand.Read(buffer)使用的是golang的crypto/rand包,对应的是使用系统熵值的CSPRNG,生成的是一个密码学安全的伪随机数。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。