午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

AES加密解密的基本原理與Python爬取AES加密接口

 小小明代碼實(shí)體 2021-11-30

大家好,我是小小明,今天我要帶大家學(xué)習(xí)AES加密的基本原理,并爬取一個(gè)經(jīng)過(guò)AES加密的接口。一起來(lái)學(xué)習(xí)吧!

AES編碼解碼基礎(chǔ)

AES簡(jiǎn)介

AES(Advanced Encryption Standard)是取代其前任標(biāo)準(zhǔn)(DES)而成為新標(biāo)準(zhǔn)的一種對(duì)稱(chēng)加密算法。
DES因?yàn)閼?yīng)用時(shí)間較早,密文已經(jīng)可以在短時(shí)間內(nèi)被破譯,所以現(xiàn)在已經(jīng)基本不再使用。

被選定為AES的Rijndael算法

全世界的企業(yè)和密碼學(xué)家提交了多個(gè)對(duì)稱(chēng)密碼算法作為AES的候選,最終在2000年從這些候選算法中選出了一種名為 Rijndael的對(duì)稱(chēng)密碼算法,并將其確定為了AES。

Rijndael分組密碼算法,會(huì)多次重復(fù)以下4個(gè)步驟:SubBytes、ShiftRows、MixColumnsAddRoundkey。

  1. SubBytes:將每一組16字節(jié)的明文數(shù)據(jù)以每個(gè)字節(jié)的值(0-255)為索引,從一張擁有256個(gè)值得表中查找對(duì)應(yīng)值進(jìn)行替換(類(lèi)似Base64的查表替換)。
  2. ShiftRows:將以4字節(jié)為單位的行按照一定的規(guī)則向左平移,且每一行平移的字節(jié)數(shù)不同。
  3. MixColumns:對(duì)一個(gè)4字節(jié)的值進(jìn)行位運(yùn)算,將其變?yōu)榱硪粋€(gè)4字節(jié)的值。
  4. AddRoundkey:將MixColumns的輸出與輪密鑰進(jìn)行xor異或。

Rijndael的分組長(zhǎng)度和密鑰長(zhǎng)度可以分別以32比特為單位在128比特到256比特的范圍內(nèi)進(jìn)行選擇。不過(guò)在AES的規(guī)格中,分組長(zhǎng)度固定為128比特,密鑰長(zhǎng)度只有128、192和256比特三種。

流密碼與分組密碼

對(duì)數(shù)據(jù)流進(jìn)行連續(xù)處理的密碼算法稱(chēng)為流密碼,流密碼一般以1bit、8bit、32bit等單位進(jìn)行加密解密運(yùn)算。
流密碼需要對(duì)一串?dāng)?shù)據(jù)進(jìn)行連續(xù)處理,因此需要保持內(nèi)部狀態(tài)。

分組密碼則每次只處理特定長(zhǎng)度的一塊數(shù)據(jù),一個(gè)分組的比特?cái)?shù)(bit)就稱(chēng)為 分組長(zhǎng)度。DES、AES等多數(shù)對(duì)稱(chēng)加密算法都屬于分組密碼。

AES的分組長(zhǎng)度是128bit(16字節(jié)),因此一次可以加密128bit的明文,并生成128bit的密文。每次處理完一個(gè)分組就結(jié)束了,不需要通過(guò)內(nèi)部狀態(tài)來(lái)記錄加密的進(jìn)度。

分組密碼算法只能加密固定長(zhǎng)度的分組數(shù)據(jù),對(duì)于一段很長(zhǎng)的明文,需要不斷迭代出固定的長(zhǎng)度進(jìn)行加密;對(duì)于最后不夠固定長(zhǎng)度的明文需要補(bǔ)齊至固定長(zhǎng)度,最終全部加密。

AES常用的分組模式有:

  • ECB模式:Electronic CodeBook mode(電子密碼本模式)
  • CBC模式:Cipher Block Chaining mode(密碼分組鏈接模式)
  • CFB模式:Cipher FeedBack mode(密文反饋模式)
  • OFB模式:Output FeedBack mode(輸出反饋模式)
  • CTR模式:Counter mode(計(jì)數(shù)器模式)

目前筆者只見(jiàn)過(guò)ECBCBC兩種密碼模式,下來(lái)針對(duì)這兩種模式介紹:

