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