PyCryptodome是python一个强大的加密算法库,能够实现常见的单向加密、对称加密、非对称加密和流加密算法。直接pip安装便可:html
pip install pycryptodome
官网地址:https://pycryptodome.readthedocs.io/en/latest/index.htmlpython
原理:git
将要编码的内容按3字节为一组进行分组,最后一组不够3位的则补0(显然最多补两个0)github
每组中每字节最高2位改为0不使用,原先各位的内容保持原有顺序日后移;最后在上一步中补了几个0就加几个等号以供解码时按等号个数删除0(经此操做原先3节字就变成了只使用低6位的4字节)算法
用途:一是SMTP中要以BASE64形式传输二进制文件,二是经常使用于将二进制数据转成可打印的ASCII码字符进行存储(下文各加密算法的密钥通常使用十六进制字符串形式存储,但也有以base64形式存储)。安全
其余:本质上讲Base64只能算是一种编码不能算是一种加密算法,PyCryptodome库也不支持。但从”Base64让人一下看不懂本来内容是什么“的角度讲你也不能说他彻底不算加密,平时也常常用,咱们就顺道讲一讲如何实现。dom
import base64 # 编码b"123456",输出为b'MTIzNDU2' base64.b64encode(b"123456") # 解码b'MTIzNDU2',输出为b"123456" base64.b64decode(b'MTIzNDU2')
别称:单向加密算法,又称哈希函数、散列函数、杂凑函数、摘要算法,英文名One-way encryption algorithm。函数
原理:单向加密如其名只能加密不能解密(彩虹表攻击不是正经的解密),不能解密的缘由是本质上并非用IV(Initial Vector)去加密M输出M的密文,而是用M去加密IV输出IV的密文。编码
用途:消息认证摘要、内容或文档的数字指纹、口令存储。加密
其余:
单向加密又能够分为hash和hmac两大类,hmac和hash的算法是同样的,其实能够认为hmac就是hash加盐的形式(不过这盐值不是hash中经常使用的拼接在最前边或拼接在最后边,具体怎么拼接的我不太肯定)。
通常来讲标准库就挺好用时咱们通常就直接用标准库,python的标准库就能容易地实现单向加密算法,因此单向加密咱们使用标准库实现。
python中hash类算法使用hashlib库实现,hmac类算法使用hmac库实现。
import hashlib # 注意输出结果中各算法使用大写和小写写了两遍 # 同时也是说到后边的书写中算法名大写或小写都是能够的 hashlib.algorithms_available
import hashlib # 实例化方法一,直接使用算法名;这种形式不彻底支持hashlib.algorithms_available中的算法 # m = hashlib.md5() # 实例化方法二,使用new方法;全部支持的算法名看上边hashlib.algorithms_available m = hashlib.new("md5") # update内是要加密的内容 # update使用+=,即连续屡次update表示在原先内容上追加而不是替换 m.update(b"123456") # 以十六进制字符串形式输出 m.hexdigest()
import hmac # 实例化原形是hmac.new(key, msg=None, digestmod=None) # key--加密用的盐值 # msg--要加密码的内容,可为空然后用update方法设置 # digestmod--加密算法,默认为md5,全部支持的算法名看上边hashlib.algorithms_available m = hmac.new(b"123",digestmod="sha1") # update使用+=,即连续屡次update表示在原先内容上追加而不是替换 # 但要注意所谓的+=是msg之间的+=,而不是key和msg之间的+= # 即便用如下update后等于hmac.new(b"123",b"123456", digestmod="sha1"),但不等于hmac.new(b"123123456", digestmod="sha1") m.update(b"123456") # 以十六进制字符串形式输出 m.hexdigest()
别名:对称加密算法,又称密钥加密算法、单密钥算法、共享密钥算法,英文名Symmetric Encryption Algorithms。
原理:对称加密算法最关键的就是SP变换,S变换经过代替操做实现混乱(即消除统计信息),P变换经过换位操做实现扩散(即雪崩效应);加解密是使用同一个密钥的逆操做过程。
用途:对称加密能够还原内容,且代替和换位操做运算量不大,适用于大量内容的加解密。对称加密算法的缺点是加解密双方密钥分发困难。
其余:对称加密算法有ECB、CBC、CFB、OFB、CTR等等多种模式,各类模式的加密是有些区别的,好比ECB不须要IV、CBC等则须要IV、EAX则须要nonce和tag等等,因此实现不一样模式时写法会有差异须要具体研究,不能彻底照搬下边的例子。
加密代码以下:
from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Random import get_random_bytes # 要加密的内容 data = b"123456" # 随机生成16字节(即128位)的加密密钥 key = get_random_bytes(16) # 实例化加密套件,使用CBC模式 cipher = AES.new(key, AES.MODE_CBC) # 对内容进行加密,pad函数用于分组和填充 encrypted_data = cipher.encrypt(pad(data, AES.block_size)) # 将加密内容写入文件 file_out = open("encrypted.bin", "wb") # 在文件中依次写入key、iv和密文encrypted_data [file_out.write(x) for x in (key, cipher.iv, encrypted_data)]
对应解密代码以下:
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad # 从前边文件中读取出加密的内容 file_in = open("encrypted.bin", "rb") # 依次读取key、iv和密文encrypted_data,16等是各变量长度,最后的-1则表示读取到文件末尾 key, iv, encrypted_data = [file_in.read(x) for x in (16, AES.block_size, -1)] # 实例化加密套件 cipher = AES.new(key, AES.MODE_CBC, iv) # 解密,如无心外data值为最早加密的b"123456" data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
别称:非对称加密算法,又称公钥加密算法,英文名Asymmetric Cryptographic Algorithm。
原理:非对称加密依赖与明文通过与公钥进行数学运算可得出密文,而密文通过与密钥进行数学运算又可获得明文。
用途:非对称加密算法的优势是密钥分发简单,但缺点也是很明显的,其加解密过程依赖于数学运算运算量大因此加解密速度慢(另外一样的密钥强度其安全性弱于对称加密算法),其只适用于少许内容的加解密,最典型的就是https中用于完成对称密钥的交换。
生成密钥对代码以下:
from Crypto.PublicKey import RSA# 生成密钥对 key = RSA.generate(2048) # 提取私钥并存入文件 private_key = key.export_key() file_out = open("private_key.pem", "wb") file_out.write(private_key) # 提取公钥存入文件 public_key = key.publickey().export_key() file_out = open("public_key.pem", "wb") file_out.write(public_key)
加密代码以下:
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP # 要加密的内容 data = b"123456" # 从文件中读取公钥 public_key = RSA.import_key(open("public_key.pem").read()) # 实例化加密套件 cipher = PKCS1_OAEP.new(public_key) # 加密 encrypted_data = cipher.encrypt(data) # 将加密后的内容写入到文件 file_out = open("encrypted_data.bin", "wb") file_out.write(encrypted_data)
解密代码以下:
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP # 从私钥文件中读取私钥 private_key = RSA.import_key(open("private_key.pem", "rb").read()) # 实例化加密套件 cipher = PKCS1_OAEP.new(private_key) # 从文件中读取加密内容 encrypted_data = open("encrypted_data.bin", "rb").read() # 解密,如无心外data值为最早加密的b"123456" data = cipher.decrypt(encrypted_data)
我一直觉得私钥加密公钥解密和公钥加密私钥解密没什么两样,但首先一是和一个朋友说用私钥加密发送回来时她疑或说私钥能够加密吗,而后回公司又和领导说私钥加密公钥解密的时候他直接说私钥不能加密只能作签名。
首先说私钥加密公钥解密在数学原理上是可行的,并且所谓的数字签名其本质就是我用你的公钥能够解开这加密的内容说明这些内容就是你的,即数字签名和签名认证本质就是私钥加密公钥解密。
但另外一方面,由于公钥是公开的因此私钥加密并不能起加密通讯的做用,因此通常没有直接的私钥加密公钥解密的操做----但我不太明白为何PyCryptodome这些库在程序试图使用私钥加密时直接报错拒绝执行(TypeError: This is not a private key),虽然没什么用,私钥加密也没有什么危害吧?
咱们直接使用5.2中的公私钥,另外由于签名要传给签名校验的内容比较多,因此就两部分不分开写了,代码以下:
from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA # 如下是签名部分 # 要签名的内容 data = b'123456' # 获取要签名的内容的HASH值。摘要算法是什么不重要,只要验证时使用同样的摘要算法便可 digest = SHA256.new(data) # 读取私钥 private_key = RSA.import_key(open('private_key.pem').read()) # 对HASH值使用私钥进行签名。所谓签名,本质就是使用私钥对HASH值进行加密 signature = pkcs1_15.new(private_key).sign(digest) # 如下是签名校验部分 # 签名部分要传给签名校验部分三个信息:签名内容原文、摘要算法、HASH值签名结果 # 获取被签名的内容的HASH值。使用与签名部分同样的摘要算法计算 digest = SHA256.new(data) # 读取公钥 public_key = RSA.import_key(open('public_key.pem').read()) try: # 进行签名校验。本质上就是使用公钥解密signature,看解密出来的值是否与digest相等 # 相等则校验经过,说明确实data确实原先的内容;不等则校验不经过,data或signature被篡改 # 可能有人会想,若是我先修改data而后再用本身的私钥算出signature,是否是能够完成欺骗? # 答案是不能,由于此时使用原先的公钥去解signature,其结果不会等于digest pkcs1_15.new(public_key).verify(digest, signature) print(f"The signature is valid.") except (ValueError, TypeError): print("The signature is not valid.")
别称:流加密算法,又称序列加密算法,英文名Stream cipher。
原理:流加密算法加密和解密也使用同一个密钥,因此从咬文嚼字来讲他也属于对称加密算法。流加密算法与前边单向加密算法、对称加密算法、非对称加密算法的区别是前三者都是分组加密算法即一个分组使用同一个密钥,而流加密算法每一位都使用不一样的密钥。
用途:流加密主要基于异或(xor)操做,运算相对简单,但安全性较低,没有不少的使用场景,最典型的是WEP上的使用但也正因为其安全性问题致使WEP的淘汰。
from Crypto.Cipher import ARC4 from Crypto.Hash import SHA from Crypto.Random import get_random_bytes # 要加密的内容 data = b"123456" # 流加密密码长度是可变的,RC4为40到2048位 # 通常上使用一个字符串做为初始密钥,而后再用sha1等生成真正的密钥 # 咱们这是直接点,随机生成16字节(即128位)做为密钥 key = get_random_bytes(16) # 实例化加密套件 cipher = ARC4.new(key) # 加密内容 encrypted_data = cipher.encrypt(data) # 注意在即使加解密像这里同样在同一文件里,解密时必定要从新实例化否则解密不正确 cipher = ARC4.new(key) # 解密,如无心外data为前边加密的b"123456" data = cipher.decrypt(encrypted_data)
参考:
https://pycryptodome.readthedocs.io/en/latest/src/examples.html#encrypt-data-with-aes
https://github.com/nemozqqz/pycrypto-sample/blob/master/RC4.py