加密技術(shù)定義滓玖、使用
在開發(fā)爬蟲的過程中,我們經(jīng)常遇到的一種反爬措施是數(shù)據(jù)加密秩命。常見的加密算法可以分為三類:對稱加密算法阔涉,非對稱加密算法和Hash算法(事實(shí)上不是加密算法而是摘要算法)
一、對稱加密
1.定義
采用單鑰密碼系統(tǒng)的加密方法媒抠,同一個(gè)密鑰可以同時(shí)用作信息的加密和解密弟断,這種加密方法稱為對稱加密咏花,也稱為單密鑰加密趴生。由于其速度快,對稱性加密通常在消息發(fā)送方需要加密大量數(shù)據(jù)時(shí)使用昏翰。但是苍匆,加解密雙方使用同樣的密鑰進(jìn)行加密和解密。密鑰是控制加密及解密的指令棚菊,算法是一種規(guī)則浸踩,規(guī)定如何進(jìn)行加密和解密。因此加密的安全性不僅取決于加密算法本身统求,密鑰管理的安全性更是重要检碗。因?yàn)榧用芙饷芏际褂猛粋€(gè)密鑰,如何把密鑰安全地傳遞到解密者手上就成了必須要解決的問題码邻。
2.工作過程
下面舉個(gè)例子來簡要說明一下對稱加密的工作過程折剃。甲和乙是一對生意搭檔,他們住在不同的城市像屋。由于生意上的需要怕犁,他們經(jīng)常會(huì)相互之間郵寄重要的貨物。為了保證貨物的安全己莺,他們商定制作一個(gè)保險(xiǎn)盒奏甫,將物品放入其中。他們打造了兩把相同的鑰匙分別保管凌受,以便在收到包裹時(shí)用這個(gè)鑰匙打開保險(xiǎn)盒阵子,以及在郵寄貨物前用這把鑰匙鎖上保險(xiǎn)盒。
上面是一個(gè)將重要資源安全傳遞到目的地的傳統(tǒng)方式胜蛉,只要甲乙小心保管好鑰匙挠进,那么就算有人得到保險(xiǎn)盒智蝠,也無法打開。這個(gè)思想被用到了現(xiàn)代計(jì)算機(jī)通信的信息加密中奈梳。
3.常用算法
對稱加密的常用算法有:DES杈湾,3DES,AES
DES
簡介
DES全稱為Data Encryption Standard攘须,即數(shù)據(jù)加密標(biāo)準(zhǔn)漆撞,是一種使用密鑰加密的塊算法,1977年被美國聯(lián)邦政府的國家標(biāo)準(zhǔn)局確定為聯(lián)邦資料處理標(biāo)準(zhǔn)(FIPS)于宙,并授權(quán)在非密級(jí)政府通信中使用浮驳,隨后該算法在國際上廣泛流傳開來。
算法原理
太過非人類捞魁,有興趣自行查閱相關(guān)資料至会。
算法特點(diǎn)
分組比較短、密鑰太短谱俭、密碼生命周期短奉件、運(yùn)算速度較慢。因?yàn)樗惴ㄖ杏写罅康奈贿\(yùn)算昆著,一般在硬件中實(shí)現(xiàn)县貌。
3DES
簡介
3DES(或稱為Triple DES)是三重數(shù)據(jù)加密算法(TDEA,Triple Data Encryption Algorithm)塊密碼的通稱凑懂。它相當(dāng)于是對每個(gè)數(shù)據(jù)塊應(yīng)用三次DES加密算法煤痕。由于計(jì)算機(jī)運(yùn)算能力的增強(qiáng),原版DES密碼的密鑰長度變得容易被暴力破解接谨;3DES即是設(shè)計(jì)用來提供一種相對簡單的方法摆碉,即通過增加DES的密鑰長度來避免類似的攻擊,而不是設(shè)計(jì)一種全新的塊密碼算法脓豪。
AES
https://blog.csdn.net/lrwwll/article/details/78069013 有意思的博客
簡介
高級(jí)加密標(biāo)準(zhǔn)(英語:Advanced Encryption Standard巷帝,縮寫:AES),在密碼學(xué)中又稱Rijndael加密法跑揉,是美國聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)锅睛。這個(gè)標(biāo)準(zhǔn)用來替代原先的DES,已經(jīng)被多方分析且廣為全世界所使用历谍。經(jīng)過五年的甄選流程现拒,高級(jí)加密標(biāo)準(zhǔn)由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)于2001年11月26日發(fā)布于FIPS PUB 197,并在2002年5月26日成為有效的標(biāo)準(zhǔn)望侈。2006年印蔬,高級(jí)加密標(biāo)準(zhǔn)已然成為對稱密鑰加密中最流行的算法之一。
不同于它的前任標(biāo)準(zhǔn)DES脱衙,Rijndael使用的是代換-置換網(wǎng)絡(luò)侥猬,而非Feistel架構(gòu)例驹。AES在軟件及硬件上都能快速地加解密,相對來說較易于實(shí)作退唠,且只需要很少的存儲(chǔ)器鹃锈。作為一個(gè)新的加密標(biāo)準(zhǔn),目前正被部署應(yīng)用到更廣大的范圍瞧预。
算法原理
不討論屎债。
設(shè)計(jì)思想
- 抵抗所有已知的攻擊。
- 在多個(gè)平臺(tái)上速度快垢油,編碼緊湊盆驹。
- 設(shè)計(jì)簡單。
實(shí)際開發(fā)中使用AES加密需要注意的地方
- 服務(wù)端和我們客戶端必須使用一樣的密鑰和初始向量IV滩愁。
- 服務(wù)端和我們客戶端必須使用一樣的加密模式躯喇。
- 服務(wù)端和我們客戶端必須使用一樣的Padding模式。
以上三條有一個(gè)不滿足硝枉,雙方就無法完成互相加解密廉丽。
同時(shí)針對對稱加密密鑰傳輸問題這個(gè)不足:我們一般采用RSA+AES加密相結(jié)合的方式,用AES加密數(shù)據(jù)檀咙,而用RSA加密AES的密鑰雅倒。同時(shí)密鑰和IV可以隨機(jī)生成璃诀,這要是128位16個(gè)字節(jié)就行弧可,但是必須由服務(wù)端來生成,因?yàn)槿绻晌覀兛蛻舳松傻脑捔踊叮秃帽任覀兛蛻舳舜娣帕朔菍ΨQ加密的私鑰一樣棕诵,這樣容易被反編譯,不安全凿将,一定要從服務(wù)端請求密鑰和初始向量IV校套。
在python中使用
PyCrypto是 Python 中密碼學(xué)方面最有名的第三方軟件包∧恋郑可惜的是笛匙,它的開發(fā)工作于2012年就已停止。
幸運(yùn)的是犀变,有一個(gè)該項(xiàng)目的分支PyCrytodome 取代了 PyCrypto 妹孙。
PyCrypto文檔: https://pycryptodome.readthedocs.io/en/latest/src/introduction.html
安裝與導(dǎo)入
-
完全替代老的
PyCrypto
庫,你可以這樣安裝:pip install pycryptodome
這種情況下获枝,所有的模塊安裝在
Crypto
包下蠢正。避免同時(shí)安裝
PyCrypto
和PyCryptodome
, 它們相互起沖突省店。因此嚣崭,只有當(dāng)您確定整個(gè)應(yīng)用程序部署在virtualenv中時(shí)笨触,才建議使用此選項(xiàng)。
-
一個(gè)獨(dú)立于老的
PyCrypto
庫的方案雹舀,你可以這樣安裝:pip install pycryptodomex
這種情況下芦劣,所有的模塊安裝在
Cryptodome
包下。PyCrypto
和PyCryptodome
可以共存说榆。
不同操作系統(tǒng)的安裝詳見官方文檔持寄。
案例
DES案例
# DES 使用
import binascii
from Cryptodome.Cipher import DES
key = b'-8B key-' # key 必須是8個(gè)字節(jié)64位
# 創(chuàng)建一個(gè)密碼對象
# iv 參數(shù)也需要是一個(gè)8字節(jié)64位的二進(jìn)制數(shù)的初始化向量
# DES.MOD_OFB加密模式
cipher = DES.new(key, DES.MODE_OFB, iv=b'12345179')
# 待加密數(shù)據(jù)
data = '我是心藍(lán)最帥無敵'.encode()
# 加密
msg = cipher.encrypt(data)
# 輸出二進(jìn)制數(shù)據(jù)
print(msg)
# 輸出16進(jìn)制字符串
print(binascii.b2a_hex(msg))
# 解密過程
# 創(chuàng)建一個(gè)新的密碼對象
# 模式,key娱俺,iv 和加密過程對應(yīng)
cipher2 = DES.new(key, iv=cipher.iv, mode=DES.MODE_OFB)
# 解密
res = cipher2.decrypt(msg)
# 解碼成明文字符串
print(res.decode('utf-8'))
文檔參考:https://pycryptodome.readthedocs.io/en/latest/src/cipher/des.html
DES加密了解就好稍味,幾乎沒人使用了。
3DES案例
# 3DES案例
from Cryptodome.Cipher import DES3
# 需要24個(gè)字節(jié)長度的key荠卷,一般會(huì)隨機(jī)生成
# 本質(zhì)上是三次des的key的串聯(lián)模庐,k1,k2油宜,k3
# 當(dāng)k1=k2=k3時(shí)掂碱,DES3降級(jí)為DES
key = b'12345678qwertyui12345678'
# 創(chuàng)建一個(gè)密碼對象
cipher = DES3.new(key, DES3.MODE_CFB)
# 原數(shù)據(jù)
data = '我是心藍(lán)'.encode()
# 加密
msg = cipher.encrypt(data)
print(msg)
# 解密過程
cipher2 = DES3.new(key, DES3.MODE_CFB, iv=cipher.iv)
# 解密
res = cipher2.decrypt(msg)
print(res.decode('utf-8'))
文檔參考:https://pycryptodome.readthedocs.io/en/latest/src/cipher/des3.html
AES案例
# AES案例
from Cryptodome.Cipher import AES
# 16個(gè)字節(jié)的密碼
key = b'1234567890123456'
# 創(chuàng)建加密對象
cipher = AES.new(key, AES.MODE_EAX)
data = '我是心藍(lán)'.encode()
# 加密
msg = cipher.encrypt(data)
print(msg)
# 解密 過程
# 創(chuàng)建一個(gè)新的密碼對象
cipher2 = AES.new(key, AES.MODE_EAX, nonce=cipher.nonce)
res = cipher2.decrypt(msg)
print(res.decode('utf-8'))
文檔參考:https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html
二、非對稱加密
1.定義
非對稱加密算法是一種密鑰的保密方法慎冤。
非對稱加密算法需要兩個(gè)密鑰:公開密鑰(publickey:簡稱公鑰)和私有密鑰(privatekey:簡稱私鑰)疼燥。公鑰與私鑰是一對,如果用公鑰對數(shù)據(jù)進(jìn)行加密蚁堤,只有用對應(yīng)的私鑰才能解密醉者。因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作非對稱加密算法披诗。
2.特點(diǎn)
非對稱密碼體制的特點(diǎn):算法強(qiáng)度復(fù)雜撬即、安全性依賴于算法與密鑰但是由于其算法復(fù)雜,而使得加密解密速度沒有對稱加密解密的速度快呈队。對稱密碼體制中只有一種密鑰剥槐,并且是非公開的,如果要解密就得讓對方知道密鑰宪摧。所以保證其安全性就是保證密鑰的安全粒竖,而非對稱密鑰體制有兩種密鑰,其中一個(gè)是公開的几于,這樣就可以不需要像對稱密碼那樣傳輸對方的密鑰了蕊苗。這樣安全性就大了很多。
事實(shí)上孩革,公鑰加密算法很少用于數(shù)據(jù)加密岁歉,它通常只是用來做身份認(rèn)證,因?yàn)樗拿荑€太長,加密速度太慢--公鑰加密算法的速度甚至比對稱加密算法的速度慢上3個(gè)數(shù)量級(jí)(1000倍)锅移。
3.工作原理
- A要向B發(fā)送信息熔掺,A和B都要產(chǎn)生一對用于加密和解密的公鑰和私鑰
- A的私鑰保密,A的公鑰告訴B非剃;B的私鑰保密置逻,B的公鑰告訴A。
- A要給B發(fā)送信息時(shí)备绽,A用B的公鑰加密信息券坞,因?yàn)锳知道B的公鑰。
- A將這個(gè)消息發(fā)給B(已經(jīng)用B的公鑰加密消息)肺素。
- B收到這個(gè)消息后恨锚,B用自己的私鑰解密A的消息。其他所有收到這個(gè)報(bào)文的人都無法解密倍靡,因?yàn)橹挥蠦才有B的私鑰猴伶。
4.常用算法
非對稱加密最常用,最廣泛的算法是:RSA
RSA
簡介
RSA加密算法是一種非對稱加密算法塌西。在公開密鑰加密和電子商業(yè)中RSA被廣泛使用他挎。RSA是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的捡需。當(dāng)時(shí)他們?nèi)硕荚?a target="_blank">麻省理工學(xué)院工作办桨。RSA就是他們?nèi)诵帐祥_頭字母拼在一起組成的。今天只有短的RSA鑰匙才可能被強(qiáng)力方式解破站辉。到目前為止呢撞,世界上還沒有任何可靠的攻擊RSA算法的方式。只要其鑰匙的長度足夠長庵寞,用RSA加密的信息實(shí)際上是不能被解破的狸相。
算法原理
RSA算法基于一個(gè)十分簡單的數(shù)論事實(shí):將兩個(gè)大質(zhì)數(shù)相乘十分容易,但是想要對其乘積進(jìn)行因式分解卻極其困難捐川,因此可以將乘積公開作為加密密鑰。
RSA的加解密過程非常簡單:
公鑰 | (n, e) |
私鑰 | (n, d) |
加密 | 密文 = (明文^e)%n |
解密 | 明文 = (密文^d)%n |
RSA加密算法實(shí)現(xiàn)過程:https://www.cnblogs.com/coolYuan/p/9168284.html
RSA加密算法原理:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
RSA加密算法python實(shí)現(xiàn):https://www.jb51.net/article/138018.htm
在python中使用
生成RSA密鑰
# 生成RSA密鑰
from Cryptodome.PublicKey import RSA
key = RSA.generate(2048)
private_key = key.export_key()
print(private_key)
file_out = open("private.pem", "wb")
file_out.write(private_key)
public_key = key.publickey().export_key()
print(public_key)
file_out = open("receiver.pem", "wb")
file_out.write(public_key)
使用RSA加密數(shù)據(jù)
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_OAEP
data = '我是心藍(lán)哈哈哈哈'.encode()
# 導(dǎo)入公鑰
recipient_key = RSA.import_key(open("receiver.pem").read())
# 創(chuàng)建一個(gè)密碼對象
cipher_rsa = PKCS1_OAEP.new(recipient_key)
# 加密
msg = cipher_rsa.encrypt(data)
print(msg)
使用RSA解密數(shù)據(jù)
# 接上面代碼
# 導(dǎo)入私鑰
private_key = RSA.import_key(open("private.pem").read())
cipher_rsa = PKCS1_OAEP.new(private_key)
# 解密
res = cipher_rsa.decrypt(msg)
print(res.decode('utf-8'))
爬蟲中的用法
有些網(wǎng)站會(huì)在請求過程中發(fā)送公鑰逸尖,然后加密參數(shù)后傳回后臺(tái)來實(shí)現(xiàn)數(shù)據(jù)的加密古沥。
import binascii
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_OAEP
data = '我是心藍(lán)哈哈哈哈'.encode()
# 網(wǎng)頁上收到的n值
pubkey_n = '8d7e6949d411ce14d7d233d7160f5b2cc753930caba4d5ad24f923a505253b9c39b09a059732250e56c594d735077cfcb0c3508e9f544f101bdf7e97fe1b0d97f273468264b8b24caaa2a90cd9708a417c51cf8ba35444d37c514a0490441a773ccb121034f29748763c6c4f76eb0303559c57071fd89234d140c8bb965f9725'
# e常常為65537
pbukey_e = 65537
# 生成公鑰
recipient_key = RSA.RsaKey(n=int(pubkey_n, 16), e=65537)
# 創(chuàng)建rsa對象
cipher_rsa = PKCS1_OAEP.new(recipient_key)
# 加密數(shù)據(jù)
msg = cipher_rsa.encrypt(data)
print(msg)
# 輸出16進(jìn)制字符串
print(binascii.b2a_hex(msg))
三、Hash算法
1.定義
一種算法的名稱娇跟,一般翻譯為哈希岩齿,或者散列。
它是把任意長度的輸入通過散列算法轉(zhuǎn)變成固定長度的輸出苞俘,該輸出就是散列值盹沈。
2.特點(diǎn)
- 不可逆: 無法通過散列值還原原來的數(shù)據(jù)
- 定長輸出:無論輸入的原始數(shù)據(jù)有多長,結(jié)果長度相同
- 抗修改:輸入微小的改變吃谣,會(huì)引起結(jié)果的巨大改變
- 強(qiáng)碰撞性:很難找到兩段不同的數(shù)據(jù)乞封,使他們產(chǎn)生相同的hash值
3.應(yīng)用領(lǐng)域
- 一致性驗(yàn)證
- 數(shù)字簽名
- 安全訪問認(rèn)證
4.常用算法
md5
MD5消息摘要算法(英語:MD5 Message-Digest Algorithm)做裙,一種被廣泛使用的密碼散列函數(shù),可以產(chǎn)生出一個(gè)128位(16字節(jié))的散列值(hash value)肃晚,用于確保信息傳輸完整一致锚贱。
SHA家族
安全散列算法(英語:Secure Hash Algorithm,縮寫為SHA)是一個(gè)密碼散列函數(shù)家族关串,是FIPS所認(rèn)證的安全散列算法拧廊。能計(jì)算出一個(gè)數(shù)字消息所對應(yīng)到的,長度固定的字符串(又稱消息摘要)的算法晋修。
SHA家族的五個(gè)算法吧碾,分別是SHA-1、SHA-224墓卦、SHA-256滤港、SHA-384,和SHA-512趴拧,由美國國家安全局(NSA)所設(shè)計(jì)溅漾,并由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)發(fā)布;是美國的政府標(biāo)準(zhǔn)著榴。后四者有時(shí)并稱為SHA-2添履。
5.在python中使用
import hashlib
# sha1 sha256 sha512 一樣的用法
info = '心藍(lán)老師最帥!'
m = hashlib.md5(info.encode()) # 注意傳入數(shù)據(jù)一定是二進(jìn)制數(shù)據(jù)
res1 = m.hexdigest() # 輸出散列字符串
print(res1)
res2 = m.digest() # 輸出二進(jìn)制數(shù)據(jù)
# 大數(shù)據(jù)的hash
big_m = hashlib.md5()
with open('movie.avi', 'rb') as f:
for line in f:
big_m.update(line) # 循環(huán)追加
print(big_m.hexdigest())
作業(yè)
將RSA的加密過程通過面向?qū)ο蟮姆绞綄懗梢粋€(gè)類脑又,封裝起來暮胧。
只需要傳入一些參數(shù)就可以進(jìn)行加密。
from Cryptodome.Cipher import AES, PKCS1_OAEP
from Cryptodome.PublicKey import RSA
class Rsa:
def __init__(self, pubkey, e=65537):
"""
create a Rsa object
:param pubkey:
public key
It can be an integer or a string.
When it is a string, its format is either
a hexadecimal string or a PEM format
:param e:
The general value is 65537.
"""
if isinstance(pubkey, int):
self.key = RSA.RsaKey(n=pubkey, e=e)
else:
if not isinstance(pubkey, str):
raise ValueError('pubkey must be str or int.')
if '----' in pubkey:
try:
self.key = RSA.import_key(pubkey)
except Exception as e:
print(e)
else:
if pubkey == pubkey.lower():
pubkey = int(pubkey, 16)
self.key = RSA.RsaKey(n=pubkey, e=e)
else:
pubkey = '-----BEGIN PUBLIC KEY-----\n' + pubkey + '\n-----END PUBLIC KEY-----'
try:
self.key = RSA.import_key(pubkey)
except Exception as e:
print(e)
def encrypt(self, data):
"""
encrypted data by rsa
:param data: Plaintext
:return: Binary ciphertext
"""
cipher_rsa = PKCS1_OAEP.new(self.key)
return cipher_rsa.encrypt(data)
class Aes:
def __init__(self, key):
"""
create a Aes object
:param key: key used for encryption
"""
if len(key) not in (16, 24, 32):
raise ValueError('Incorrect AES key length.')
if not isinstance(key, bytes):
raise ValueError('The key must be bytes.')
self.key = key
def encrypt(self, data, mode, *args, **kwargs):
"""
encrypted data by aes
:param data: Plaintext
:param mode: Encryption mode
:param args:
:param kwargs:
:return: Binary ciphertext
"""
cipher = AES.new(self.key, mode=mode, *args, **kwargs)
if not isinstance(data, bytes):
raise ValueError('The data must be bytes.')
return cipher.encrypt(data)
if __name__ == '__main__':
rsa = Rsa(pubkey=open("receiver.pem").read())
res = rsa.encrypt('我是心藍(lán)'.encode())
print(res)
print(len(res))