NOTE
1.4 加密
对称加密、分组模式、非对称加密、RSA 与基础实现。
这是历史学习笔记,可能存在过时或不完整的理解。
1. 加密是什么
2. 加密特性
机密性
3. 加密三要素
3.1. 加密
- 明文
- 密钥
- 加密算法
3.2. 解密
- 密文
- 密钥
- 解密算法:可能跟加密算法不同
4. 加密算法分类
4.1. 对称加密
4.1.1. 是什么
- 通信双方共享同一个密钥
- 优点:加解密效率高
- 缺点:需要安全地分发和保管共享密钥
4.1.2. 凯撒密码

4.1.3. DES
不推荐使用,DES 已不适合现代安全场景。
- 加密

- 解密

- 密钥 长度为8bytes
- 分组 8bytes
4.1.4. 3DES
Triple DES。新系统也不应再优先选择 3DES。
-
加密 中间使用解密的原因是为了兼容以前的DES

-
解密

-
密钥 长度为8bytes,总共3个密钥,所以总长度为24bytes 密钥1和密钥2相同,或者密钥2和密钥3相同,就是DES
-
分组 8bytes
4.1.5. AES
现代系统优先使用 AES,并应配合合适的认证加密模式(如 GCM)或额外的完整性保护。
- 密钥 长度可选,16、24、32
- 分组 16bytes
4.2. 分组模式
DES、3DES、AES都属于分组密码,即每次只能处理特定长度的一块(block)数据的一类加解密 如果要加密的明文比较长,就需要对加密进行迭代
4.2.1. 分组与对称加密的关系

4.2.2. ECB
- 需要分组,分组长度根据算法而定
- 对数据分组之后需要填充
- 加密效率高,但是相同明文块会产生相同密文块,会泄露数据模式,因此不应直接用于一般数据加密
- 可以并行加解密

4.2.3. CBC
- 需要分组,分组长度根据算法而定
- 对数据分组之后需要填充
- 需要提供初始化向量
- 每一个密文都是下一个加密操作的输入
- 不能并行加密,可以并行解密

4.2.4. CFB
- 需要分组,分组长度根据算法而定
- 没有直接对明文分组加密,故不需要填充
- 需要提供初始化向量
- 相对初始化向量加密,然后再与明文异或
- 支持并行解密,不支持并行加密

4.2.5. OFB
- 需要分组,分组长度根据算法而定
- 没有直接对明文分组加密,故不需要填充
- 是对初始化向量的结果不断进行加密,作为下一次加密的数据来源


4.2.6. CTR
- 需要分组,分组长度根据算法而定
- 没有直接对明文分组加密,故不需要填充
- 可以并行加解密

4.3. 非对称加密
4.3.1. 是什么
- 密钥有两个:公钥可以公开,私钥必须由持有者安全保管
- 签名和验签:私钥签名,公钥验签,用于验证完整性和签名者身份
- 加密和解密:公钥加密,私钥解密。目的是防止信息被第三方拦截和偷听
- 缺点:加密解密效率很低
- 优点:公开公钥不需要传输私钥

4.3.2. RSA算法

4.3.3. 数学原理
- 假设由两个很大的质数:p和q
- 记它们的乘积为:N=p * q 这里p * q计算很快,但是由N反推回p和q代价非常大,目前没有行之有效的公式
- 计算出比N小且与N互质的自然数的个数:φ(n)=(p-1) * (q-1)。这个公式由集合论证明
- 找出比φ(n)小且与之互质的自然数,记为e
- 有了e和φ(n)后,根据辗转相除法的原理,可以找到x和y,即e * x - φ(n) * y=1
- 把φ(n)=(p-1) * (q-1)代入,移动一下位置就有了e * x = 1 + (p - 1)* (q - 1) * y
- 最后我们有了N,e,x, 公钥就是N和e,私钥就是x
4.3.4. 工作过程
- 加密要用公钥(N,e)
- 假设明文是A,那么根据
A的e次方=R(mod N),公式的意思A的e次方 / N得到的余数是R,计算出的R就是密文
- 假设明文是A,那么根据
- 解密要用私钥x
- 假设密文是R,那么根据
R的x次方 = A (mod N),公式的意思R的x次方 / N得到的余数是A,计算出的A就是明文
- 假设密文是R,那么根据
4.3.4.1. 欧拉函数
上面加密解密的过程的原理是欧拉函数:
A的e次方=R(mod N)和R的x次方 = A (mod N),可以看出A的e次方和R的x次方同余,换句话说A的e次方 / R 余数是N,R的x次方 / A余数是N,这里代入公式没搞懂- 且由于
e * x - φ(n) * y=1,即A的e*x次方 = A的(1+φ(n) * y)次方 = A * A的(φ(n) * y)次方,这里φ(n) * y = 1的原理就是欧拉函数
5. 实现
5.1. OpenSSL
openssl
# 生成私钥
> genrsa -out rsa_private_key.pem
# 生成公钥
> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
5.2. Golang实现
5.2.1. AES-CTR
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
)
func cryptCTR(key, iv, input []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
output := make([]byte, len(input))
cipher.NewCTR(block, iv).XORKeyStream(output, input)
return output, nil
}
func main() {
key := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, key); err != nil {
panic(err)
}
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
plaintext := []byte("hello")
ciphertext, _ := cryptCTR(key, iv, plaintext)
recovered, _ := cryptCTR(key, iv, ciphertext)
fmt.Println(string(recovered))
}