简介
pycrypto
实现了哈希函数(如 SHA256)和加密算法(如 AES、DES、RSA)。
注意!pycrypto
已很久未维护,有安全漏洞。
建议使用 pycryptodome
替代 pycrypto
,它是后者的一个分支,一直在维护。
安装
以下方法均可,推荐方法二。
方法一:Visual Studio
Windows 需要安装 Visual Studio 2015 或以上版本,本人是 Visual Studio 2017,安装方法大同小异。
cd C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build
vcvars64.bat
set CL=-FI"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\include\stdint.h"
pip install pycrypto
- 1
- 2
- 3
- 4
方法二:pycryptodome(推荐)
也可以用 pycryptodome
替代 pycrypto
,它是后者的一个分支,一直在维护。
pip uninstall pycrypto
pip install pycryptodome
- 1
- 2
初试
SHA256 计算散列值(哈希值)
from Crypto.Hash import SHA256
hash = SHA256.new()
hash.update(‘message’.encode())
print(hash.digest())
# b’\xabS\n\x13\xe4Y\x14\x98+y\xf9\xb7\xe3\xfb\xa9\x94\xcf\xd1\xf3\xfb"\xf7\x1c\xea\x1a\xfb\xf0+F\x0cm\x1d’
- 1
- 2
- 3
- 4
- 5
- 6
公钥
公钥系统下,发送方和接收方使用不同密钥——公钥或私钥。
场景 | 发送方 | 接收方 |
---|---|---|
加解密 | 公钥 | 私钥 |
数字签名 | 私钥 | 公钥 |
from Crypto.PublicKey import RSA
key_pair = RSA.generate(4096) # 生成密钥对
open(‘public.pem’, ‘wb’).write(key_pair.public_key().export_key(‘PEM’)) # 导出公钥
open(‘private.pem’, ‘wb’).write(key_pair.export_key(‘PEM’)) # 导出私钥
- 1
- 2
- 3
- 4
- 5
加解密
三种加密方式:
- 对称加密:参与方使用相同密钥进行加解密,速度快,适合处理大量数据。如 AES。
- 非对称加密:发送方使用公钥加密,接收方使用私钥解密,速度慢。如 RSA。
- 混合加密:将上述加密进行组合,优点兼具,非对称加密用于保护有效时间短的对称密钥,对称加密用于加密实际数据。
对称加密
两种对称加密方式:
- 流加密:一次加密一个字节数据。如 ChaCha20、XChaCha20 和 Salsa20
- 分组密码:对固定数量的数据进行加密。如 AES,一次加密 16 个字节。
Salsa20 加密
from Crypto.Cipher import Salsa20
# 加密方
plaintext = b’Hello World!‘ # 明文
key = b’0123456789012345’ # 密钥
cipher = Salsa20.new(key=key)
msg = cipher.nonce + cipher.encrypt(plaintext) # 消息=随机数+密文
# 解密方
key = b’0123456789012345’ # 密钥
msg_nonce = msg[:8]
ciphertext = msg[8:]
cipher = Salsa20.new(key=key, nonce=msg_nonce)
plaintext = cipher.decrypt(ciphertext)
print(plaintext)
# b’Hello World!'
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
AES 加密
from Crypto.Cipher import AES
# 加密方
plaintext = b’Hello World!‘ # 明文
key = b’0123456789012345’ # 密钥
cipher = AES.new(key, AES.MODE_EAX)
nonce = cipher.nonce
ciphertext, tag = cipher.encrypt_and_digest(plaintext)
# 解密方
key = b’0123456789012345’ # 密钥
cipher = AES.new(key, AES.MODE_EAX, nonce=nonce)
plaintext = cipher.decrypt(ciphertext)
try:
cipher.verify(tag) # 验证真实性
print(plaintext)
except ValueError:
print(‘密钥不正确或消息被破坏’)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
非对称加密
RSA 加密
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
# 生成公私密钥
key_pair = RSA.generate(1024)
open(‘public.pem’, ‘wb’).write(key_pair.public_key().export_key(‘PEM’))
open(‘private.pem’, ‘wb’).write(key_pair.export_key(‘PEM’))
# 加密方
plaintext = b’Hello World!'
public_key = RSA.importKey(open(‘public.pem’).read())
cipher = PKCS1_OAEP.new(public_key)
ciphertext = cipher.encrypt(plaintext)
# 解密方
private_key = RSA.importKey(open(‘private.pem’).read())
cipher = PKCS1_OAEP.new(private_key)
plaintext = cipher.decrypt(ciphertext)
print(plaintext)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
实际场景下,密钥长度应使用 3072 或 4096 位
数字签名
用于保证完整性和不可抵赖性。
PKCS#1 RSA 签名
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
# 生成公私密钥
key_pair = RSA.generate(1024)
open(‘public.pem’, ‘wb’).write(key_pair.public_key().export_key(‘PEM’))
open(‘private.pem’, ‘wb’).write(key_pair.export_key(‘PEM’))
# 发送方
plaintext = b’Hello World!'
private_key = RSA.importKey(open(‘private.pem’).read())
signer = pkcs1_15.new(private_key)
hash = SHA256.new(plaintext)
signature = signer.sign(hash)
# 接收方
plaintexts = [b’Hello World!‘, b’abc’]
public_key = RSA.importKey(open(‘public.pem’).read())
signer = pkcs1_15.new(public_key)
for plaintext in plaintexts:
hash = SHA256.new(plaintext)
try:
signer.verify(hash, signature)
print(‘合法’)
except:
print(‘非法’)
- 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
推荐阅读:什么是数字签名?
哈希函数
用于信息摘要。
将任意二进制字符串作为输入,并产生类似随机的固定长度的输出,即摘要或哈希值。
SHA256 计算散列值(哈希值)
from Crypto.Hash import SHA256
hash = SHA256.new()
hash.update(‘message’.encode())
print(hash.digest())
# b’\xabS\n\x13\xe4Y\x14\x98+y\xf9\xb7\xe3\xfb\xa9\x94\xcf\xd1\xf3\xfb"\xf7\x1c\xea\x1a\xfb\xf0+F\x0cm\x1d’
- 1
- 2
- 3
- 4
- 5
- 6
安全通信
PBKDF2 进行口令保护
from Crypto.Hash import SHA512
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Random import get_random_bytes
password = ‘123456’ # 口令
salt = get_random_bytes(16) # 加盐
keys = PBKDF2(password, salt, 64, count=1000000, hmac_hash_module=SHA512)
key1 = keys[:32]
key2 = keys[32:]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
推荐阅读:PBKDF2函数,比「Hash加盐」更好的口令保护方案
加密IO
封装
遇到的坑
参考文献
- pycrypto GitHub
- PyCryptodome GitHub
- PyCryptodome Documentation
- python 3.6.5 在windows下安装PyCrypto
- windows下python3.9安装pycrypto成功总结
- Installing pycrypto on windows (popular solution not working)
- How do I install PyCrypto on Windows?
- RSA Encrypt / Decrypt
- 什么是数字签名?
- PBKDF2函数,比「Hash加盐」更好的口令保护方案