一、前言
在数字信息时代,数据的安全性和隐私保护成为了至关重要的问题。随着信息技术的迅猛发展和互联网的普及,各种网络攻击和数据泄露事件屡见不鲜,给个人和企业都带来了很大的威胁。加密技术作为保护数据安全的重要手段,越来越受到重视。
加密算法是指将敏感信息转化为不可读形式的数学方法,包括对称加密算法和非对称加密算法等。这些算法被广泛应用于各种场景,如在线支付、电子邮件、文件传输等,以确保数据在传输和存储过程中的安全性和完整性。
本文将介绍几种常用的加密算法,理解它们的工作原理、优缺点以及应用场景。希望通过这篇博客,能够为大家提供一些有用的信息,帮助在实际应用中选择合适的加密技术来保护数据安全。
二、常用的加密算法
2.1、对称加密算法
AES(Advanced Encryption Standard)
- 简介:
AES
是一种对称加密算法,广泛应用于各类数据加密场景。 - 密钥长度:
128
位、192
位、256
位。 - 优点:安全性高、性能好,被广泛认为是目前最安全的对称加密算法之一。
- 简介:
DES(Data Encryption Standard)
- 简介:
DES
曾是广泛使用的对称加密算法,但由于密钥长度较短(56
位),现已被认为不够安全。 - 密钥长度:56位。
- 优点:历史悠久,曾经被广泛使用。
- 简介:
3DES(Triple DES)
- 简介:
3DES
是对DES
算法的扩展,通过三次加密提高安全性。 - 密钥长度:
112
位或168
位。 - 优点:比
DES
更安全,但性能较差。
- 简介:
2.2、非对称加密算法
RSA(Rivest-Shamir-Adleman)
- 简介:
RSA
是一种非对称加密算法,广泛应用于数据加密和数字签名。 - 密钥长度:
1024
位、2048
位、4096
位等。 - 优点:安全性高,适用于加密少量数据和密钥交换。
- 简介:
ECC(Elliptic Curve Cryptography)
- 简介:
ECC
是一种基于椭圆曲线数学的非对称加密算法,提供相同安全级别的情况下,密钥长度更短。 - 密钥长度:
160
位、224
位、256
位等。 - 优点:高效且安全,适用于资源受限的环境。
- 简介:
2.3、哈希算法
SHA-256(Secure Hash Algorithm 256-bit)
- 简介:
SHA-256
是一种广泛使用的哈希算法,生成256
位的哈希值。 - 优点:安全性高,广泛应用于数字签名和区块链技术。
- 简介:
MD5(Message Digest Algorithm 5)
- 简介:
MD5
是一种常用的哈希算法,生成128
位的哈希值。 - 优点:计算速度快,但已被证明存在安全漏洞,不推荐用于安全性要求高的场景。
- 简介:
SHA-1(Secure Hash Algorithm 1)
- 简介:
SHA-1
生成160
位的哈希值,曾经广泛使用,但已被认为不够安全。 - 优点:曾经广泛使用,但现在被认为不安全。
- 简介:
加密哈希算法
- HMAC(Hash-based Message Authentication Code)
- 简介:
HMAC
是一种基于哈希函数和密钥的消息认证码,用于验证消息的完整性和真实性。 - 优点:结合了哈希算法和密钥,提供了较高的安全性。
- 简介:
三、对称加密算法 - AES
AES
(Advanced Encryption Standard
,高级加密标准)是一种对称加密算法,用于加密和解密数据。它由美国国家标准与技术研究院(NIST
)于2001
年发布,取代了之前的DES(Data Encryption Standard)
算法,成为新的加密标准。AES
广泛应用于各种安全通信和数据保护场景,包括网络通信、文件加密、硬盘加密等。
主要特点:
- 对称加密:
AES
是一种对称加密算法,这意味着加密和解密使用相同的密钥。 - 分组加密:
AES
是一种分组加密算法,处理固定长度的数据块(128位
,即16字节
)。 - 多种密钥长度:
AES
支持128位
、192位
和256位
的密钥长度,提供不同级别的安全性。 - 高效性:
AES
设计高效,适合在硬件和软件中实现,具有较高的加密和解密速度。
粗略加密流程:
放大看AES里面的加密过程:
3.1、Initial round
初始轮AddRoundKey
操作是AES
加密的第一步,AddRoundKey
主要的工作就是把矩阵中的每一个字节都与该次回合密钥(round key
)做XOR
运算;AddRoundKey
用的密钥依赖密钥扩展
3.2、字节代换(SubBytes)
字节代换(SubBytes
)通过使用一个固定的S-Box
(Substitution box
)对状态矩阵中的每个字节进行替换,从而引入非线性变换,增加加密的复杂性和安全性。
S-Box
通常是固定的(例如DES
和AES
加密算法), 也有一些加密算法的S-Box
是基于密钥动态生成的(例如Blowfish
和双鱼算法
加密算法)。
3.3、⾏移位(ShiftRows)
3.4、列混合(MixColumn)
MixColumns
操作的主要作用是将状态矩阵中的每一列视为一个多项式,并在有限域GF(2^8)
上与一个固定的多项式矩阵相乘。这一步骤通过混合列内的字节,增加了数据的扩散性,使得单个字节的变化能够影响整个数据块。
举例:
c‘0 = 02*d4 ⊕ 03*bf ⊕ 01*5d ⊕ 01*30
这里乘法不是普通意义上的乘法,而是有限域 GF(2^8) 上的乘法。在有限域GF(2^8)
上,乘法是通过以下步骤进行的:
- 左移操作:将数值左移一位,相当于乘以
2
。 - 模约减:如果左移操作导致数值超过一个字节(即结果大于
0xFF
),则需要模约减(模多项式为0x11B
)。模约减是通过按位异或0x11B
来实现的。
详细计算过程:
左移操作:
0xd4 = 11010100 (二进制) 0xd4 << 1 = 110101000 (二进制) = 0x1A8 (十六进制)
模约减:
0x1A8 = 110101000 (二进制) 0x11B = 100011011 (二进制) 0x1A8 XOR 0x11B = 110101000 XOR 100011011 = 010110101 (二进制) = 0xB5 (十六进制)
3.5、密钥扩展(Key Expansion)
AES128
、AES192
、AES256
,分别会使用AddRoundKey
加密11
、13
、15
轮,每轮需要用16
字节的密钥,所以AES128
、AES192
、AES256
分别需要11*16=176
、13*16=208
、15*16=240
字节的密钥。
拿AES128
举例,第一轮AddRoundKey
的16Byte
的密钥,全部来自用户的输入(密钥长度是128bit
),假设需要用用到的所有密钥是一个长度为44
的Word
(一个Word
大小4
个字节)数组 W[i]
,i
的范围是0~43
。后面每一轮用到的密钥计算方式如下:
- 如果
i
不是4
的倍数(即i%4 != 0
)则计算方式:W[i] = W[i-4] ⨁ W[i-1]
- 如果
i
是4
的倍数(即i%4 == 0
),则:W[i]=W[i-4]⨁T(W[i-1])
- 函数
T
由3
部分组成:字循环、字节代换和轮常量异或。 - RotWord:对字进行循环左移一个字节。
- SubWord:对字的每个字节应用
S盒
(Substitution box
)变换。 - Rcon:轮常量(
Round Constant
),是一个特定的常量数组。
- 函数
3.6、加密模式
ECB(Electronic Codebook)
- 工作原理:每个数据块独立加密。
- 优点:实现简单,适合加密少量数据。
- 缺点:相同的明文块加密后会产生相同的密文块,容易被攻击者利用模式识别攻击。
- 应用场景:由于安全性较差,通常不推荐在实际应用中使用。
CBC(Cipher Block Chaining)
- 工作原理:每个明文块在加密前先与前一个密文块进行
XOR
操作,第一个块与初始化向量(IV
)进行XOR
。 - 优点:相同的明文块不会产生相同的密文块,增强了安全性。
- 缺点:加密是串行的,不能并行处理;解密可以并行处理。
- 应用场景:常用于文件加密和数据传输。
加密过程:
解密过程:
CFB(Cipher Feedback)
- 工作原理:将前一个密文块加密后,再与当前明文块进行
XOR
操作生成当前密文块。 - 优点:可以处理
任意长度的数据
,适合流式数据加密。 - 缺点:加密和解密都是串行的,不能并行处理。
- 应用场景:适用于流数据加密,如网络通信。
加密过程:
解密过程:
OFB(Output Feedback)
- 工作原理:将前一个加密输出作为下一个块的输入,与当前明文块进行
XOR
操作生成当前密文块。 - 优点:类似于流密码,可以处理任意长度的数据;加密和解密可以并行处理。
- 缺点:对
IV
非常敏感,IV
的重复会导致安全问题。 - 应用场景:适用于流数据加密和同步数据加密。
加密过程:
解密过程:
CTR(Counter)
- 工作原理:使用一个计数器值加密,与明文块进行
XOR
操作生成密文块。计数器值通常是一个不断增加的数值。 - 优点:可以并行处理加密和解密操作,效率高;可以随机访问加密数据。
- 缺点:对计数器的管理要求严格,计数器值不能重复。
- 应用场景:适用于高性能要求的场景,如磁盘加密、网络数据加密。
加密过程:
解密过程:
GCM(Galois/Counter Mode)
- 加密和认证:
GCM
模式不仅加密数据,还生成一个消息认证码(MAC
),用于验证数据的完整性和真实性。 - 并行处理:
GCM
模式支持并行处理,能够提高加密和解密的效率。 - 计数器模式:
GCM
模式基于计数器模式(CTR
),每个数据块使用一个唯一的计数器值进行加密。 - Galois消息认证码:
GCM
模式使用Galois
域上的乘法运算生成消息认证码(GMAC
),确保数据的完整性和真实性。
工作原理
GCM
模式的工作流程可以分为两个主要部分:加密和认证。
加密过程:
- 初始化向量(IV):选择一个随机的初始化向量(
IV
)。 - 计数器初始化:将
IV
和一个计数器值(通常为1
)结合,生成初始计数器值。 - 计数器加密:对初始计数器值进行
AES
加密,生成一个密钥流。 - 块加密:将密钥流与明文块进行
XOR
操作,生成密文块。 - 计数器递增:每加密一个块,计数器递增
1
。
认证过程:
- 附加数据:
GCM
模式允许附加数据(AAD
),这些数据不被加密,但需要认证。 - 生成认证标签:使用
Galois
域上的乘法运算,结合密文块和附加数据,生成一个消息认证码(MAC
)。 - 附加认证标签:将生成的认证标签附加到密文后,形成最终的加密输出。
解密过程:
- 计数器初始化:与加密过程相同,使用
IV
和初始计数器值。 - 计数器加密:对初始计数器值进行
AES
加密,生成密钥流。 - 块解密:将密钥流与密文块进行
XOR
操作,恢复明文块。 - 计数器递增:每解密一个块,计数器递增
1
。 - 验证认证标签:使用
Galois
域上的乘法运算,结合密文块和附加数据,验证消息认证码(MAC
)。
加密过程:
解密过程:
3.7、填充模式
在使用AES(Advanced Encryption Standard)
加密算法时,加密的数据块大小必须是固定的128
位(16
字节)。然而,实际应用中待加密的数据长度通常不是16
字节的整数倍,因此需要填充(Padding
)机制来确保数据块的长度符合要求。
PKCS#7 填充
PKCS#7
是最常见的填充方式之一,广泛应用于各种加密标准中。
- 填充方法:在数据的末尾添加
N
个字节,每个字节的值都是N
,其中N
是需要填充的字节数。 - 示例:
- 如果数据长度为
14
字节,需要填充2
字节,填充值为0x02
。 - 原始数据:
[0x01, 0x02, ..., 0x0E]
- 填充后数据:
[0x01, 0x02, ..., 0x0E, 0x02, 0x02]
- 如果数据长度为
ANSI X.923 填充
ANSI X.923
填充方式在数据末尾添加零字节,最后一个字节是填充的字节数。
- 填充方法:在数据的末尾添加
N-1
个零字节,最后一个字节的值是N
,其中N
是需要填充的字节数。 - 示例:
- 如果数据长度为
14
字节,需要填充2
字节。 - 原始数据:
[0x01, 0x02, ..., 0x0E]
- 填充后数据:
[0x01, 0x02, ..., 0x0E, 0x00, 0x02]
- 如果数据长度为
ISO/IEC 7816-4 填充
ISO/IEC 7816-4
填充方式在数据末尾添加一个0x80
字节,然后添加零字节,直到数据块长度为16字节。
- 填充方法:在数据的末尾添加一个
0x80
字节,然后添加零字节,直到数据块长度为16字节。 - 示例:
- 如果数据长度为14字节,需要填充2字节。
- 原始数据:
[0x01, 0x02, ..., 0x0E]
- 填充后数据:
[0x01, 0x02, ..., 0x0E, 0x80, 0x00]
Zero Padding(零填充)
Zero Padding
在数据末尾添加零字节,直到数据块长度为16
字节。
- 填充方法:在数据的末尾添加零字节,直到数据块长度为
16
字节。 - 示例:
- 如果数据长度为
14
字节,需要填充2
字节。 - 原始数据:
[0x01, 0x02, ..., 0x0E]
- 填充后数据:
[0x01, 0x02, ..., 0x0E, 0x00, 0x00]
- 如果数据长度为
- 注意:这种填充方式在解密时可能存在歧义,因为无法区分原始数据末尾的零字节和填充的零字节。
四、非对称加密算法 - RSA
RSA(Rivest-Shamir-Adleman)
是一种广泛使用的非对称加密算法,由Ron Rivest
、Adi Shamir
和Leonard Adleman
在1977
年共同设计。RSA
算法基于大整数分解的数学难题,其安全性依赖于大数分解的计算复杂性。RSA
算法用于数据加密和数字签名,广泛应用于网络安全、电子商务和数字证书等领域。
4.1、基础知识
质数:是指在⼤于1
的⾃然数中,除了1
和它本身以外不再有其他因数的⾃然数。
互质:是公约数只有1
的两个整数,叫做互质整数。
欧拉函数:
- 欧拉函数(
Euler's Totient Function
),通常记作φ(n)
,是数论中的一个重要函数。对于一个正整数n
,φ(n)
表示小于n
且与n
互质的正整数的个数。这里,两个数互质的意思是它们的最大公约数(GCD
)为1
。 - 对于两个互质数
m
和n
,如果m
和n
互质,则欧拉函数满足乘法性质:φ(mn) = φ(m) * φ(n)
φ(6)
在1,2,3,4,5,6
中只有1
和5
与6
是互质
的,所以φ(6) = 2
φ(7)
因为7
是质数,只能被自己和1
整除,所以φ(7) = 6
同余符号:(≡
)是数学中的同余符号,表示两个数在模运算下是同余的。具体来说,对于整数a
、b
和正整数n
,如果a
和b
除以n
的余数相同,则称a
和b
在模n
下是同余的,记作:a ≡ b (mod n)
也等同于 a - b = kn
,k
是一个整数。举例:
17 ≡ 5 (mod 12)
23 ≡ 2 (mod 7)
同余的性质:
- 自反性:对于任意整数
a
和正整数n
,有a ≡ a (mod n)
。 - 对称性:如果
a ≡ b (mod n)
,则b ≡ a (mod n)
。 - 传递性:如果
a ≡ b (mod n)
且b ≡ c (mod n)
,则a ≡ c (mod n)
。 - 加法:如果
a ≡ b (mod n)
且c ≡ d (mod n)
,则a+c ≡ b+d (mod n)
。 - 减法:如果
a ≡ b (mod n)
且c ≡ d (mod n)
,则a-c ≡ b-d (mod n)
。 - 乘法:如果
a ≡ b (mod n)
且b ≡ c (mod n)
,则a*c ≡ b*d (mod n)
。
模运算
- 加法模运算:
(a+b) mod n = ((a mod n) + (b mod n)) mod n
- 减法模运算:
(a-b) mod n = ((a mod n) - (b mod n) + n) mod n
- 乘法模运算:
(a * b) mod n = ((a mod n) * (b mod n) ) mod n
- 指数模运算:(ab) mod n = ((a mod n)b) mod n
欧拉定理:
等同 aφ(m) - 1 = km
模反元素:
模反元素(Modular Inverse
)是数论中的一个概念,通常用于解决模运算中的方程。对于给定的整数a
和模数m
,模反元素是指一个整数x
,使得: a*x ≡ 1 (mod m)
,等同于 a*x - 1 = k*m
。
模反元素x
存在的条件是a
和m
互质,即最大公约数gcd(a,m)=1
。如果a
和m
不是互质的,则a
在模m
下没有模反元素。
4.2、加解密流程
RSA
算法包括密钥生成、加密和解密三个主要步骤。以下是RSA
算法的详细原理和操作步骤。
步骤 | 说明 | 描述 |
---|---|---|
1 | 选择一对不相等且足够大的质数 | p, q |
2 | 计算 p, q 的乘积 | n = p * q |
3 | 计算 n 的欧拉函数 | φ(n) = (p - 1) * (q - 1) |
4 | 选一个与 φ(n) 互质的整数 e | 1 < e < φ(n) |
5 | 计算出 e 对于 φ(n) 的模反元素 d | e*d ≡ 1 (mod φ(n))=> ed mod φ(n) = 1 |
6 | 公钥 | KU = (e, n) |
7 | 私钥 | KR = (d, n) |
8 | 将明文 M 加密 | Me mod n = C |
9 | 将密⽂ C 解密 | Cd mod n = M |
举例
- 假设 p = 3 、 q = 7 ,n = 21
- φ(n) = (q-1)(p-1) = 12
- 公钥 e 要满足 1 < e < φ(n) ,随机选择 e = 5
- 私钥 d 满足 e*d ≡ 1 (mod φ(n)),所以 d * 5 ≡ 1 (mod 12),根据扩展欧几里得算法算的 d =5
- 所以公钥就是 (e, n) = (5,21)
- 私钥就是 (d, n) = (5,21)
- 假设明文是 10,使用公钥加密 C = C = 105 mod 21 = 19
- 解密过程, M = 195 mod 21 = 2476099 mod 21 = 10
4.3、解密推导过程
已知 Me mod n = C,求 Cd mod n = M 是否成立?
解:
- 先把 Me mod n = C 带入到 Cd mod n = M
- 可以得到(Me mod n)d mod n = M
- 根据模运算的性质,我们可以将其进一步简化
- Med mod n = M
- ed mod φ(n) = 1 , 所以有 ed = 1 + k*φ(n)
- 代入 Med mod n = M
- 得 M1 + k*φ(n) mod n = M
- M * (Mφ(n))k mod n = M
- 根据乘法模运算得 ( (M mod n) * ((Mφ(n))k mod n) ) mod n = M
- M 是一个明文,比如 ASCII 256, 由于 p, q 都是一个很大的质数,所以 n 也是一个远大于 M 的数据。
- 所以只用证明 (Mφ(n))k mod n = 1 就行了
- 根据指数模运算得 (Mφ(n))k mod n = (Mφ(n) mod n )k mod n
- M < p and M < q and n = pq 的话,那 M 就一定跟 n 互质了
- 根据欧拉定理我们知道,M 和 n 互质的话就有: Mφ(n) ≡ 1 (mod n)
- 所以 Mφ(n) mod n = 1
- 所以 (1)k = 1
- 所以 (Mφ(n))k mod n = 1
五、哈希算法
哈希函数(Hash Function
)是一种算法,它将任意长度的输入数据(通常称为消息)转换为固定长度的输出数据(通常称为哈希值或摘要)。哈希函数在计算机科学和密码学中有广泛的应用,主要用于数据完整性验证、数字签名、加密、数据检索等。
哈希函数的特点
- 固定长度输出:无论输入数据的长度是多少,哈希函数都生成固定长度的输出。例如,
SHA-256
总是生成256
位(32
字节)的哈希值。 - 快速计算:哈希函数的计算应该是快速高效的,能够在短时间内处理大量数据。
- 不可逆性:哈希函数应具有单向性,即很难从哈希值反推出原始输入数据。
- 抗碰撞性:不同的输入数据应该生成不同的哈希值,找到两个不同的输入数据具有相同哈希值的可能性应该非常低。
- 雪崩效应:输入数据的微小变化(如改变一个比特)应导致输出哈希值的显著变化。
哈希函数的应用
- 数据完整性验证:哈希函数用于验证数据在传输或存储过程中是否被篡改。例如,文件下载后可以通过计算哈希值与提供的哈希值进行比较,验证文件的完整性。
- 数字签名:在数字签名中,哈希函数用于生成消息的摘要,签名者对摘要进行签名,接收者可以验证签名的真实性和消息的完整性。
- 密码学:哈希函数在密码学中用于生成密钥、密码存储等。例如,用户密码通常通过哈希函数处理后存储在数据库中,以提高安全性。
- 数据检索:哈希函数用于快速数据检索和查找,如哈希表(
Hash Table
)和哈希集合(Hash Set
)。 - 区块链:在区块链技术中,哈希函数用于生成区块的哈希值,确保区块链的安全性和不可篡改性。
常见的哈希函数
- MD5(Message Digest Algorithm 5):生成
128
位(16
字节)的哈希值,已被证明存在安全漏洞,不推荐用于安全性要求高的场景。 - SHA-1(Secure Hash Algorithm 1):生成
160
位(20
字节)的哈希值,1995
年发布,SHA-1
在许多安全协议中广为使用,包括TLS
、GnuPG
、SSH
、S/MIME
和IPsec
,是MD5
的后继者。但SHA-1
的安全性在2010
年以后已经不被大多数的加密场景所接受。2017
年荷兰密码学研究小组CWI
和Google
正式宣布攻破了SHA-1[1]
。 - SHA-2(Secure Hash Algorithm 2):
2001
年发布,包括SHA-224
、SHA-256
、SHA-384
、SHA-512
、SHA-512/224
、SHA-512/256
。SHA-2
目前没有出现明显的弱点。虽然至今尚未出现对SHA-2
有效的攻击,但它的算法跟SHA-1
基本上仍然相似。 - SHA-3(Secure Hash Algorithm 3):基于
Keccak
算法设计,提供更高的安全性,适用于高安全性需求的应用。2015
年正式发布,由于对MD5
出现成功的破解,以及对SHA-0
和SHA-1
出现理论上破解的方法,NIST
感觉需要一个与之前算法不同的,可替换的加密散列算法,也就是现在的SHA-3
。
5.1、MD5
MD5(Message Digest Algorithm 5)
是一种广泛使用的哈希函数,用于生成数据的128
位(16
字节)哈希值。尽管MD5
已经被证明存在安全漏洞,不再适合用于安全性要求高的场景,但它在数据完整性验证等领域仍然有一定的应用。以下是MD5
算法的工作原理和操作步骤。
- 消息填充
消息填充的目的是使消息的长度满足特定条件,即长度模512
等于448
。这是为了确保消息长度(以位为单位)加上填充后的长度是512
的倍数。
- 添加一个’1’位:在消息末尾添加一个
'1'
位(即0x80
)。 - 填充’0’位:在
'1'
位之后添加足够的'0'
位,使得消息长度模512
等于448
。 - 附加消息长度:在填充后的消息末尾附加消息的原始长度(以位为单位),长度为
64
位。
- 初始化MD缓冲区
MD5
算法使用四个32
位的寄存器(A、B、C、D)
作为缓冲区,并将其初始化为特定的常量:
A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476
- 处理消息块
消息被分成512
位(64
字节)的块,每个块进一步划分为16
个32
位的子块。MD5
算法对每个512
位的消息块进行四轮变换,每轮包括16
次操作。每次操作使用一个非线性函数、一个常量和当前消息块中的一个子块。
四个非线性函数:
F(X, Y, Z) = (X & Y) | (~X & Z)
G(X, Y, Z) = (X & Z) | (Y & ~Z)
H(X, Y, Z) = X ^ Y ^ Z
I(X, Y, Z) = Y ^ (X | ~Z)
每轮变换:
- 第一轮:使用函数
F
和消息块中的子块。 - 第二轮:使用函数
G
和消息块中的子块。 - 第三轮:使用函数
H
和消息块中的子块。 - 第四轮:使用函数
I
和消息块中的子块。
- 第一轮:使用函数
每轮变换包括以下步骤:
- 将当前的缓冲区值(
A、B、C、D
)与非线性函数的结果、消息块中的一个子块和一个常量进行加法运算。 - 将结果进行左循环移位。
- 将移位后的结果加到当前缓冲区值上。
- 输出最终哈希值
所有消息块处理完毕后,缓冲区中的四个寄存器(A、B、C、D
)包含了最终的哈希值。将这四个寄存器按小端序连接起来,得到128
位的哈希值。
以下是MD5算法的详细计算过程:
消息填充:
- 假设原始消息长度为
L
位。 - 在消息末尾添加一个
'1'
位(即0x80
)。 - 添加
k
个'0'
位,使得L + 1 + k ≡ 448 (mod 512)
。 - 在填充后的消息末尾附加消息的原始长度
L
,长度为64
位。
- 假设原始消息长度为
初始化MD缓冲区:
A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476
处理消息块:
- 将消息分成若干个
512
位(64
字节)的块,每个块进一步划分为16
个32
位的子块。 - 对每个消息块,执行四轮变换,每轮包括
16
次操作。
- 将消息分成若干个
四轮变换:
- 第一轮:使用函数
F
和消息块中的子块。 - 第二轮:使用函数
G
和消息块中的子块。 - 第三轮:使用函数
H
和消息块中的子块。 - 第四轮:使用函数
I
和消息块中的子块。
- 第一轮:使用函数
伪代码:
//Note: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating
var int[64] r, k
//r specifies the per-round shift amounts
r[ 0..15]:= {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22}
r[16..31]:= {5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20}
r[32..47]:= {4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23}
r[48..63]:= {6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}
//Use binary integer part of the sines of integers as constants:
for i from 0 to 63
k[i] := floor(abs(sin(i + 1)) × 2^32)
//Initialize variables:
var int h0 := 0x67452301
var int h1 := 0xEFCDAB89
var int h2 := 0x98BADCFE
var int h3 := 0x10325476
//Pre-processing:
append "1" bit to message
append "0" bits until message length in bits ≡ 448 (mod 512)
append bit length of message as 64-bit little-endian integer to message
//Process the message in successive 512-bit chunks:
for each 512-bit chunk of message
break chunk into sixteen 32-bit little-endian words w[i], 0 ≤ i ≤ 15
//Initialize hash value for this chunk:
var int a := h0
var int b := h1
var int c := h2
var int d := h3
//Main loop:
for i from 0 to 63
if 0 ≤ i ≤ 15 then
f := (b and c) or ((not b) and d)
g := i
else if 16 ≤ i ≤ 31
f := (d and b) or ((not d) and c)
g := (5×i + 1) mod 16
else if 32 ≤ i ≤ 47
f := b xor c xor d
g := (3×i + 5) mod 16
else if 48 ≤ i ≤ 63
f := c xor (b or (not d))
g := (7×i) mod 16
temp := d
d := c
c := b
b := leftrotate((a + f + k[i] + w[g]),r[i]) + b
a := temp
Next i
//Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
End ForEach
var int digest := h0 append h1 append h2 append h3 //(expressed as little-endian)
5.2、SHA-256
SHA-256(Secure Hash Algorithm 256-bit)
是SHA-2(Secure Hash Algorithm 2)
家族中的一种哈希函数,广泛应用于密码学、数据完整性验证和数字签名等领域。SHA-256
将任意长度的输入数据转换为固定长度的256
位(32
字节)哈希值。以下是SHA-256
算法的工作原理和具体步骤。
SHA-256 算法原理
SHA-256
通过一系列的位操作、逻辑运算和非线性函数,将输入数据转换为固定长度的哈希值。其主要步骤包括消息填充、初始化哈希值、消息分块处理和输出最终的哈希值。
- 消息填充
消息填充的目的是使消息的长度满足特定条件,即长度模512
等于448
。这是为了确保消息长度(以位为单位)加上填充后的长度是512
的倍数。
- 添加一个’1’位:在消息末尾添加一个
'1'
位(即0x80
)。 - 填充’0’位:在
'1'
位之后添加足够的'0'
位,使得消息长度模512
等于448
。 - 附加消息长度:在填充后的消息末尾附加消息的原始长度(以位为单位),长度为
64
位。
- 初始化哈希值
SHA-256
算法使用8
个32
位的寄存器作为初始哈希值,这些寄存器被初始化为特定的常量:
H0 = 0x6a09e667
H1 = 0xbb67ae85
H2 = 0x3c6ef372
H3 = 0xa54ff53a
H4 = 0x510e527f
H5 = 0x9b05688c
H6 = 0x1f83d9ab
H7 = 0x5be0cd19
- 处理消息块
消息被分成512
位(64
字节)的块,每个块进一步划分为16
个32
位的子块。SHA-256
算法对每个512
位的消息块进行64
轮变换,每轮使用一个非线性函数、一个常量和当前消息块中的一个子块。
- 消息扩展:将
16
个32
位的子块扩展为64
个32
位的字。 - 循环变换:对每个消息块执行
64
轮变换,每轮使用一个非线性函数、一个常量和当前消息块中的一个字。
每一轮都把256
位缓冲区的值abcdefgh
作为输入,并更新缓冲区的值。每一轮会用到一个32
位的值W
,该值由当前被处理的512
比特的消息分组M
导出,导出算法是消息扩展算法。每一轮还将使用附加的常数K
,其中 0<t≤64
,用来使每轮的运算不同。
- 轮函数
SHA-256
使用以下非线性函数和常量进行变换:
- 选择函数(Ch):
Ch(x, y, z) = (x AND y) XOR (~x AND z)
- 多数函数(Maj):
Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
- Σ0函数:
Σ0(x) = ROTR(2, x) XOR ROTR(13, x) XOR ROTR(22, x)
- Σ1函数:
Σ1(x) = ROTR(6, x) XOR ROTR(11, x) XOR ROTR(25, x)
- σ0函数:
σ0(x) = ROTR(7, x) XOR ROTR(18, x) XOR SHR(3, x)
- σ1函数:
σ1(x) = ROTR(17, x) XOR ROTR(19, x) XOR SHR(10, x)
- 常量表(K)
SHA-256
使用64
个32
位的常量表,这些常量是前64
个素数的立方根的小数部分:
K = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
...
0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c,
0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814,
0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
0xc67178f2
]
- 轮函数计算
每个轮次的计算如下:
for i in range(64):
T1 = H + Σ1(E) + Ch(E, F, G) + K[i] + W[i]
T2 = Σ0(A) + Maj(A, B, C)
H = G
G = F
F = E
E = D + T1
D = C
C = B
B = A
A = T1 + T2
- 更新哈希值
每处理完一个消息块后,更新哈希值:
H0 = H0 + A
H1 = H1 + B
H2 = H2 + C
H3 = H3 + D
H4 = H4 + E
H5 = H5 + F
H6 = H6 + G
H7 = H7 + H
- 输出最终哈希值
所有消息块处理完毕后,连接8
个32
位的寄存器,得到256
位的哈希值。
伪代码:
初始化
(以下是前8個質數2..19平方根小數部分的前32位元):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
初始化每輪用的常數
(前64個質數2..311的立方根小數部分的前32位元):
k[0..63] :=
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
預處理:
訊息後接上一個位元'1'
再接上k個'0',其中k為最小的非負整數,使所得的訊息長度(位元數)同余於448(mod 512)
將預處理前訊息的長度(位元數)寫成64位元大端序整數,接在最尾
將訊息分成若干連續段處理,每段512位元:
將訊息分成512位元的分段
for 每段
將該段再分成十六個32位元的字組,看成大端序的整數w[0..15]
從該十六個字組,計算多四十八個同樣長度的字組,得到總共六十四個32位元字組:
for i from 16 to 63
s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor(w[i-15] rightshift 3)
s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor(w[i-2] rightshift 10)
w[i] := w[i-16] + s0 + w[i-7] + s1
初始化此段的雜湊值:
a := h0
b := h1
c := h2
d := h3
e := h4
f := h5
g := h6
h := h7
主迴圈:
for i from 0 to 63
s0 := (a rightrotate 2) xor (a rightrotate 13) xor(a rightrotate 22)
maj := (a and b) xor (a and c) xor(b and c)
t2 := s0 + maj
s1 := (e rightrotate 6) xor (e rightrotate 11) xor(e rightrotate 25)
ch := (e and f) xor ((not e) and g)
t1 := h + s1 + ch + k[i] + w[i]
h := g
g := f
f := e
e := d + t1
d := c
c := b
b := a
a := t1 + t2
將此段的雜湊值加進總和:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
h5 := h5 + f
h6 := h6 + g
h7 := h7 + h
輸出最總的雜湊值(大端序):
digest = hash = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
六、benchmarks
七、参考文章
Advanced Encryption Standard (AES)
HMAC | MAC | 基于哈希函数的消息认证码| 消息认证码 |HMAC-MD5