crypto

1. 基础概念

1. 对称密钥加密

对称密钥加密: (英语:Symmetric-key algorithm)又称为对称加密、私钥加密、共享密钥加密(shared secrets),是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。实务上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通讯联系。

对称密钥加密的主要问题是一旦私钥泄漏,信息即被泄漏。比如摩斯电码可以被看作是一种对称加密算法,比如将英文字母向右移动一位的规则(凯撒密码,移位密码)也是一种对称加密,只是这种简单的加密方法容易被暴力破解。

在不安全的环境中如何传递对称加密的私钥也是一个难点。因为密钥一旦被截获,信息则被泄漏。(ECDH密钥协商算法可以通过非对称加密共享得到共享密钥)

常见的对称加密算法有DES、3DES、AES、Blowfish、IDEA、RC5、RC6

2.非对称密钥加密

公开密钥加密(英语:public-key cryptography,又译为公开密钥加密),也称为非对称加密(asymmetric cryptography),一种密码学算法类型。

在这种密码学方法中,需要一对密钥。一个是private key,另一个则是public key。这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质。

public key用于发送给需要给自己发信息的用户,该用户使用该public key来对自己的信息进行加密,再传输回来。这样即使被截获,黑客也无法破解其中的信息,因为只要该public key对应的private key才能够解密。

非对称加密常用于SSH, HTTPS, TLS,电子证书,电子签名,电子身份证等等

3. 摘要,电子签名 和 电子证书

非对称加密的一个问题是,发送信息者如何确保自己收到的public key来自于接受信息者。黑客很有可能将自己的public key冒充成接受信息者的key,从而获取到信息。比如在浏览器和服务器之间的数据传输中,需要确认服务器发送给浏览器的public key是来自于该服务器。

此时该服务器的public key和对应身份需要可信赖机构的认证,公开密钥基础建设负责分发认证申请,并分发电子证书。客户端收到电子证书后可以通过预先安装的根证书,验证该密钥是否对应于该服务器。

数字证书的生成实际上是用可信赖机构的私钥对服务器公钥和服务器信息加密,生成的。这样客户端通过可信赖机构的公钥解密该证书即可分辨该公钥和服务器信息是否对应。数字证书一般由数字证书认证机构(Certificate Authority)颁发,证书里面包含了真实服务器的公钥和网站的一些其他信息,数字证书机构用自己的私钥加密后发给浏览器,浏览器使用数字证书机构的公钥解密后得到真实服务器的公钥。这个过程是建立在被大家所认可的证书机构之上得到的公钥,所以这是一种安全的方式。

4. ssh原理

https://www.jellythink.com/archives/555

SSH使用非对称加密的一种通信协议。

SSH免密登陆的前提是使用ssh-keygen -t RSA生成公私秘钥对,然后通过ssh-copy-id -i ~/.ssh/id_rsa.pub user@host命令将公钥分发至远程主机。接下来的每次免密登陆步骤如下:

  1. 用户使用ssh user@host命令对远程主机发起登陆;
  2. 远程主机对用户返回一个随机串
  3. 用户所在主机使用私钥对这个随机串进行加密,并将加密的随机串返回至远程主机;
  4. 远程主机使用分发过来的公钥对加密随机串进行解密;
  5. 如果解密成功,就证明用户的登陆信息是正确的,则允许登陆;否则反之。

通过ssh-copy-id -i ~/.ssh/id_rsa.pub user@host命令分发的公钥都会被保存至远程主机的~/.ssh/authorized_keys文件中。

5. 哈希算法

https://www.liaoxuefeng.com/wiki/1252599548343744/1304227729113121

哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。相同的输入得到相同的输出摘要,不同的输入大概率得到不同的输出。

哈希碰撞时不可避免的,因为输出的字节数是一定的,所以能够保证不发生碰撞时,最大的输入个数必须大于等于输出的最大个数。而输入是有无限种可能的。所以,哈希算法是把一个无限的输入集合映射到一个有限的输出集合,必然会产生碰撞。

哈希算法要求碰撞的概率极低,以及难以从输出推测输入。哈希碰撞的概率越低,哈希算法越安全。

2. 对称加密算法

1. XOR加密

http://www.ruanyifeng.com/blog/2017/05/xor.html

异或运算的特性是,如果对原始值对一个密钥进行两次异或,会得到这个值本身。刚好可以用于对称加密。XOR加密相同的明文会对应相同的密文,这是很大的一个问题。

2. AES-GCM加密算法

https://juejin.cn/post/6844904122676690951

AES加密就是对称加密的一种,即加密和解密使用相同的一把密钥。它的全称是Advanced Encryption Standard(高级加密标准),主要是用来取代DES加密算法。

GCM是认证加密模式中的一种,它结合了上述两者的特点(GCM中的G就是指GMAC,C就是指CTR),能同时确保数据的保密性、完整性及真实性,另外,它还可以提供附加消息的完整性校验。

AES密钥必须是保密的,而nonce类似于salt,可以随机生成并以明文的方式附在密文后,或者通过相同的shared secret生成相同的nonce。两种方式均可以保证接收方能够收到nonce,而key却是保密的。

