一、什么叫數據加密
數據加密是指利用加密算法和秘鑰將明文轉變為密文的過程。
二、數據加密的方式
1、單向加密
指只能加密數據而不能解密數據,這種加密方式主要是為了保證數據的完整性,常見的加密算法有MD5、sha系列等(位於python內置的hashlib模塊中)。
2、對稱加密
指數據加密和解密使用相同的秘鑰,這種加密方式主要是為了保證數據的機密性,常見的加密算法有DES、AES(位於python第三方庫pycrytodomex中)。
3、非對稱加密
也叫公鑰加密,指數據加密和解密使用不同的密鑰,這種加密方式基本不可能被破解,主要用於身份驗證等方面,常見的加密算法有DSA、RSA(位於python第三方模塊rsa中)。
三、加密算法
1、單向加密算法(MD5、sha系列)
from hashlib import md5, sha256, sha512 m = md5() m.update("123".encode()) print(m.hexdigest()) # 32 # 202cb962ac59075b964b07152d234b70 print(m.digest()) # b' ,\xb9b\xacY\x07[\x96K\x07\x15-#Kp' s = sha512() s.update("123".encode()) print(s.hexdigest()) # 3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2 print(s.digest()) b'<\x99\t\xaf\xec%5MU\x1d\xae!Y\x0b\xb2n8\xd5?!s\xb8\xd3\xdc>\xeeL\x04~z\xb1\xc1\xeb\x8b\x85\x10>;\xe7\xbaa;1\xbb\\\x9c6!M\xc9\xf1JB\xfdz/\xdb\x84\x85k\xca\\D\xc2'
2、對稱加密算法(AES、DES)
安裝第三方庫:
pip install pycryptodomex -i https://pypi.douban.com/simple
DES算法為密碼體制中的對稱密碼體制,又被稱為美國數據加密標准。 DES是一個分組加密算法,典型的DES以64位為分組對數據加密,加密和解密用的是同一個算法。 DES算法的入口參數有三個:Key1。其中Key為8個字節共64位,是DES算法的工作密鑰;Data為8個字節64位的整數倍,是要被加密或被解密的數據** 密鑰長64位,密鑰事實上是56位參與DES運算(第8、16、24、32、40、48、56、64位是校驗位,使得每個密鑰都有奇數個1),對64位二進制數據塊進行加密,分組后的明文組和56位的密鑰按位替代或交換的方法形成密文組。每次加密對64位的輸入數據進行16輪編碼,經過一系列替換和移位后轉換成完全不同的64位輸出數據。
from Cryptodome.Cipher import DES key = b'88888888' data = "Good Good Study! Day Day Up!" count = 8 - (len(data) % 8) plaintext = data + count * "=" des = DES.new(key, DES.MODE_ECB) ciphertext = des.encrypt(plaintext.encode()) print(ciphertext) # b'D\xa4Z\x1dt\xba\xf3\xe8\xdbv\x1aP\x81\xe4\xe6Jx?\xfe\xf2\x0b\x82\nG\x08d\xea\xd0\t\x07vs' plaintext = des.decrypt(ciphertext) plaintext = plaintext[:(len(plaintext)-count)] print(plaintext) # b'Good Good Study! Day Day Up!'
3DES(或稱為Triple DES)是三重數據加密算法(TDEA,Triple Data Encryption Algorithm)塊密碼的通稱。它相當於是對每個數據塊應用三次DES加密算法。 由於計算機運算能力的增強,原版DES密碼的密鑰長度變得容易被暴力破解。3DES即是設計用來提供一種相對簡單的方法,即通過增加DES的密鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼算法。 3DES(即Triple DES)是DES向AES過渡的加密算法(1999年,NIST將3-DES指定為過渡的加密標准),加密算法,其具體實現如下:設Ek()和Dk()代表DES算法的加密和解密過程,K代表DES算法使用的密鑰,M代表明文,C代表密文,這樣: 3DES加密過程為:C=Ek3(Dk2(Ek1(M))) 3DES解密過程為:M=Dk1(EK2(Dk3(C)))。
AES為分組密碼,分組密碼也就是把明文分成一組一組的,每組長度相等,每次加密一組數據,直到加密完整個明文。在AES標准規范中,分組長度只能是128位,也就是說,每個分組為16個字節(每個字節8位)。密鑰的長度可以使用128位、192位或256位。密鑰的長度不同,推薦加密輪數也不同。
from Cryptodome.Cipher import DES, AES from Cryptodome import Random # 密鑰的長度為16字節、24字節或32字節 key = b"8888888888888888" print(AES.block_size) # 16 iv = Random.new().read(AES.block_size) # 也可以為24、32 plaintext = "測試數據" # 該數據長度不受限制 aes = AES.new(key, AES.MODE_EAX, iv) ciphertext = aes.encrypt(plaintext.encode()) # 一般后端會將iv放在加密的數據前一起傳遞到前端 transform_data = iv + ciphertext print(transform_data) # b'\x9e\xabF\xddx\xfa\x9f\xb7\x91\xa0\xafp\xee\xe9w\x8e\x11\x08\x12\xae\x0b\xc0\xc1\xbe\x80\xb2\xff\x0c' iv = transform_data[:16] aes = AES.new(key, AES.MODE_EAX, iv) plaintext = aes.decrypt(transform_data[16:]) print(plaintext) # b'\xe6\xb5\x8b\xe8\xaf\x95\xe6\x95\xb0\xe6\x8d\xae' print(plaintext.decode()) # 測試數據
3、非對稱加密算法(RSA、DSA)
安裝第三方庫:
pip install rsa -i https://pypi.douban.com/simple
指的是加密和解密使用不同的秘鑰。 一把作為公開的公鑰,另一把作為私鑰。這對密鑰中的公鑰進行加密,私鑰用於解密。反之亦然(被私鑰加密的數據也可以被公鑰解密) 。 在實際使用中私鑰一般保存在發布者手中,是私有的不對外公開的,只將公鑰對外公布,就能實現只有私鑰的持有者才能將數據解密的方法。 這種加密方式安全系數很高,因為它不用將解密的密鑰進行傳遞,從而沒有密鑰在傳遞過程中被截獲的風險,而破解密文幾乎又是不可能的。 但是算法的效率低,所以常用於很重要數據的加密,常和對稱配合使用,使用非對稱加密的密鑰去加密對稱加密的密鑰。 事實上,**公鑰加密算法很少用於數據加密,它通常只是用來做身份認證**,因為它的密鑰太長,加密速度太慢--公鑰加密算法的速度甚至比對稱加密算法的速度慢上3個數量級(1000倍)。
import rsa # 公鑰加密、私鑰解密 public_key, private_key = rsa.newkeys(1024) print(public_key) # PublicKey(115358647593237027749555219330290547595292720354379729059572469455025379115527291514465303947468690370446593609121177089794716265226101498361786298396410892325533861129676356325971818358112602498513419680609056457389715318966834362898086552554130435425753061655286667511557573410756120684188042377774434444807, 65537) print(private_key) # PrivateKey(115358647593237027749555219330290547595292720354379729059572469455025379115527291514465303947468690370446593609121177089794716265226101498361786298396410892325533861129676356325971818358112602498513419680609056457389715318966834362898086552554130435425753061655286667511557573410756120684188042377774434444807, 65537, 111285529956928522901721617280604228002764723117703733926382810265271061290888840676549733913221737511493431004615227720952917381576663793443813612330045581626681883557204892676718975967265771623672679503776812616315334112382868415864141371197836942710738341439472967902074841400226409659228441303650822610777, # 38470842708546405208704625508367712891471208299333441783981501073550023095274000403563916879641908231011170773153102126825952183163444780110955065002626432268349573, 2998599444966402616240989100234166167805477168671480027322013770416359562366030923233399853472241710845190991402502764232214027989568380839340059) plaintext = b"15863274538" ciphertext = rsa.encrypt(plaintext, public_key) print(ciphertext) # b'\x04\xb3ri\x1e\nA\xfb\x94\xff\xde{HtNw\xd4Q{\xdeRJ\xe0Fwl\x97kL\xde\xe6m\xc1\x8f\xd4\t\x96=\xb62\xad\x02\xfe\xeb4\xb4i\x8f\x9e\x0fp\x10\xbe\x8fiNrrUB\xbc\xe3\x87Q-\xe2\xa5\x86\xd9\x0b6,.\x90\xa1\xa6\x80\xf3\xaa\xcc\xdf7!\xdcp\xea\x0eE_?$\x8b\xcd\xb2\xca\x18\xf9e\xb5\x9b^\x84CcU\xe5.\xaeeFlz\xdeh\xb8\xa3D\xcb\xb6\xd5\x02\xe38\x98\xc80#Q' plaintext = rsa.decrypt(ciphertext, private_key) print(plaintext) # b'15863274538' # 私鑰加簽、公鑰驗簽 plaintext = b"15863274538" sign_message = rsa.sign(plaintext, private_key, "MD5") plaintext = b"15863274538" method = rsa.verify(b"15863274532", sign_message, public_key) print(method) # rsa.pkcs1.VerificationError: Verification failed
4、補充算法(base64)
目前Base64已經成為網絡上常見的傳輸8Bit字節代碼的編碼方式之一。在做支付系統時,系統之間的報文交互都需要使用Base64對明文進行轉碼,然后再進行簽名或加密,之后再進行(或再次Base64)傳輸。那么,Base64到底起到什么作用呢? 在參數傳輸的過程中經常遇到的一種情況:使用全英文的沒問題,但一旦涉及到中文就會出現亂碼情況。與此類似,網絡上傳輸的字符並不全是可打印的字符,比如二進制文件、圖片等。Base64的出現就是為了解決此問題,它是基於64個可打印的字符來表示二進制的數據的一種方法。 電子郵件剛問世的時候,只能傳輸英文,但后來隨着用戶的增加,中文、日文等文字的用戶也有需求,但這些字符並不能被服務器或網關有效處理,因此Base64就登場了。隨之,Base64在URL、Cookie、網頁傳輸少量二進制文件中也有相應的使用。 原文鏈接:https://blog.csdn.net/wo541075754/article/details/81734770
from base64 import b64encode, b64decode plaintext = "我的銀行卡密碼是020012" ciphertext = b64encode(plaintext.encode()) print(ciphertext) # b'5oiR55qE6ZO26KGM5Y2h5a+G56CB5pivMDIwMDEy' plaintext = b64decode(ciphertext) print(plaintext) # b'\xe6\x88\x91\xe7\x9a\x84\xe9\x93\xb6\xe8\xa1\x8c\xe5\x8d\xa1\xe5\xaf\x86\xe7\xa0\x81\xe6\x98\xaf020012' print(plaintext.decode()) # 我的銀行卡密碼是020012