NOTE

1.4 加密

对称加密、分组模式、非对称加密、RSA 与基础实现。

Security创建于 更新于 约 3 分钟读完historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 加密是什么

2. 加密特性

机密性

3. 加密三要素

3.1. 加密

  • 明文
  • 密钥
  • 加密算法

3.2. 解密

  • 密文
  • 密钥
  • 解密算法:可能跟加密算法不同

4. 加密算法分类

4.1. 对称加密

4.1.1. 是什么

  • 密钥只有一个,双方使用的密钥相同
  • 优点:加密效率高
  • 缺点:密钥的传输不安全

4.1.2. 凯撒密码

4.1.3. DES

不推荐使用。

  • 加密
  • 解密
  • 密钥 长度为8bytes
  • 分组 8bytes

4.1.4. 3DES

Triple DES

  • 加密 中间使用解密的原因是为了兼容以前的DES

  • 解密

  • 密钥 长度为8bytes,总共3个密钥,所以总长度为24bytes 密钥1和密钥2相同,或者密钥2和密钥3相同,就是DES

  • 分组 8bytes

4.1.5. AES

推荐使用

  • 密钥 长度可选,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就是密文
  • 解密要用私钥x
    • 假设密文是R,那么根据R的x次方 = A (mod N),公式的意思R的x次方 / N得到的余数是A,计算出的A就是明文
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"
	"fmt"
	"log"
)

const (
	aesKey = "12345678abcdefgh"
	aesIv = "abcdabcd12345678"
)

//加密
func AesEny(plaintext []byte) []byte {
	var(
		block cipher.Block
		err error
	)
        //创建aes
	if block, err = aes.NewCipher([]byte(aesKey)); err != nil{
		log.Fatal(err)
	}
        //创建ctr
	stream := cipher.NewCTR(block, []byte(aesIv))
        //加密, src,dst 可以为同一个内存地址
	stream.XORKeyStream(plaintext, plaintext)
	return plaintext
}

//解密
func AesDec1(ciptext []byte) []byte {
	var(
		 block cipher.Block
		 err error
	)
        //创建aes
	if block, err = aes.NewCipher([]byte(aesKey)); err != nil{
		log.Fatal(err)
	}
        //创建ctr
	stream := cipher.NewCTR(block,[]byte(aesIv))
	stream.XORKeyStream(ciptext, ciptext)
	return ciptext
}

//解密
func AesDec2(ciptext []byte) []byte  {
        //对密文再进行一次按位异或就可以得到明文
        //例如:3的二进制是0011和8的二进制1000按位异或(相同为0,不同为1)后得到1011,
        //对1011和8的二进制1000再进行按位异或得到0011即是3
	return AesEny(ciptext)
}

func main() {
	plaintext := []byte("我 爱 你")
	fmt.Println("明文", string(plaintext))
	ciptext := AesEny(plaintext)
	fmt.Println("加密", ciptext)
	//platext1 := AesDec1(ciptext)
	//fmt.Println("解密", string(platext1))
	platext2 := AesDec2(ciptext)
	fmt.Println("解密", string(platext2))
}

6. 参考

讨论

使用 GitHub 账号参与讨论,评论会保存在 GitHub Issues 中。在 GitHub 查看