1. 介绍
PyCrypto 是加密工具包 Crypto 的 python 版,该模块实现了各种算法和协议的加密,提供了各种加密方式对应的算法的实现,包括单向加密、对称加密及公钥加密和随机数操作等。
但是 PyCrypto 工具包在 2013 年之后就不再更新了,其开发者在 Github issue 里呼吁开发者使用 PyCryptodome 来代替 PyCrypto ,PyCryptodome 是 PyCrypto 包的扩展,其官方文档链接在 这儿。
2. 安装
PyCryptodome 可以直接使用 pip
安装,安装分为两种情形:
- 如果原来安装过 PyCrypto 库,并且想要 PyCryptodome 与 PyCrypto 同时独立存在,可以使用下面的命令,这样安装的所有模块包含在
Cryptodome
包中。
安装成功后可以使用下面的语句测试是否安装成功:pip install pycryptodome
pip install pycryptodome-test-vectors python -m Cryptodome.SelfTest
- 如果想完全替换原有的 PyCrypto 库,可以直接使用下面的命令,这样安装的所有模块都包含在
Crypto
包中。
测试是否安装成功:pip install pycryptodomex
pip install pycryptodome-test-vectors python -m Crypto.SelfTest
3. 简单使用的例子
官方文档给出的几个例子,参考文档
3.1 使用 AES 加密数据
下面的代码首先生成了一个 AES128 的密钥,之后对数据进行加密并存入保存到文件。
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
data = b'secret data'
key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(data)
file_out = open("encrypted.bin", "wb")
[ file_out.write(x) for x in (cipher.nonce, tag, ciphertext) ]
file_out.close()
如果知道密钥,就可以对已经加密的数据进行机密了,示例代码如下:
from Crypto.Cipher import AES
file_in = open("encrypted.bin", "rb")
nonce, tag, ciphertext = [ file_in.read(x) for x in (16, 16, -1) ]
# let's assume that the key is somehow available again
cipher = AES.new(key, AES.MODE_EAX, nonce)
data = cipher.decrypt_and_verify(ciphertext, tag)
3.2 生成 RSA 密钥
下面的代码生成了一个 RSA 密钥对,然后保存为一个文件,并对导出的密钥进行加密保存。最后以 ASCII/PEM 格式输出了 公钥。
from Crypto.PublicKey import RSA
#对密钥加密的密码
secret_code = "Unguessable"
#生成一个 2048 位的密钥
key = RSA.generate(2048)
#导出私钥,passphrase 指定了对私钥加密的密码
encrypted_key = key.export_key(passphrase=secret_code, pkcs=8,
protection="scryptAndAES128-CBC")
#将私钥保存到文件
file_out = open("rsa_key.bin","wb")
file_out.write(encrypted_key)
file_out.close()
#输出公钥
print(key.publickey().export_key())
"""
key:
RsaKey(n=22463096197996553139995046737582607693723050140918656968187783806048296851994713030637639584244546296229418273354730974731565132654730433478976537490969316053279136160323775384906719704647541878915106405211833999714714378734453635229891193929663456959822053965269987269594421836727975042800995386241667934412074534164766364388804722528648910960025057545935787296675224127288175435109671522952372878841804906859992071875306060687236789702901154379102325198197815894203477728818303000428325769511587465685717034283843241918646967437102530309248821918636225702751357928614730071472184308753632770719524107044460408634117, e=65537, d=8217708514199099131909474694552875639117704329670190276344449862549566522346144044830442770527413823111348060070133702865200418663708889755026961481525471673030409219400379583148924398107590221064881419933111464671256459516729376252410948320195404311155738816917627901523735611127631195182496374305157537902093462102237148415797171680504030427322921279144570085409749557852911900454393261339095241862855198342426664348286696499842068928446966299492513810120675677923666898663789698382472530197397760744545958420705114903052295325876496093509383926221586906276989185447349605518977383246985386830674059746974910106507, p=143397651514036487129005828827112040438803680420714037402740895385303361788683343615351947691447619163835696538596288824093586191844430325258117324837924246756959547987090445991958051369276902552467894541888302182662160018044539541602309435140270749210645181612853822850584471561720529363784190172464316328579, q=156648982468152567434543818122036991140036190334255771107533313319055793365217865125418050461072762503037720818820041575551717562332867184546763499983790131145153974131507210944382057299080722424387657102687724645524200600765653820332608941430757519632137733064191900145145925246064134049452838244334742859223, u=38868992018538102789197954260818058448125005376983029872818542145958024164377463002539217706689305479515437163956541525780015355926620596826814188069076194377095062859569533442106184216373931699737431325856796855629229898856335229535601710744639576472292148598507154704406900385116611139593990262730341244679)
key.exportKey():直接导出私钥(bytes形式)
b'-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAsfEmxlmGBGQVr/CoIdKO3gSpg/rM+Cp/LAweyecZxqGziyxl\n7FBwXGTizSv/N1yvqvhLQAZ0szYTIL8KxHOQdfjJjun0LHJkJXMye329YDZG9Kaq\n2sjO4hCp3WvJ55fVr750zK9ujLWF0MOeQTXXnewtrHhEbYFzSzMV3k2QbORHFeSV\nJPkcN3Ta8a9ynBJO4MCLH9V0t4EyKllHITQ3HNwu2A0RvFY+9UYWNqqTWZ6Gv8Hl\nTOFrRN8JuHK+7ty20LYLSiOmkiMI3WPFNb3I8Hyf9Lf58a3YfNwc3NkS2w2WwNfo\n4zBU1nz+woVCHGv4ofYeHfo6xecrte1+w+R7BQIDAQABAoIBAEEYx0YmBxzBHpv8\nbw3ckU6QpxE05dpd9aNAFd1oMapUirH9/pWKwehTMhO8JkRzIILsDd9w3S2YuTuw\nGDjRTEaUSuyBE0ZVXOTEdXHvCKJTiPbEqFmcv+69CN+LqNQUXGTMSL9+6HMKj1dV\n0SXrFCPefMENSH9FLdATcsseVhk3d6dVbdzEDDddXWbqK25j7KuSMevdeJJliAlc\nR80DExGeku4Tu4TL8yDIOifSPpSrvLl5bg5MabAuVfDHtnBKMmxNkpIB2LeOOxkw\n3VYyH+zkDNvZg0VGDkEe8PkkQEUslcOst6SDNdIW8fOz6dcwjmD9aODBsWFThjry\n2gnzy4sCgYEAzDR9HRp7S7yAxVdymg4nMW3nlLH2kYzkWxTTUk2T0ztkL7GKZ2+u\nbDND3p6Uz4TNzKgYfbxr1unXdgYiq2y6iDzVKiHE7RqO5SdIMOWPxvUkCBCrg30u\n4owiASYT5lPBP1WEAZjOuXRP+5KdBAgGtFxQU4hc+R6aOS/YLwXCqoMCgYEA3xNX\nnw4Cu/g4x++saCKNO1yjvYh69On68TlSXw39zqz57nRWY8H93ocC5VbEHVpZ1rNh\nuGrwTAOZ9w+MNF+1JUyBGQb3VMoUVorxrib7EbGV8Ek/Jza6YutGJL8MW1xyAdtt\nJwyXfjsEsugBgq/xL05g+HK5feglfj7PQu6E7dcCgYEAvwTGmIfiGBmwN2my6Usd\n/I37mEvVA5hRMKZNe2rYQjsHX9nrRxDgj5RxA3lCaNCpFq2To2KzWemKxHu+yK6/\n2ptVJ8FJDibOzqstS5giI5HC78xwNGLQjdlaIcr1yHpGhjE/d6LyleaovwMJ3/CG\nHQdRmKIxnlOzHpWT24C+9XMCgYEAutsI2kJyJ+GULmWklNXcV40R2wEnfV9AxC6v\nwM+HekeKUyM/+e/VJ0EQO+qh+7Ri7GT1xfRNtF6P6VMsrfI9WjDrMnuTUYKz5ooc\nRzR/uiJ25f901vQQzCsnZkBhqWWWWdfjZoI1o5bsKLAOE9osvON6dqIinkSGo2kZ\nU4dX8aECgYEAmYk6+WQnYnNRXfeWm4SxHAWm1X5dqcYKagHVYhK1GwnJcAmOuHRX\n2/EWZnzhm5KCafdklS9YiO/wnB6R7u/g5142BNFwJYKocooFwBKY5ZxDPbm//r9/\nFnfpHZorZK5rYqiV3aGh8fJRsGfpP6Im3QvFQFbFF+4xrW12KPx41vc=\n-----END RSA PRIVATE KEY-----'
key.public_key():获取公钥
RsaKey(n=22463096197996553139995046737582607693723050140918656968187783806048296851994713030637639584244546296229418273354730974731565132654730433478976537490969316053279136160323775384906719704647541878915106405211833999714714378734453635229891193929663456959822053965269987269594421836727975042800995386241667934412074534164766364388804722528648910960025057545935787296675224127288175435109671522952372878841804906859992071875306060687236789702901154379102325198197815894203477728818303000428325769511587465685717034283843241918646967437102530309248821918636225702751357928614730071472184308753632770719524107044460408634117, e=65537)
key.public_key().export_key():将公钥导出为bytes形式,等价于key.public_key().export_key(‘PEM’)
b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsfEmxlmGBGQVr/CoIdKO\n3gSpg/rM+Cp/LAweyecZxqGziyxl7FBwXGTizSv/N1yvqvhLQAZ0szYTIL8KxHOQ\ndfjJjun0LHJkJXMye329YDZG9Kaq2sjO4hCp3WvJ55fVr750zK9ujLWF0MOeQTXX\nnewtrHhEbYFzSzMV3k2QbORHFeSVJPkcN3Ta8a9ynBJO4MCLH9V0t4EyKllHITQ3\nHNwu2A0RvFY+9UYWNqqTWZ6Gv8HlTOFrRN8JuHK+7ty20LYLSiOmkiMI3WPFNb3I\n8Hyf9Lf58a3YfNwc3NkS2w2WwNfo4zBU1nz+woVCHGv4ofYeHfo6xecrte1+w+R7\nBQIDAQAB\n-----END PUBLIC KEY-----'
key.public_key().exportKey('DER'):将公钥导出为 DER 类型,可以用 key.exportKey('DER') 将私钥导出为该形式
b'0\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xb1\xf1&\xc6Y\x86\x04d\x15\xaf\xf0\xa8!\xd2\x8e\xde\x04\xa9\x83\xfa\xcc\xf8*\x7f,\x0c\x1e\xc9\xe7\x19\xc6\xa1\xb3\x8b,e\xecPp\\d\xe2\xcd+\xff7\\\xaf\xaa\xf8K@\x06t\xb36\x13 \xbf\n\xc4s\x90u\xf8\xc9\x8e\xe9\xf4,rd%s2{}\xbd`6F\xf4\xa6\xaa\xda\xc8\xce\xe2\x10\xa9\xddk\xc9\xe7\x97\xd5\xaf\xbet\xcc\xafn\x8c\xb5\x85\xd0\xc3\x9eA5\xd7\x9d\xec-\xacxDm\x81sK3\x15\xdeM\x90l\xe4G\x15\xe4\x95$\xf9\x1c7t\xda\xf1\xafr\x9c\x12N\xe0\xc0\x8b\x1f\xd5t\xb7\x812*YG!47\x1c\xdc.\xd8\r\x11\xbcV>\xf5F\x166\xaa\x93Y\x9e\x86\xbf\xc1\xe5L\xe1kD\xdf\t\xb8r\xbe\xee\xdc\xb6\xd0\xb6\x0bJ#\xa6\x92#\x08\xddc\xc55\xbd\xc8\xf0|\x9f\xf4\xb7\xf9\xf1\xad\xd8|\xdc\x1c\xdc\xd9\x12\xdb\r\x96\xc0\xd7\xe8\xe30T\xd6|\xfe\xc2\x85B\x1ck\xf8\xa1\xf6\x1e\x1d\xfa:\xc5\xe7+\xb5\xed~\xc3\xe4{\x05\x02\x03\x01\x00\x01'
"""
以下的代码展示了读取 RSA 的私钥,之后输出公钥:
from Crypto.PublicKey import RSA
#打开密钥的密码
secret_code = "Unguessable"
#读取私钥
encoded_key = open("rsa_key.bin", "rb").read()
key = RSA.import_key(encoded_key, passphrase=secret_code)
#输出私钥对应公钥
print(key.publickey().export_key())
"""
RSA.import_key(private_key): 导入export_key() 生成的密钥得到下面形式的密钥,私钥包含所有参数 n,e,d,p,q,u
RsaKey(n=22463096197996553139995046737582607693723050140918656968187783806048296851994713030637639584244546296229418273354730974731565132654730433478976537490969316053279136160323775384906719704647541878915106405211833999714714378734453635229891193929663456959822053965269987269594421836727975042800995386241667934412074534164766364388804722528648910960025057545935787296675224127288175435109671522952372878841804906859992071875306060687236789702901154379102325198197815894203477728818303000428325769511587465685717034283843241918646967437102530309248821918636225702751357928614730071472184308753632770719524107044460408634117, e=65537, d=8217708514199099131909474694552875639117704329670190276344449862549566522346144044830442770527413823111348060070133702865200418663708889755026961481525471673030409219400379583148924398107590221064881419933111464671256459516729376252410948320195404311155738816917627901523735611127631195182496374305157537902093462102237148415797171680504030427322921279144570085409749557852911900454393261339095241862855198342426664348286696499842068928446966299492513810120675677923666898663789698382472530197397760744545958420705114903052295325876496093509383926221586906276989185447349605518977383246985386830674059746974910106507, p=143397651514036487129005828827112040438803680420714037402740895385303361788683343615351947691447619163835696538596288824093586191844430325258117324837924246756959547987090445991958051369276902552467894541888302182662160018044539541602309435140270749210645181612853822850584471561720529363784190172464316328579, q=156648982468152567434543818122036991140036190334255771107533313319055793365217865125418050461072762503037720818820041575551717562332867184546763499983790131145153974131507210944382057299080722424387657102687724645524200600765653820332608941430757519632137733064191900145145925246064134049452838244334742859223, u=38868992018538102789197954260818058448125005376983029872818542145958024164377463002539217706689305479515437163956541525780015355926620596826814188069076194377095062859569533442106184216373931699737431325856796855629229898856335229535601710744639576472292148598507154704406900385116611139593990262730341244679)
RSA.import_key(public_key): 导入公钥得到的结果,公钥只包含 n,e
RsaKey(n=22395380937051172592642191568353575659442401561948694151236178214579276476617359009574814713581975317967266789329250810214761477132684341141109994693723548407901666853496648441685301736381459326622270685675365589520132728107466350762967859095599346906404210846508846196780424321013454084972144071952447199215717558045283912107175928584292682929679260517884044425951918884326563997230882538478197418417986055768041422169471162484047697740022235754206220872973261966094102754911818183974914765257149896515211594864299250764977834831170212919576793525794299277755668606355205589281493644067469456737254201353819478668307, e=65537)
"""
3.3 生成公钥和私钥
下面的代码生成了私钥,并保存到 private.pem
,之后生成了公钥,保存为 receiver.pem
。
from Crypto.PublicKey import RSA
#生成密钥
key = RSA.generate(2048)
#保存私钥
private_key = key.export_key()
file_out = open("private.pem", "wb")
file_out.write(private_key)
file_out.close()
#保存公钥
public_key = key.publickey().export_key()
file_out = open("receiver.pem", "wb")
file_out.write(public_key)
file_out.close()
3.4 RSA + AES 混合加密
为了加密任意数量的数据,这里使用混合加密方式(RSA+AES)。这里使用 RSA 和 PKCS#1oaep 对 AES 会话密钥进行非对称加密。
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
#要加密的数据
data = "I met aliens in UFO. Here is the map.".encode("utf-8")
#加密数据的输出
file_out = open("encrypted_data.bin", "wb")
#读取公钥
recipient_key = RSA.import_key(open("receiver.pem").read())
session_key = get_random_bytes(16)
# Encrypt the session key with the public RSA key
#加密会话密钥
cipher_rsa = PKCS1_OAEP.new(recipient_key)
enc_session_key = cipher_rsa.encrypt(session_key)
# Encrypt the data with the AES session key
#利用 AES 会话密钥加密数据
cipher_aes = AES.new(session_key, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(data)
[ file_out.write(x) for x in (enc_session_key, cipher_aes.nonce, tag, ciphertext) ]
file_out.close()
对于拥有私钥的解密者,首先使用私钥对会话密钥进行解密,再用会话密钥解密文件:
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
file_in = open("encrypted_data.bin", "rb")
#导入私钥
private_key = RSA.import_key(open("private.pem").read())
#读取 AES 的相关参数
enc_session_key, nonce, tag, ciphertext = \
[ file_in.read(x) for x in (private_key.size_in_bytes(), 16, 16, -1) ]
# Decrypt the session key with the private RSA key
# 对会话密钥解密
cipher_rsa = PKCS1_OAEP.new(private_key)
session_key = cipher_rsa.decrypt(enc_session_key)
# Decrypt the data with the AES session key
#使用会话密钥解密数据
cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce)
data = cipher_aes.decrypt_and_verify(ciphertext, tag)
print(data.decode("utf-8"))
相关文章: