關注微信公眾號:K哥爬蟲,QQ交流群:808574309,持續分享爬蟲進階、JS/安卓逆向等技術乾貨!
【01x00】 簡介
國密即國家密碼局認定的國產加密演算法,爬蟲工程師在做 JS 逆向的時候,會遇到各種各樣的加密演算法,其中 RSA、AES、SHA 等演算法是最常見的,這些演算法都是國外的,在 K 哥以前的文章裡也有介紹:《【爬蟲知識】爬蟲常見加密解密演算法》
事實上從 2010 年開始,我國國家密碼管理局就已經開始陸續釋出了一系列國產加密演算法,這其中就包括 SM1、SM2、SM3 、SM4、SM7、SM9、ZUC(祖沖之加密演算法)等,SM 代表商密,即商業密碼,是指用於商業的、不涉及國家祕密的密碼技術。SM1 和 SM7 的演算法不公開,其餘演算法都已成為 ISO/IEC 國際標準。
在這些國產加密演算法中,SM2、SM3、SM4 三種加密演算法是比較常見的,在爬取部分 gov 網站時,也可能會遇到這些演算法,所以作為爬蟲工程師是有必要了解一下這些演算法的,如下圖所示某 gov 網站就使用了 SM2 和 SM4 加密演算法:
【02x00】演算法概述
演算法名稱 | 演算法類別 | 應用領域 | 特點 |
---|---|---|---|
SM1 | 對稱(分組)加密演算法 | 晶片 | 分組長度、金鑰長度均為 128 位元 |
SM2 | 非對稱(基於橢圓曲線 ECC)加密演算法 | 資料加密 | ECC 橢圓曲線密碼機制 256 位,相比 RSA 處理速度快,消耗更少 |
SM3 | 雜湊(hash)函式演算法 | 完整性校驗 | 安全性及效率與 SHA-256 相當,壓縮函式更復雜 |
SM4 | 對稱(分組)加密演算法 | 資料加密和區域網產品 | 分組長度、金鑰長度均為 128 位元,計算輪數多 |
SM7 | 對稱(分組)加密演算法 | 非接觸式 IC 卡 | 分組長度、金鑰長度均為 128 位元 |
SM9 | 標識加密演算法(IBE) | 端對端離線安全通訊 | 加密強度等同於 3072 位金鑰的 RSA 加密演算法 |
ZUC | 對稱(序列)加密演算法 | 行動通訊 4G 網路 | 流密碼 |
【03x00】演算法詳解
【03x01】SM1 分組加密演算法
SM1 為分組加密演算法,對稱加密,分組長度和金鑰長度都為 128 位,故對訊息進行加解密時,若訊息長度過長,需要進行分組,要訊息長度不足,則要進行填充。演算法安全保密強度及相關軟硬體實現效能與 AES 相當,該演算法不公開,僅以 IP 核的形式存在於晶片中,呼叫該演算法時,需要通過加密晶片的介面進行呼叫,採用該演算法已經研製了系列晶片、智慧 IC 卡、智慧密碼鑰匙、加密卡、加密機等安全產品,廣泛應用於電子政務、電子商務及國民經濟的各個應用領域(包括國家政務通、警務通等重要領域),一般瞭解的人比較少,爬蟲工程師也不會遇到這種加密演算法。
【03x02】SM2 橢圓曲線公鑰加密演算法
SM2 為橢圓曲線(ECC)公鑰加密演算法,非對稱加密,SM2 演算法和 RSA 演算法都是公鑰加密演算法,SM2 演算法是一種更先進安全的演算法,在我們國家商用密碼體系中被用來替換 RSA 演算法,在不少 gov 網站會見到此類加密演算法。我國學者對橢圓曲線密碼的研究從 20 世紀 80 年代開始,目前已取得不少成果,SM2 橢圓曲線公鑰密碼演算法比 RSA 演算法有以下優勢:
SM2 | RSA | |
---|---|---|
安全性 | 256 位 SM2 強度已超過 RSA-2048 | 一般 |
演算法結構 | 基本橢圓曲線(ECC) | 基於特殊的可逆模冪運算 |
計算複雜度 | 完全指數級 | 亞指數級 |
儲存空間(金鑰長度) | 192-256 bit | 2048-4096 bit |
祕鑰生成速度 | 較 RSA 演算法快百倍以上 | 慢 |
解密加密速度 | 較快 | 一般 |
【03x03】SM3 雜湊演算法
SM3 為密碼雜湊演算法,採用密碼雜湊(hash)函式標準,用於替代 MD5/SHA-1/SHA-2 等國際演算法,是在 SHA-256 基礎上改進實現的一種演算法,訊息分組長度為 512 位,摘要值長度為 256 位,其中使用了異或、模、模加、移位、與、或、非運算,由填充、迭代過程、訊息擴充套件和壓縮函式所構成。在商用密碼體系中,SM3 主要用於數字簽名及驗證、訊息認證碼生成及驗證、隨機數生成等。據國家密碼管理局表示,其安全性及效率要高於 MD5 演算法和 SHA-1 演算法,與 SHA-256 相當。
【03x04】SM4 分組加密演算法
SM4 為無線區域網標準的分組加密演算法,對稱加密,用於替代 DES/AES 等國際演算法,SM4 演算法與 AES 演算法具有相同的金鑰長度和分組長度,均為 128 位,故對訊息進行加解密時,若訊息長度過長,需要進行分組,要訊息長度不足,則要進行填充。加密演算法與金鑰擴充套件演算法都採用 32 輪非線性迭代結構,解密演算法與加密演算法的結構相同,只是輪金鑰的使用順序相反,解密輪金鑰是加密輪金鑰的逆序。
SM4 | DES | AES | |
---|---|---|---|
計算輪數 | 32 | 16(3DES 為 16*3) | 10/12/14 |
密碼部件 | S 盒、非線性變換、線性變換、合成變換 | 標準算術和邏輯運算、先替換後置換,不含線性變換 | S 盒、行移位變換、列混合變換、圈金鑰加變換(AddRoundKey) |
【03x05】SM7 分組加密演算法
SM7 為分組加密演算法,對稱加密,該演算法不公開,應用包括身份識別類應用(非接觸式 IC 卡、門禁卡、工作證、參賽證等),票務類應用(大型賽事門票、展會門票等),支付與通卡類應用(積分消費卡、校園一卡通、企業一卡通等)。爬蟲工程師基本上不會遇到此類演算法。
【03x06】SM9 標識加密演算法
SM9 為標識加密演算法(Identity-Based Cryptography),非對稱加密,標識加密將使用者的標識(如微訊號、郵件地址、手機號碼、QQ 號等)作為公鑰,省略了交換數字證照和公鑰過程,使得安全系統變得易於部署和管理,適用於網際網路應用的各種新興應用的安全保障,如基於雲技術的密碼服務、電子郵件安全、智慧終端保護、物聯網安全、雲端儲存安全等等。這些安全應用可採用手機號碼或郵件地址作為公鑰,實現資料加密、身份認證、通話加密、通道加密等。在商用密碼體系中,SM9 主要用於使用者的身份認證,據新華網公開報導,SM9 的加密強度等同於 3072 位金鑰的 RSA 加密演算法。
【03x07】ZUC 祖沖之演算法
ZUC 為流密碼演算法,對稱加密,該機密性演算法可適用於 3GPP LTE 通訊中的加密和解密,該演算法包括祖沖之演算法(ZUC)、機密性演算法(128-EEA3)和完整性演算法(128-EIA3)三個部分。已經被國際組織 3GPP 推薦為 4G 無線通訊的第三套國際加密和完整性標準的候選演算法。
【04x00】程式語言實現
【04x01】Python 語言實現
在 Python 裡面並沒有比較官方的庫來實現國密演算法,這裡僅列出了其中兩個較為完善的第三方庫,需要注意的是,SM1 和 SM7 演算法不公開,目前大多庫僅實現了 SM2、SM3、SM4 三種密演算法。
- snowland-smx-python:https://gitee.com/snowlandltd...
- gmssl:https://github.com/duanhongyi...
- gmssl-python:https://github.com/gongxian-d...
其中 gmssl-python 是 gmssl 的改進版,gmssl-python 新增支援了 SM9 演算法,不過截止本文編寫時,gmssl-python 並未釋出 pypi,也未 PR 到 gmssl,使用 pip install gmssl
安裝的 gmssl 不支援 SM9 演算法。若要使用 SM9 演算法,可下載 gmssl-python 原始碼手動安裝。
以 gmssl 的 SM2 演算法為例,實現如下(其他演算法和詳細用法可參考其官方文件):
SM2 加密(encrypt)和解密(decrypt):
from gmssl import sm2
# 16 進位制的公鑰和私鑰
private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207'
sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key)
# 待加密資料和加密後資料為 bytes 型別
data = b"this is the data to be encrypted"
enc_data = sm2_crypt.encrypt(data)
dec_data = sm2_crypt.decrypt(enc_data)
print('enc_data: ', enc_data.hex())
print('dec_data: ', dec_data)
# enc_data: 3cb96dd2e0b6c24df8e22a5da3951d061a6ee6ce99f46a446426feca83e501073288b1553ca8d91fad79054e26696a27c982492466dafb5ed06a573fb09947f2aed8dfae243b095ab88115c584bb6f0814efe2f338a00de42b244c99698e81c7913c1d82b7609557677a36681dd10b646229350ad0261b51ca5ed6030d660947
# dec_data: b'this is the data to be encrypted'
SM2 簽名(sign)和校驗(verify):
from gmssl import sm2, func
# 16 進位制的公鑰和私鑰
private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207'
sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key)
# 待簽名資料為 bytes 型別
data = b"this is the data to be signed"
random_hex_str = func.random_hex(sm2_crypt.para_len)
# 16 進位制
sign = sm2_crypt.sign(data, random_hex_str)
verify = sm2_crypt.verify(sign, data)
print('sign: ', sign)
print('verify: ', verify)
# sign: 45cfe5306b1a87cf5d0034ef6712babdd1d98547e75bcf89a17f3bcb617150a3f111ab05597601bab8c41e2b980754b74ebe9a169a59db37d549569910ae273a
# verify: True
【04x02】JavaScript 語言實現
在 JavaScript 中已有比較成熟的實現庫,這裡推薦 sm-crypto,目前支援 SM2、SM3 和 SM4,需要注意的是,SM2 非對稱加密的結果由 C1、C2、C3 三部分組成,其中 C1 是生成隨機數的計算出的橢圓曲線點,C2 是密文資料,C3 是 SM3 的摘要值,最開始的國密標準的結果是按 C1C2C3 順序的,新標準的是按 C1C3C2 順序存放的,sm-crypto 支援設定 cipherMode,也就是 C1C2C3 的排列順序。
sm-crypto:https://www.npmjs.com/package...
以 SM2 演算法為例,實現如下(其他演算法和詳細用法可參考其官方文件):
SM2 加密(encrypt)和解密(decrypt):
const sm2 = require('sm-crypto').sm2
// 1 - C1C3C2,0 - C1C2C3,預設為1
const cipherMode = 1
// 獲取金鑰對
let keypair = sm2.generateKeyPairHex()
let publicKey = keypair.publicKey // 公鑰
let privateKey = keypair.privateKey // 私鑰
let msgString = "this is the data to be encrypted"
let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode) // 加密結果
let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode) // 解密結果
console.log("encryptData: ", encryptData)
console.log("decryptData: ", decryptData)
// encryptData: ddf261103fae06d0efe20ea0fe0d82bcc170e8efd8eeae24e9559b3835993f0ed2acb8ba6782fc21941ee74ca453d77664a5cb7dbb91517e6a3b0c27db7ce587ae7af54f8df48d7fa822b7062e2af66c112aa57de94d12ba28e5ba96bf4439d299b41da4a5282d054696adc64156d248049d1eb1d0af28d76b542fe8a95d427e
// decryptData: this is the data to be encrypted
SM2 簽名(sign)和校驗(verify):
const sm2 = require('sm-crypto').sm2
// 獲取金鑰對
let keypair = sm2.generateKeyPairHex()
let publicKey = keypair.publicKey // 公鑰
let privateKey = keypair.privateKey // 私鑰
// 純簽名 + 生成橢圓曲線點
let msgString = "this is the data to be signed"
let sigValueHex = sm2.doSignature(msgString, privateKey) // 簽名
let verifyResult = sm2.doVerifySignature(msgString, sigValueHex, publicKey) // 驗簽結果
console.log("sigValueHex: ", sigValueHex)
console.log("verifyResult: ", verifyResult)
// sigValueHex: 924cbb9f2b5adb554ef77129ff1e3a00b2da42017ad3ec2f806d824a77646987ba8c8c4fb94576c38bc11ae69cc98ebbb40b5d47715171ec7dcea913dfc6ccc1
// verifyResult: true
【04x03】其他語言實現以及參考資料
Java 語言實現:
- Go 語言實現:https://github.com/tjfoc/gmsm
- 開源國密演算法工具箱:http://gmssl.org/
- 國密演算法原始碼下載:http://www.scctc.org.cn/templ...
- 國家密碼管理局:https://www.sca.gov.cn/
- 密碼標準委員會:http://www.gmbz.org.cn/
【05x00】附:GM/T 密碼行業標準
- GM/T 0001.1-2012:祖沖之序列密碼演算法:第1部分:演算法描述
- GM/T 0001.2-2012:祖沖之序列密碼演算法:第2部分:基於祖沖之演算法的機密性演算法
- GM/T 0001.3-2012:祖沖之序列密碼演算法:第3部分:基於祖沖之演算法的完整性演算法
- GM/T 0003.1-2012:SM2 橢圓曲線公鑰密碼演算法第1部分:總則
- GM/T 0003.2-2012:SM2 橢圓曲線公鑰密碼演算法第2部分:數字簽名演算法
- GM/T 0003.3-2012:SM2 橢圓曲線公鑰密碼演算法第3部分:金鑰交換協議
- GM/T 0003.4-2012:SM2 橢圓曲線公鑰密碼演算法第4部分:公鑰加密演算法
- GM/T 0003.5-2012:SM2 橢圓曲線公鑰密碼演算法第5部分:引數定義
- GM/T 0004-2012:SM3 密碼雜湊演算法
- GM/T 0002-2012:SM4 分組密碼演算法
- GM/T 0044.1-2016:SM9 標識密碼演算法 第1部分:總則
- GM/T 0044.2-2016:SM9 標識密碼演算法 第2部分:數字簽名演算法
- GM/T 0044.3-2016:SM9 標識密碼演算法 第3部分:金鑰交換協議
- GM/T 0044.4-2016:SM9 標識密碼演算法 第4部分:金鑰封裝機制和公鑰加密演算法
- GM/T 0044.5-2016:SM9 標識密碼演算法 第5部分:引數定義