1
2
3
4
shared_secret = ecdh_compute_shared_secret(ecc_key1,ecc_key2)
aes_key = SHA256.new(shared_secret + b'key').digest()[:AES128_KEY_LEN]
aes_nonce = SHA256.new(shared_secret + b'nonce').digest()[:AES_NONCE_SIZE]
cipher = AES.new(aes_key, AES.MODE_GCM, nonce=aes_nonce, mac_len=AES_TAG_SIZE)

3. 分组加密

https://www.jianshu.com/p/b63095c59361

https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)

因为分组加密只能加密固定长度的分组,而实际需要加密的明文可能超过分组长度,此时就要对分组密码算法进行迭代,以完成整个明文加密,迭代的方法就是加密模式。

工作模式

1. ECB电子密码本

使用相同的密钥对不同的分组进行加密

缺乏混淆性,相同的明文对应相同的密文,极可能会暴露数据的pattern。加密一个要点在于相同的明文能够对应不同的密文,以此隐藏数据的模式!

2. 初始向量(IV,Initialization Vector)

为了防止相同的明文对应相同的密文,AES密钥需要随着分组的不同被修改。

初始向量

3. CTR模式

CTR

3. 非对称加密算法

1. ECC:椭圆曲线密码学

https://zhuanlan.zhihu.com/p/36326221
https://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/
https://segmentfault.com/a/1190000019172260

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 曲线方程为 y^2 = x^3 + ax + b
@dataclasses.dataclass(init=False)
class EccCurve:
name: str
p: int # 有限域点的个数,定义有限域
a: int # 曲线参数
b: int # 曲线参数
order: int # 基点的阶,order * (Gx, Gy) = 0
Gx: int # 基点为(Gx, Gy)
Gy: int
"""
Note: 有限域内逆元的定义 (inv(x) * x) % p = 1,模反元素
基点 * 私钥 = 公钥
G * d = Q
离散对数问题保证了,已经大数d的情况下计算Q很容易,反推困难。这个特性确保了密钥难以被破解。私钥可以是随机生成的数
"""
1
2
# 公钥 point_Q(point_x, point_y),私钥(d)
EccKey(curve='NIST P-521', point_x=1878215278705420913809941221673070453630291285278607802615476602600875358248113817201275279498247334786329838442133900179181579335312961075329458832888483454, point_y=1492631405230049828034629191114631058481712503830618825528196556525243860134770105498486116951576226435160198858744355258829276721863793065418711188792568624, d=14795520984477726864976711521888896156542260800586806650124809936525264257017938443585197860840835415724634154698356719165115708346614576620653695982388024)

2. ECDH密钥协商算法

https://www.orchome.com/1049

ECDH能够在不安全的网络传输中安全的分发密钥(共享密钥),分发的这个密钥可以作为对称加密的共享密钥。

基本原理是,双方交换公钥后能够推算出共享密钥,而只有知道其中一个的私钥才能够破解该共享密钥。而ECC的离散对数问题确保了私钥难以被破解

1
shared_secret = da * Qb = db * Qa = da * db * G

shared_secret的x点可以作为共享密钥来进行对称加密数据传输

然而ECDH不能够验证公钥是否来自于中间人攻击,即中间人可能将双方交换的公钥替换为自己生成的公钥,从而轻易的破解双方的信息以及伪装为对方通信。因此交换密钥之前可以通过使用公共证书颁发机构 (CA) 向双方提供可信数字签名密钥,CA权威机构可以确保该公钥确实来自于对方而不是中间人。

1
2
3
4
5
def ecdh_compute_shared_secret(self_pri_key: ECC.EccKey,
other_pub_key: ECC.EccKey) -> bytes:
assert (self_pri_key.curve == other_pub_key.curve)
point = other_pub_key.pointQ * self_pri_key.d
return int(point.x).to_bytes(point.size_in_bytes(), 'big')

3. ECDSA签名算法

https://www.orchome.com/1432

数字签名https://www.liaoxuefeng.com/wiki/1252599548343744/1304227943022626

私钥加密得到的密文实际上就是数字签名,要验证这个签名是否正确,只能用私钥持有者的公钥进行解密验证。

使用数字签名的目的是为了确认某个信息确实是由某个发送方发送的,任何人都不可能伪造消息,并且,发送方也不能抵赖。数字签名可以确保该信息确实是由发送方发出的,而不能被伪造。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def ecdsa_det_sign(self_pri_key: ECC.EccKey, msg: bytes) -> bytes:
hash_obj = SHA256.new(msg)
signer = DSS.new(self_pri_key,
mode='deterministic-rfc6979',
encoding='binary')
signature = signer.sign(hash_obj)
return signature


def ecdsa_verify(other_pub_key: ECC.EccKey, msg: bytes, signature: bytes):
hash_obj = SHA256.new(msg)
verifier = DSS.new(other_pub_key,
mode='deterministic-rfc6979',
encoding='binary')
verifier.verify(hash_obj, signature)

在实际应用的时候,签名实际上并不是针对原始消息,而是针对原始消息的哈希进行签名。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!