ECB模式

ECB模式的全稱(chēng)是 Electronic CodeBook mode(電子密碼本模式)。在ECB模式中,將明文分組加密之后的結(jié)果將直接成為密文分組。

加密:

image-20210630102059605

解密:

image-20210630102217830

使用ECB模式加密時(shí),相同的明文分組會(huì)被轉(zhuǎn)換為相同的密文分組??梢岳斫鉃槭且粋€(gè)巨大的“明文分組→密文分組”的對(duì)應(yīng)表,因此ECB模式也稱(chēng)為電子密碼本模式

當(dāng)最后一個(gè)明文分組的內(nèi)容小于分組長(zhǎng)度時(shí),需要用一些特定的數(shù)據(jù)進(jìn)行填充( padding)。

注意:ECB模式最簡(jiǎn)單的一種模式,明文分組與密文分組是一一對(duì)應(yīng)的關(guān)系,只要觀察一下密文,就可以知道明文中存在怎樣的重復(fù)組合,并可以以此為線索來(lái)破譯密碼,因此ECB模式安全性也是最低的。

CBC模式

CBC模式的全稱(chēng)是Cipher Block Chaining(密文分組鏈接)模式,因?yàn)槊芪姆纸M是像鏈條一樣相互連接在一起的。

在CBC模式中,首先將密文分組與前一個(gè)密文分組進(jìn)行XOR運(yùn)算,然后再進(jìn)行加密。

當(dāng)加密第一個(gè)明文分組時(shí),由于不存在“前一個(gè)密文分組”,因此需要事先準(zhǔn)備一個(gè)(長(zhǎng)度為一個(gè)分組的隨機(jī)數(shù)據(jù))來(lái)代替“前一個(gè)密文分組”,這個(gè)隨機(jī)數(shù)據(jù)就稱(chēng)為:初始化向量(IV)。

加密:

image-20210630102909771

解密:

image-20210630102928856

CBC模式明文分組在加密之前一定會(huì)與“前一個(gè)密文分組”進(jìn)行XOR運(yùn)算,因此即便明文分組1和2的值是相等的,密文分組1和2的值也是不相等的。ECB模式的缺陷也就不存在了。

參考:《圖解密碼技術(shù)》

AES支持的填充方式

前面說(shuō)到當(dāng)最后一個(gè)明文分組的內(nèi)容小于分組長(zhǎng)度時(shí),需要用一些特定的數(shù)據(jù)進(jìn)行填充( padding)。

AES支持支持的填充方式:

  • NoPadding
  • ISO10126Padding
  • Zeros
  • PKCS7

簡(jiǎn)單介紹一下:

NoPadding:表示不填充。

ISO10126Padding:填充字節(jié)序列的最后一個(gè)字節(jié)填充字節(jié)序列的長(zhǎng)度,其余字節(jié)填充隨機(jī)數(shù)據(jù)。

示例(塊長(zhǎng)度為 8,數(shù)據(jù)長(zhǎng)度為 9):

數(shù)據(jù): FF FF FF FF FF FF FF FF FF

ISO10126 填充: FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07

Zeros : 填充字符串由設(shè)置為零的字節(jié)組成。

PKCS7 :填充字節(jié)序列,每個(gè)字節(jié)填充該字節(jié)序列的長(zhǎng)度。

示例(塊長(zhǎng)度為 8,數(shù)據(jù)長(zhǎng)度為 9):

數(shù)據(jù): FF FF FF FF FF FF FF FF FF

ISO10126 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07

PKCS5與PKCS7的區(qū)別

在PKCS5Padding中,明確定義Block的大小是8位,而在PKCS7Padding定義中,對(duì)于塊的大小可以在1-255之間,填充值的算法都是一樣的。PKCS7填充方式在設(shè)定塊長(zhǎng)度為 8時(shí),與 PKCS5 填充方式等價(jià)。

Python爬取ECB加密數(shù)據(jù)示例

這次我們爬取的網(wǎng)站是:https://www./data/market-ratio/

目的是抓取比特幣市值占比數(shù)據(jù):

image-20210630115826283

接口地址https://gate./w1/home/head_pair

