Python3+PyCryptodome實現各種加密算法教程


一、說明

PyCryptodome是python一個強大的加密算法庫,可以實現常見的單向加密、對稱加密、非對稱加密和流加密算法。直接pip安裝即可:

pip install pycryptodome

官網地址:https://pycryptodome.readthedocs.io/en/latest/index.html

 

二、Base64編碼

2.1 base64編碼說明

原理:

將要編碼的內容按3字節為一組進行分組,最后一組不夠3位的則補0(顯然最多補兩個0)

每組中每字節最高2位改成0不使用,原先各位的內容保持原有順序往后移;最后在上一步中補了幾個0就加幾個等號以供解碼時按等號個數刪除0(經此操作原先3節字就變成了只使用低6位的4字節)

用途:一是SMTP中要以BASE64形式傳輸二進制文件,二是常用於將二進制數據轉成可打印的ASCII碼字符進行存儲(下文各加密算法的密鑰一般使用十六進制字符串形式存儲,但也有以base64形式存儲)。

其他:本質上講Base64只能算是一種編碼不能算是一種加密算法,PyCryptodome庫也不支持。但從”Base64讓人一下看不懂原本內容是什么“的角度講你也不能說他完全不算加密,平時也經常用,我們就順道講一講如何實現。

 

2.2 base64編碼實現代碼

import base64

# 編碼b"123456",輸出為b'MTIzNDU2'
base64.b64encode(b"123456")

# 解碼b'MTIzNDU2',輸出為b"123456"
base64.b64decode(b'MTIzNDU2')

 

三、單向加密算法

3.1 單向加密算法說明

別稱:單向加密算法,又稱哈希函數、散列函數、雜湊函數、摘要算法,英文名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庫實現。

 

3.2 標准庫支持的單向加密算法

import hashlib

# 注意輸出結果中各算法使用大寫和小寫寫了兩遍
# 同時也是說到后邊的書寫中算法名大寫或小寫都是可以的
hashlib.algorithms_available

 

3.3 使用hashlib實現hash算法(以md5為例)

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()

 

3.4 使用hmac實現hmac算法(以sha1為例)

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()

 

四、對稱加密算法

4.1 對稱加密算法說明

別名:對稱加密算法,又稱密鑰加密算法、單密鑰算法、共享密鑰算法,英文名Symmetric Encryption Algorithms。

原理:對稱加密算法最關鍵的就是SP變換,S變換通過代替操作實現混亂(即消除統計信息),P變換通過換位操作實現擴散(即雪崩效應);加解密是使用同一個密鑰的逆操作過程。

用途:對稱加密可以還原內容,且代替和換位操作運算量不大,適用於大量內容的加解密。對稱加密算法的缺點是加解密雙方密鑰分發困難。

其他:對稱加密算法有ECB、CBC、CFB、OFB、CTR等等多種模式,各種模式的加密是有些區別的,比如ECB不需要IV、CBC等則需要IV、EAX則需要nonce和tag等等,所以實現不同模式時寫法會有差別需要具體研究,不能完全照搬下邊的例子。

 

4.2 對稱加密算法實現代碼(以AES算法CBC模式為例)

加密代碼如下:

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)

 

五、非對稱加密算法

5.1 非對稱加密算法說明

別稱:非對稱加密算法,又稱公鑰加密算法,英文名Asymmetric Cryptographic Algorithm。

原理:非對稱加密依賴與明文經過與公鑰進行數學運算可得出密文,而密文經過與密鑰進行數學運算又可得到明文。

用途:非對稱加密算法的優點是密鑰分發簡單,但缺點也是很明顯的,其加解密過程依賴於數學運算運算量大所以加解密速度慢(另外同樣的密鑰強度其安全性弱於對稱加密算法),其只適用於少量內容的加解密,最典型的就是https中用於完成對稱密鑰的交換。

 

5.2 非對稱加密算法實現代碼(以RSA為例)

生成密鑰對代碼如下:

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)

 

5.3 非對稱加密算法簽名實現(以RSA為例)

我一直以為私鑰加密公鑰解密和公鑰加密私鑰解密沒什么兩樣,但首先一是和一個朋友說用私鑰加密發送回來時她疑或說私鑰可以加密嗎,然后回公司又和領導說私鑰加密公鑰解密的時候他直接說私鑰不能加密只能做簽名。

首先說私鑰加密公鑰解密在數學原理上是可行的,而且所謂的數字簽名其本質就是我用你的公鑰可以解開這加密的內容說明這些內容就是你的,即數字簽名和簽名認證本質就是私鑰加密公鑰解密。

但另一方面,因為公鑰是公開的所以私鑰加密並不能起加密通信的作用,所以一般沒有直接的私鑰加密公鑰解密的操作----但我不太明白為什么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.")

 

六、流加密算法實現(以RC4為例)

6.1 流加密算法說明

別稱:流加密算法,又稱序列加密算法,英文名Stream cipher。

原理:流加密算法加密和解密也使用同一個密鑰,所以從咬文嚼字來說他也屬於對稱加密算法。流加密算法與前邊單向加密算法、對稱加密算法、非對稱加密算法的區別是前三者都是分組加密算法即一個分組使用同一個密鑰,而流加密算法每一位都使用不同的密鑰。

用途:流加密主要基於異或(xor)操作,運算相對簡單,但安全性較低,沒有很多的使用場景,最典型的是WEP上的使用但也正由於其安全性問題導致WEP的淘汰。

 

6.2 流加密算法實現代碼(以RC4為例)

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM