对称加密AES和非对称加密RSA

AES( Advanced Encryption Standard )

对称加密算法加密和解密过程使用同一个密钥

AES为分组加密法,把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文,在AES标准规范中,分组长度只能是128位,AES是按照字节进行加密的,也就是说每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。这导致密钥长度不同,推荐加密的轮数也不同。

因为明文和密钥必须是128位(密钥可以是192/256 位),所以需要将分组明文和密钥进行补位

python代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from Crypto.Cipher import AES
import base64

# 加密 ECB模式 16代表16字节也就是128位
def aes_encode(key, password):
# 将密钥填充到16的倍数
key = key + (16 - len(key) % 16) * '\0'
# 创建AES密码器对象
cipher = AES.new(key.encode(), AES.MODE_ECB)
# 将明文填充到16的倍数
password = password + (16 - len(password) % 16) * '\0'
# 加密
ciphertext = cipher.encrypt(password.encode())
# 将密文进行Base64编码
ciphertext = base64.b64encode(ciphertext)
return ciphertext.decode()


# 解密
def aes_decode(key, ciphertext):
# 将密钥填充到16的倍数
key = key + (16 - len(key) % 16) * '\0'
# 创建AES密码器对象
cipher = AES.new(key.encode(), AES.MODE_ECB)
# 解码Base64编码的密文
ciphertext = base64.b64decode(ciphertext)
# 解密
plaintext = cipher.decrypt(ciphertext)
# 去除填充字符
plaintext = plaintext.rstrip(b'\0')
return plaintext.decode()


RSA

RSA是一种公钥加密算法,它可以用于保护数据的机密性和完整性。它基于两个大质数的乘积难以被分解的数学问题,通过这种问题的解决来保护数据的安全性。

RSA算法包括三个步骤:密钥生成、加密和解密。在密钥生成过程中,首先选择两个大质数p和q,计算它们的乘积n=pq,并选择一个整数e,使得e和(p-1)(q-1)互质。然后计算d,使得(de) mod((p-1)(q-1))=1。公钥是(e,n),私钥是(d,n)。

在加密过程中,要发送的消息m被转换为整数M,并用公钥(e,n)进行加密,计算C=M^e mod n。

在解密过程中,使用私钥(d,n)对加密的消息进行解密,计算M=C^d mod n。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

def generate_key_pair():
"""生成RSA密钥对"""
key_pair = RSA.generate(2048)
private_key = key_pair.export_key()
public_key = key_pair.publickey().export_key()
return private_key, public_key

def encrypt(public_key, plaintext):
"""RSA加密"""
key = RSA.import_key(public_key)
cipher = PKCS1_v1_5.new(key)
ciphertext = cipher.encrypt(plaintext.encode('utf-8'))
return base64.b64encode(ciphertext).decode('utf-8')

def decrypt(private_key, ciphertext):
"""RSA解密"""
key = RSA.import_key(private_key)
cipher = PKCS1_v1_5.new(key)
ciphertext = base64.b64decode(ciphertext.encode('utf-8'))
plaintext = cipher.decrypt(ciphertext, None).decode('utf-8')
return plaintext

if __name__ == '__main__':
# 生成RSA密钥对
private_key, public_key = generate_key_pair()

# unicode 转str
print(private_key.decode("utf-8"))
print(public_key.decode("utf-8"))
# 加密消息
message = 'Hello, world!'
ciphertext = encrypt(public_key, message)
print('加密后的消息:', ciphertext)
# 解密消息
plaintext = decrypt(private_key, ciphertext)
print('解密后的消息:', plaintext)

摘要算法,非对称加密算法与对称加密算法 安全性 比较

引用博客 https://blog.betamao.me/posts/2021/24/pkcs-v1_5_misuse/

  • 摘要算法通过单向陷门函数将任意长度映射到固定长度,这个过程是不可逆的,再加上它的抗碰撞性让它成为标识数据的好方法,这方面如果用的算法是老古董就可能受碰撞和长度扩展攻击的影响。
  • 对称加密算法使用的加解密钥相同,可再分为流密码与分组密码,流密码将它的密钥作为随机数种子通过伪随机生成函数源源不断地生成随机数,明文与之异或就得到了密文,由于异或运算的特性密文与之异或也就恢复了明文,因此它的加解密算法是一样的,而且它针对的任意长度的数据。分组密码的密钥和加密长度是固定的,它会对加密密钥进行一些变换,再与明文进行运算,该过程可能进行多次因此加解密算法不一定相同,由于它只能加密固定长度的数据,而一般要加密的数据长度都不满足要求,此时就需要把数据分组,若分组后最后一组的长度不满足要求又需要对其填充,前者就是分组密码的工作模式。是否需要填充也和工作模式相关,如OFB模式就可以将过程转换为类似流密码的方式,而XTS使用密文窃取也不需要填充,另外即使长度刚好符合也可能需要填充,如PKCS7此时就需要再填充一个完整的分组,之前提到若PKCS7与CBC模式组合时,就有可能出现PaddingOracle漏洞,即若服务端会返回解密状态则可以通过推测加密任何数据。
  • 非对称加密算法加解密不再使用相同的密钥,而且它的结构和对称密码有很大的不同,对称密码更像是逻辑位运算而非对称是数学运算,它利用的全是数学上的难题,就是(给一个限制)后只有正向计算的算法,而还没有逆向计算的算法(大整数分解,椭圆曲线离散对数,格最短向量等),先随机生成符合要求的私钥,私钥到公钥的生成过程是正向的有算法因此很容易,而反过来就没有算法可恢复,通过公开公钥就可实现加密与签名功能,由于这种加密也是在有限的范围上完成的因此单次运算的数字大小有限制,为此也需要对其分组填充,RSA就有PKCS1 V1.5与PKCS OAEP。