Crypto 算法庫在 python 中最初叫 pycrypto,這個做者有點懶,好幾年沒有更新,後來就有大佬寫了個替代庫 pycryptodome。這個庫目前只支持 python3,安裝也很簡單pip install pycryptodome
就好了!詳細的用法能夠看看 官方文檔html
常見對稱密碼在 Crypto.Cipher 庫下,主要有:DES 3DES AES RC4 Salsa20
非對稱密碼在 Crypto.PublicKey 庫下,主要有:RSA ECC DSA
哈希密碼在 Crypto.Hash 庫下,經常使用的有:MD5 SHA-1 SHA-128 SHA-256
隨機數在 Crypto.Random 庫下
實用小工具在 Crypto.Util 庫下
數字簽名在 Crypto.Signature 庫下
注意:python3 和 python2 在字符串方面有個明顯的區別 - python3 中有字節串 b'byte',python2 中沒有字節
。因爲這個庫是在 python3 下的,因此加解密用的都是字節!python
使用這個庫來加解密特別簡單,記住這四步:算法
from Crypto.Cipher import AES
api
key = b'this_is_a_key'
dom
aes = AES.new(key,AES.MODE_ECB)
函數
text_enc = aes.encrypt(b'helloworld')
工具
from Crypto.Cipher import AES import base64 key = bytes('this_is_a_key'.ljust(16,' '),encoding='utf8') aes = AES.new(key,AES.MODE_ECB) # encrypt plain_text = bytes('this_is_a_plain'.ljust(16,' '),encoding='utf8') text_enc = aes.encrypt(plain_text) text_enc_b64 = base64.b64encode(text_enc) print(text_enc_b64.decode(encoding='utf8')) # decrypt msg_enc = base64.b64decode(text_enc_b64) msg = aes.decrypt(msg_enc) print(msg.decode(encoding='utf8'))
注意:key和明文是須要填充到指定位數的,能夠使用ljust
或者zfill
之類的填充,也能夠用Util中的pad()
函數填充!this
from Crypto.Cipher import DES import base64 key = bytes('test_key'.ljust(8,' '),encoding='utf8') des = DES.new(key,DES.MODE_ECB) # encrypt plain_text = bytes('this_is_a_plain'.ljust(16,' '),encoding='utf8') text_enc = des.encrypt(plain_text) text_enc_b64 = base64.b64encode(text_enc) print(text_enc_b64.decode(encoding='utf8')) # decrypt msg_enc = base64.b64decode(text_enc_b64) msg = des.decrypt(msg_enc) print(msg.decode(encoding='utf8'))
這個庫的 RSA 主要是用來生成
公鑰文件/私鑰文件或者讀取
公鑰文件/私鑰文件
生成公/私鑰文件:code
from Crypto.PublicKey import RSA rsa = RSA.generate(2048) # 返回的是密鑰對象 public_pem = rsa.publickey().exportKey('PEM') # 生成公鑰字節流 private_pem = rsa.exportKey('PEM') # 生成私鑰字節流 f = open('public.pem','wb') f.write(public_pem) # 將字節流寫入文件 f.close() f = open('private.pem','wb') f.write(private_pem) # 將字節流寫入文件 f.close() # -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArreg3IX19DbszqSdBKhR 9cm495XAk9PBQJwHiwjKv6S1Tk5h7xL9/fPZIITy1M1k8LwuoSJPac/zcK6rYgMb DT9tmVLbi6CdWNl5agvUE2WgsB/eifEcfnZ9KiT9xTrpmj5BJql9H+znseA1AzlP iTukrH1frD3SzZIVnq/pBly3QbsT13UdUhbmIgeqTo8wL9V0Sj+sMFOIZY+xHscK IeDOv4/JIxw0q2TMTsE3HRgAX9CXvk6u9zJCH3EEzl0w9EQr8TT7ql3GJg2hJ9SD biebjImLuUii7Nv20qLOpIJ8qR6O531kmQ1gykiSfqj6AHqxkufxTHklCsHj9B8F 8QIDAQAB -----END PUBLIC KEY----- -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEArreg3IX19DbszqSdBKhR9cm495XAk9PBQJwHiwjKv6S1Tk5h 7xL9/fPZIITy1M1k8LwuoSJPac/zcK6rYgMbDT9tmVLbi6CdWNl5agvUE2WgsB/e ifEcfnZ9KiT9xTrpmj5BJql9H+znseA1AzlPiTukrH1frD3SzZIVnq/pBly3QbsT 13UdUhbmIgeqTo8wL9V0Sj+sMFOIZY+xHscKIeDOv4/JIxw0q2TMTsE3HRgAX9CX vk6u9zJCH3EEzl0w9EQr8TT7ql3GJg2hJ9SDbiebjImLuUii7Nv20qLOpIJ8qR6O 531kmQ1gykiSfqj6AHqxkufxTHklCsHj9B8F8QIDAQABAoI... -----END RSA PRIVATE KEY-----
讀取公/私鑰文件加解密:htm
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5 import base64 def rsa_encrypt(plain): with open('public.pem','rb') as f: data = f.read() key = RSA.importKey(data) rsa = PKCS1_v1_5.new(key) cipher = rsa.encrypt(plain) return base64.b64encode(cipher) def rsa_decrypt(cipher): with open('private.pem','rb') as f: data = f.read() key = RSA.importKey(data) rsa = PKCS1_v1_5.new(key) plain = rsa.decrypt(base64.b64decode(cipher),'ERROR') # 'ERROR'必需 return plain if __name__ == '__main__': plain_text = b'This_is_a_test_string!' cipher = rsa_encrypt(plain_text) print(cipher) plain = rsa_decrypt(cipher) print(plain)
注意:RSA 有兩種填充方式,一種是 PKCS1_v1_5
,另外一種是 PKCS1_OAEP
和 hashlib
庫的用法相似,先實例化某個 Hash 算法,再用 update() 調用就能夠了!
具體栗子:
from Crypto.Hash import SHA1,MD5 sha1 = SHA1.new() sha1.update(b'sha1_test') print(sha1.digest()) # 返回字節串 print(sha1.hexdigest()) # 返回16進制字符串 md5 = MD5.new() md5.update(b'md5_test') print(md5.hexdigest())
發送發用私鑰簽名,驗證方用公鑰驗證
from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA # 簽名 message = 'To be signed' key = RSA.import_key(open('private_key.der').read()) h = SHA256.new(message) signature = pkcs1_15.new(key).sign(h) # 驗證 key = RSA.import_key(open('public_key.der').read()) h = SHA.new(message) try: pkcs1_15.new(key).verify(h, signature): print "The signature is valid." except (ValueError, TypeError): print "The signature is not valid."
和 random
庫相似。第一個函數很經常使用
import Crypto.Random import Crypto.Random.random print(Crypto.Random.get_random_bytes(4)) # 獲得n字節的隨機字節串 print(Crypto.Random.random.randrange(1,10,1)) # x到y之間的整數,能夠給定step print(Crypto.Random.random.randint(1,10)) # x到y之間的整數 print(Crypto.Random.random.getrandbits(16)) # 返回一個最大爲N bit的隨機整數
經常使用到 Util 中的pad()
函數來填充密鑰
from Crypto.Util.number import * from Crypto.Util.Padding import * # 按照規定的幾種類型 pad,自定義 pad能夠用 ljust()或者 zfill() str1 = b'helloworld' pad_str1 = pad(str1,16,'pkcs7') # 填充類型默認爲'pkcs7',還有'iso7816'和'x923' print(unpad(pad_str1,16)) # number print(GCD(11,143)) # 最大公約數 print(bytes_to_long(b'hello')) # 字節轉整數 print(long_to_bytes(0x41424344)) # 整數轉字節 print(getPrime(16)) # 返回一個最大爲 N bit 的隨機素數 print(getStrongPrime(512)) # 返回強素數 print(inverse(10,5)) # 求逆元 print(isPrime(1227)) # 判斷是否是素數