發(fā)現(xiàn)一個(gè)需要校驗(yàn)的加密字段,現(xiàn)在我們需要對(duì)它進(jìn)行JS逆向分析:

image-20210630115947722

根據(jù)參數(shù)名secretKeyVersion我們可以嘗試全局搜索。

控制臺(tái)全局搜索快捷鍵是:Ctrl+ Shift+ F

image-20210630134203035

由于并沒(méi)有做很復(fù)雜的JavaScript混淆,直接搜索到了對(duì)應(yīng)的加密代碼。對(duì)于這種json數(shù)據(jù),一般搜索JSON.stringify都能找到相應(yīng)的加密入口。

下面我們?yōu)閟ign打上斷點(diǎn),游覽器一步步跟蹤。

image-20210630134727019

僅僅進(jìn)入第一層,我們已經(jīng)清楚了加密算法是AES,采用ECB模式,Pkcs7填充方式,密鑰是WTAHAPPYACTIVITY。

被加密的文本包含appId、timestamp和serverCode三個(gè)參數(shù)。

理解這些我們就可以開(kāi)始編碼了,首先獲取參數(shù)e:

import json
import time

e = json.dumps({"appId": "1", "timestamp": str(
    int(time.time())), "serverCode": "0"}, separators=(',', ':'))
e
'{"appId":"1","timestamp":"1625033091","serverCode":"0"}'

加密后tostring方法通過(guò)簡(jiǎn)單的追蹤未找到具體的實(shí)現(xiàn),但根據(jù)最終結(jié)果可以推測(cè)是經(jīng)過(guò)了base64加密,于是對(duì)上面的json參數(shù)加密并base64編碼再進(jìn)行相應(yīng)的文本替換:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

text_pad = pad(e.encode('utf-8'), AES.block_size, style='pkcs7')
key = b'WTAHAPPYACTIVITY'
aes = AES.new(key, AES.MODE_ECB)
text = base64.encodebytes(aes.encrypt(text_pad)).decode('utf-8')
text.replace("/", "_").replace("+", "-")
'gDt1nQ3Ay458FG_Xj-Aum4u82nFPsLr55DMo8rUM2gslpKNcGY8DuHqxHUQB1nzxTWeDNrlOJiri\nmPSo2PO0DQ==\n'

結(jié)果形式已經(jīng)與前端的參數(shù)大致一致,但多了\n換行符。雖然不清楚具體機(jī)制,我們繼續(xù)把它替換掉即可,最終代碼為:

import requests
import json
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import time
import pandas as pd


def encrypt(text):
    key = b'WTAHAPPYACTIVITY'
    aes = AES.new(key, AES.MODE_ECB)
    text_pad = pad(text.encode('utf-8'), AES.block_size, style='pkcs7')
    encrypt_aes = aes.encrypt(text_pad)
    encrypted_text = base64.encodebytes(encrypt_aes).decode('utf-8')
    return encrypted_text.replace("\n", "").replace("/", "_").replace("+", "-")


def get_param():
    return json.dumps({"appId": "1", "timestamp": str(
        int(time.time())), "serverCode": "0"}, separators=(',', ':'))


text = get_param()
print(text)
print(encrypt(text))
{"appId":"1","timestamp":"1625034433","serverCode":"0"}
gDt1nQ3Ay458FG_Xj-Aum4u82nFPsLr55DMo8rUM2gu7NrP6hBq4jYMFqd9lgylaTWeDNrlOJirimPSo2PO0DQ==

然后我們就可以直接爬取接口的數(shù)據(jù)了:

header = {
    "Accept-Encoding": "gzip",
    "Authorization": "",
    "Source-Site": "qkl123",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36",
}

sign = encrypt(get_param())
header["Authorization"] = json.dumps({"secretKeyVersion": 1, "sign": sign})
r = requests.get("https://gate./w1/home/head_pair", headers=header)
df = pd.DataFrame(r.json()['pairs'])
df

image-20210630143729720

可以看到已經(jīng)成功的抓取到了相應(yīng)的數(shù)據(jù)。

對(duì)于pair_ext_info那列可以使用字典分列,擴(kuò)展到當(dāng)前表中:

df = pd.concat([df.drop(columns="pair_ext_info"),
               pd.json_normalize(df.pair_ext_info)], axis=1)

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多