Crypto库
Package
Description
Crypto.Cipher
Modules for protecting confidentiality that is, for encrypting and decrypting data (example: AES).
Crypto.Signature
Modules for assuring authenticity , that is, for creating and verifying digital signatures of messages (example: PKCS#1 v1.5).
Crypto.Hash
Modules for creating cryptographic digests (example: SHA-256).
Crypto.PublicKey
Modules for generating, exporting or importing public keys (example: RSA or ECC).
Crypto.Protocol
Modules for faciliting secure communications between parties, in most cases by leveraging cryptograpic primitives from other modules (example: Shamir’s Secret Sharing scheme).
Crypto.IO
Modules for dealing with encodings commonly used for cryptographic data (example: PEM).
Crypto.Random
Modules for generating random data.
Crypto.Util
General purpose routines (example: XOR for byte strings).
简而言之
常见对称密码在 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 库下
AES加解密 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from Crypto.Cipher import AESimport base64key = bytes ('this_is_a_key' .ljust(16 ,' ' ),encoding='utf8' ) aes = AES.new(key,AES.MODE_ECB) 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' )) msg_enc = base64.b64decode(text_enc_b64) msg = aes.decrypt(msg_enc) print(msg.decode(encoding='utf8' ))
注意:key和明文是需要填充到指定位数的,可以使用ljust
或者zfill
之类的填充,也可以用Util中的pad()
函数填充!
对称密码DES 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from Crypto.Cipher import DESimport base64key = bytes ('test_key' .ljust(8 ,' ' ),encoding='utf8' ) des = DES.new(key,DES.MODE_ECB) 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' )) msg_enc = base64.b64decode(text_enc_b64) msg = des.decrypt(msg_enc) print(msg.decode(encoding='utf8' ))
非对称密码RSA 这个库的 RSA 主要是用来生成
公钥文件/私钥文件或者读取
公钥文件/私钥文件 生成公/私钥文件
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 from Crypto.PublicKey import RSArsa = 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-----
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 读取公/私钥文件加解密: from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_v1_5import base64def 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' ) 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
Hash算法 和 hashlib
库的用法类似,先实例化某个 Hash 算法,再用 update() 调用就可以了!
1 2 3 4 5 6 7 8 9 from Crypto.Hash import SHA1,MD5sha1 = SHA1.new () sha1.update(b'sha1_test' ) print (sha1.digest()) print (sha1.hexdigest()) md5 = MD5.new () md5.update(b'md5_test' ) print (md5.hexdigest())
数字签名 发送发用私钥签名,验证方用公钥验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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
库类似。第一个函数很常用
1 2 3 4 5 6 7 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()
函数来填充密钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 )) # 判断是不是素数
gmpy2库 gmpy2常见函数使用 1.初始化大整数
1 2 3 4 import gmpy2gmpy2.mpz(909090 ) result:mpz(909090 )
2.求大整数a,b的最大公因数
1 2 3 4 import gmpy2gmpy2.gcd(6 ,18 ) result:mpz(6 )
3.求大整数x模m的逆元y
1 2 3 4 5 import gmpy2gmpy2.invert(4 ,23 ) result:mpz(6 )
4.检验大整数是否为偶数
1 2 3 4 5 6 7 8 9 10 import gmpy2gmpy2.is_even(6 ) result:True ----------- import gmpy2gmpy2.is_even(7 ) result:False
5.检验大整数是否为奇数
1 2 3 4 5 6 7 8 9 10 import gmpy2gmpy2.is_odd(6 ) result:False ----------- import gmpy2gmpy2.is_odd(7 ) result:True
6.检验大整数是否为素数
1 2 3 4 import gmpy2gmpy2.is_prime(5 ) result:True
7.求大整数x开n次根
1 2 3 4 import gmpy2gmpy2.iroot(81 ,2 ) result:(mpz(9 ),True )
8.求大整数x的y次幂模m取余
1 2 3 4 5 import gmpy2gmpy2.powmod(2 ,4 ,15 ) result:mpz(1 )
9.扩展欧几里得
1 2 3 4 5 import gmpy2 gmpy2 .gcdext(3 ,17 )result :(mpz(1 ), mpz(6 ), mpz(-1 ))
RSA库 仅对字节运行
生成密钥 1 2 3 4 (pubkey, privkey) = rsa.newkeys(512 , poolsize=8 )
name
value
pubkey
(n,e)
privkey
(n,e,d,p,q)
实际测试生成4096位密钥需要50秒左右
加密解密 rsa.encrypt(message,pubkey) rsa.decrypt(crypto,prikey) 过程演示 1 2 3 4 5 (bob_pub, bob_priv) = rsa.newkeys(512 ) message = 'hello Bob!' .encode('utf8' ) crypto = rsa.encrypt(message, bob_pub) message = rsa.decrypt(crypto, bob_priv) print(message.decode('utf8' ))
如果加密消息被篡改会报错
签名和验证 rsa.sign() 为邮件创建分离签名
rsa.verify() 验证签名,成功返回True
如果签名被篡改会报错
函数格式
rsa.encrypt
(message: bytes , pub_key: rsa.key.PublicKey ) → bytes
rsa.decrypt
(crypto: bytes , priv_key: rsa.key.PrivateKey ) → bytes
rsa.sign
(message: bytes , priv_key: rsa.key.PrivateKey , hash_method: str ) → bytes
rsa.verify
(message: bytes , signature: bytes , pub_key: rsa.key.PublicKey ) → str
rsa.find_signature_hash
(signature: bytes , pub_key: rsa.key.PublicKey ) → str 返回从签名中检测到的哈希名称
其他 https://stuvel.eu/python-rsa-doc/genindex.html
Secrets库
secrets是python3.6加入到标准库的,使用secrets模块,可以生成适用于处理机密信息(如密码,帐户身份验证,安全令牌)的加密强随机数。
导入
SystemRandom 它是使用OS提供的最高质量源生成随机数的类。 有关更多详细信息,请参阅random.SystemRandom。
1 2 3 secrets .SystemRandom ()<random .SystemRandom at 0x7fd537094418 >
choice(sequence) 从非空序列中选择一个元素。
1 secrets .choice([23 ,3 ,5 ,6 ])
randbelow [0,n) 取0-n之间的整数
1 2 3 secrets .randbelow(10 )6
randbits(k) 随机不超过k位的整数
1 2 3 secrets .randbits(10 )426
token生成 secret模块还提供用于生成适合于重置密码和难以想象的URL的安全令牌的功能。
token_bytes 1 2 3 secrets.token_bytes(nbytes=10) b'\x ca\x feQ\x 03&\x 8b7\x d7&\x af'
返回包含nbytes个字节的字节字符串。 如果nbytes为None或未给出,则使用有效的默认值。
token_hex 返回十六进制随机文本字符串。 该字符串有n个字节的随机字节,每个字节转换为两个十六进制数字。 如果nbytes为None或未给出,则使用有效的默认值。
1 2 3 secrets.token_hex() '494ee83c2a42ce3dc488b059eb64a50628667 e9f2c939a8767 2d3d6a174825 2a'
token_urlsafe 返回随机字节为nbytes的URL安全文本字符串。 文本以Base64编码,每个字节平均约为1.3个字符。 如果nbytes为None或未给出,则使用有效的默认值。
1 2 3 secrets.token_urlsafe() 'giZFsPv9ch4OGWvuqihEIkj0LwOsHDOjgGHoqDeTvb8'
compare_digest 字符串比较的安全方式,减少攻击风险。
1 2 3 secrets.compare_digest("e" ,"E" ) False