Python爬虫学习笔记之对称加密算法剖析
声明:本文章所有演示内容仅供学习交流使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系作者立即删除!
提示:演示内容相关敏感数据已做脱敏处理!
对称加密算法有哪些?
对称加密(加密解密密钥相同):DES、3DES、AES、RC4
简介
对称式加密就是加密和解密使用同一个密钥。信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行加解密了。对称加密算法用来对敏感数据等信息进行加密。
原理-1
常见算法归纳
DES:56位密钥,由于密钥太短,被逐渐被弃用。
AES:有128位、192位、256位密钥,现在比较流行。密钥长、可以增加破解的难度和成本。
加盐模式归纳 ECB模式 全称Electronic Codebook模式,译为电子密码本模式 CBC模式 全称Cipher Block Chaining模式,译为密文分组链接模式 CFB模式 全称Cipher FeedBack模式,译为密文反馈模式 OFB模式 全称Output Feedback模式,译为输出反馈模式。 CTR模式 全称Counter模式,译为计数器模式。
原理-21. DES算法
简介: DES 是一种分组 加密算法 ,他以64位为分组对数据加密。64位一组的明文从算法的一端 输入,64位的密文从另一端输出。 DES 是一个对称算法:加密和解密用的是同一个算法(除 密钥编排不同以外)。
密钥的长度为56位(密钥通常表示为64位的数,但每个第8位都用作奇偶检验,可以忽 略)。密钥可以是任意的56位数,且可以在任意的时候改变。
DES 算法的入口参数有3个:Key,Data,Mode。其中Key为8个字节共64位,是 DES 算法 的工作密钥;Data也为8个字节64位,是要被加密或解密的数据:Mode为 DES 的工作方式,有 两种:加密或解密。
DES算法的工作过程:若Mode为加密,则用Key对数据Data进行加密,生成Data的密码 形式(64位)作为DES的输出结果;若Mode为解密,则用Key对密码形式的数据Data解密,还 原为Data的明码形式(64位)作为DES的输出结果。
简单地说,算法只不过是加密的一种基本技术,DES基本组建分组是这些技术的一种组合 ,他基于密钥作用于明文,这是众所周知的轮(round)。DES有16轮,这意味着要在明文分 组上16次实施相同的组合技术。 mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。 padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。 1.1 JavaScript 实现
DES算法的入口参数有3个 key、DATA、Mode、padding key 为7个字节共56位,是DES算法的工作密钥 Data为8个字节64位,是要被加密或被解密的数据 Mode 为DES的工作方式 padding 为填充模式,如果加密后密文长度如果达不到指定整数倍(8个字节,16个字节),填充 // 引用 crypto-js 加密模块 var CryptoJS = require("crypto-js") function desEncrypt() { var key = CryptoJS.enc.Utf8.parse(desKey), iv = CryptoJS.enc.Utf8.parse(desIv), srcs = CryptoJS.enc.Utf8.parse(text), // CBC 加密模式,Pkcs7 填充方式 encrypted = CryptoJS.DES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } function desDecrypt() { var key = CryptoJS.enc.Utf8.parse(desKey), iv = CryptoJS.enc.Utf8.parse(desIv), srcs = encryptedData, // CBC 加密模式,Pkcs7 填充方式 decrypted = CryptoJS.DES.decrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); } var text = "i am ziyupython" // 待加密对象 var desKey = "123456" // 密钥 var desIv = "ertyhcdsfbdssfwtuew" // 初始向量 var encryptedData = desEncrypt() var decryptedData = desDecrypt() console.log("加密字符串: ", encryptedData) console.log("解密字符串: ", decryptedData) // 加密字符串: 3emnE4fUWAIvhTg4h38VxA== // 解密字符串: i am ziyupython
案例片段分享: var CryptoJS = require("crypto-js") o = { keyHex: CryptoJS.enc.Utf8.parse(Object({ NODE_ENV: "production", VUE_APP_BASE_API: "/pro-api", VUE_APP_CONSTRUCTION_API: "/pro-api-construction", VUE_APP_DEV_FILE_PREVIEW: "/lyjcdFileView/onlinePreview", VUE_APP_FILE_ALL_PATH: "http://www.nuyl.cn:8089", VUE_APP_FILE_PREFIX: "/mygroup", VUE_APP_LAND_API: "/pro-api-land", VUE_APP_PREVIEW_PREFIX: "/lyjcdFileView", VUE_APP_PROCUREMENT_API: "/pro-api-procurement", VUE_APP_WINDOW_TITLE: "", BASE_URL: "/" }).VUE_APP_CUSTOM_KEY || ""), ivHex: CryptoJS.enc.Utf8.parse(Object({ NODE_ENV: "production", VUE_APP_BASE_API: "/pro-api", VUE_APP_CONSTRUCTION_API: "/pro-api-construction", VUE_APP_DEV_FILE_PREVIEW: "/lyjcdFileView/onlinePreview", VUE_APP_FILE_ALL_PATH: "http://www.nuyl.cn:8089", VUE_APP_FILE_PREFIX: "/mygroup", VUE_APP_LAND_API: "/pro-api-land", VUE_APP_PREVIEW_PREFIX: "/lyjcdFileView", VUE_APP_PROCUREMENT_API: "/pro-api-procurement", VUE_APP_WINDOW_TITLE: "", BASE_URL: "/" }).VUE_APP_CUSTOM_IV || "") }; function c(t) { return CryptoJS.DES.encrypt(t, o.keyHex, { iv: o.ivHex, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }).ciphertext.toString() } console.log(c("245"));1.2 Python 实现
PythonDES模块安装:pip install pyDesimport binascii # 加密模式 CBC,填充方式 PAD_PKCS5 from pyDes import des, CBC, PAD_PKCS5 def des_encrypt(key, text, iv): k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5) en = k.encrypt(text, padmode=PAD_PKCS5) return binascii.b2a_hex(en) def des_decrypt(key, text, iv): k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5) de = k.decrypt(binascii.a2b_hex(text), padmode=PAD_PKCS5) return de if __name__ == "__main__": secret_key = "" # 密钥 text = "" # 加密对象 iv = secret_key # 偏移量 secret_str = des_encrypt(secret_key, text, iv) print("加密字符串:", secret_str) clear_str = des_decrypt(secret_key, secret_str, iv) print("解密字符串:", clear_str)1.3 实际案例1.3.1 逆向目标
首页:aHR0cHM6Ly93d3cuZW5kYXRhLmNvbS5jbi9Cb3hPZmZpY2UvQk8vTW9udGgvb25lTW9udGguaHRtbA==
数据:aHR0cHM6Ly93d3cuZW5kYXRhLmNvbS5jbi9BUEkvR2V0RGF0YS5hc2h4 1.3.2 逆向分析使用xhr断点数据地址,进行单步调试
XHR断点调试对应的数据
数据调试
总结:可以看到该站点是对数据用webInstace.shell进行了解密 2. AES算法
环境安装 pip install pycryptodome2.1 算法简介
简介:全称高级加密标准(英文名称:Advanced Encryption Standard),在密码学中又称 Rijndael 加密法,由美国国家标准与技术研究院 (NIST)于 2001 年发布,并在 2002 年成为有效的标准,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的 DES,已经被多方分析且广为全世界所使用,它本身只有一个密钥,即用来实现加密,也用于解密。 mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。 padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。
参数定义: key length(密钥位数,密码长度)AES128,AES192,AES256(128 位、192 位或 256 位) key (密钥,密码)key指的就是密码了,AES128就是128位的,如果位数不够,某些库可能会自动填充到128。 IV (向量)IV称为初始向量,不同的IV加密后的字符串是不同的,加密和解密需要相同的IV。 mode (加密模式)AES分为几种模式,比如ECB,CBC,CFB等等,这些模式除了ECB由于没有使用IV而不太安全,其他模式差别并没有太明显。 padding (填充方式)对于加密解密两端需要使用同一的PADDING模式,大部分PADDING模式为PKCS5, PKCS7, NOPADDING。
加密原理:
AES加密算法采用分组密码体制,每个分组数据的长度为128位16个字节,密钥长度可以是128位16个字节、192位或256位,一共有四种加密模式,我们通常采用需要初始向量IV的CBC模式,初始向量的长度也是128位16个字节。 2.2 JavaScript 实现
类似网站:aHR0cHM6Ly93d3cuZG5zLmNvbS9sb2dpbi5odG1s // 引用 crypto-js 加密模块 var CryptoJS = require("crypto-js") function tripleAesEncrypt() { var key = CryptoJS.enc.Utf8.parse(aesKey), iv = CryptoJS.enc.Utf8.parse(aesIv), srcs = CryptoJS.enc.Utf8.parse(text), // CBC 加密方式,Pkcs7 填充方式 encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } function tripleAesDecrypt() { var key = CryptoJS.enc.Utf8.parse(aesKey), iv = CryptoJS.enc.Utf8.parse(aesIv), srcs = encryptedData, // CBC 加密方式,Pkcs7 填充方式 decrypted = CryptoJS.AES.decrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); } var text = "" // 待加密对象 var aesKey = "" // 密钥,16 倍数 var aesIv = "" // 偏移量,16 倍数 var encryptedData = tripleAesEncrypt() var decryptedData = tripleAesDecrypt() console.log("加密字符串: ", encryptedData) console.log("解密字符串: ", decryptedData)2.3 Python 实现import base64 from Crypto.Cipher import AES # 需要补位,str不是16的倍数那就补足为16的倍数 def add_to_16(value): while len(value) % 16 != 0: value += " " return str.encode(value) # 加密方法 def aes_encrypt(key, t, iv): aes = AES.new(add_to_16(key), AES.MODE_CBC, add_to_16(iv)) # 初始化加密器 encrypt_aes = aes.encrypt(add_to_16(t)) # 先进行 aes 加密 encrypted_text = str(base64.encodebytes(encrypt_aes), encoding="utf-8") # 执行加密并转码返回 bytes return encrypted_text # 解密方法 def aes_decrypt(key, t, iv): aes = AES.new(add_to_16(key), AES.MODE_CBC, add_to_16(iv)) # 初始化加密器 base64_decrypted = base64.decodebytes(t.encode(encoding="utf-8")) # 优先逆向解密 base64 成 bytes decrypted_text = str(aes.decrypt(base64_decrypted), encoding="utf-8").replace(" ", "") # 执行解密密并转码返回str return decrypted_text if __name__ == "__main__": secret_key = "" # 密钥 text = "" # 加密对象 iv = secret_key # 初始向量 encrypted_str = aes_encrypt(secret_key, text, iv) print("加密字符串:", encrypted_str) decrypted_str = aes_decrypt(secret_key, encrypted_str, iv) print("解密字符串:", decrypted_str)
注意: 明文加密要求是16的整数倍 2.4 实际案例2.4.1 逆向目标接口:aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA== 逆向参数: sign: 3976F10977FC65F9CB967AEF79E508BD password: "A7428361DEF118911783F446A129FFCE" 2.4.2 抓包分析
来到某网通的登录页面,随便输入一个账号密码登陆,抓包定位到登录接口为 aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA==,请求头里,有一个 sign,Payload 里,密码 password 被加密处理了。
抓包分析2.4.3 参数逆向1 sign签名处理
首先来看一下请求头的 sign,尝试直接搜索一下,发现并不是经过某些请求返回的数据,观察一下其他请求,可以发现同样有 sign,而且每次请求的值都不一样:
关键字搜索
由此可以初步判断这个值应该是通过 JS 生成的,全局搜索关键字 sign:,可以分别在 request.js、request.ts 两个文件里面看到疑似 sign 赋值的地方,埋下断点调试,成功断下,原理也很简单,时间戳加上一串固定的字符,经过 MD5 加密后再转大写即可。
定位调试
使用 Python 实现: import time import hashlib timestamp = str(int(time.time() * 1000)) sign = hashlib.md5((timestamp + "bdc739ff2dcf").encode(encoding="utf-8")).hexdigest().upper() print(sign)2 password处理
password 是明文密码经过加密后得到的值,如果尝试直接去搜索的话,会发现出来的值非常非常多,要想找到准确的值难度巨大:
可以看到这条请求是 XHR 请求,本次我们使用 XHR 断点的方法来定位具体的加密位置,通过本次案例,我们来学习一下具体是如何跟进调用栈、如何通过上下文来定位具体的加密位置。
切换到 Network 选项卡,找到登陆请求,鼠标移动到 Initiator 选项卡下的 JS 上,可以看到其调用栈,如果站点的加密方式比较简单,没有太多混淆的话,调用栈里面就可以看到login、send、post、encrypt 等等之类的关键词,这种情况下就可以直接点进去,比较容易找到加密的地方,但是大多数站点对于函数名、变量名都做了混淆,和本案例一样,调用栈里面显示的都是一些单个或者多个无规则的字母的函数,无法直接定位,此时就需要我们从最后一个函数往前慢慢找。
跟栈-1
点击进入最后一个函数,即 Y 函数,它位于调用栈的最顶层,表示经过此函数后,浏览器就会发送登录的请求,密码的加密过程已经处理完毕。在此函数埋下断点,可以在右侧的Call Stack 看到调用栈,从下到上,表示的是点击登陆后,先后调用的函数的执行过程:
根据这种思路,一步一步往下跟进调用栈,可以看到在 utils.ts 里面执行了一个匿名函数,其中调用了一个 passwordEncrypt 函数,通过函数名就可以看出基本上就是密码加密的函数了
总结:
在此处埋下断点进行调试,传进来的是明文密码,passwordEncrypt 实际上是调用的 encode.ts 中的 O 函数,跟进 O 函数,引用了 crypto-js 加密模块,很明显的 AES 加密,本地改写一下就OK。
JavaScript 加密代码 CryptoJS = require("crypto-js") const key = CryptoJS.enc.Utf8.parse("20987878990967789009786788978"); const iv = CryptoJS.enc.Utf8.parse("20987878990967789009786788978"); //十六位十六进制数作为密钥偏移量 function getEncryptedPassword(word) { let srcs = CryptoJS.enc.Utf8.parse(word); let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return encrypted.ciphertext.toString().toUpperCase(); } // 测试样例 // console.log(getEncryptedPassword("123457"))
python模拟登录 import time import hashlib import execjs import requests login_url = "aHR0cHM6Ly9nYXRld2F5LmV3dDM2MC5jb20vYXBpL2F1dGhjZW50ZXIvdjIvb2F1dGgvbG9naW4vYWNjb3VudA==" session = requests.session() def get_sign(): timestamp = str(int(time.time()*1000)) sign = hashlib.md5((timestamp + "bdc739ff2dcf").encode(encoding="utf-8")).hexdigest().upper() return sign def get_encrypted_parameter(password): with open("encrypt.js", "r", encoding="utf-8") as f: ewt360_js = f.read() encrypted_password = execjs.compile(ewt360_js).call("getEncryptedPassword", password) return encrypted_password def login(sign, username, encrypted_password): headers = { "sign": sign, "timestamp": str(int(time.time()*1000)), "sec-ch-ua": "" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" } data = { "autoLogin": True, "password": encrypted_password, "platform": 1, "userName": username } response = session.post(url=login_url, headers=headers, json=data) print(response.json()) def main(): username = input("请输入登录账号: ") password = input("请输入登录密码: ") sign = get_sign() encrypted_password = get_encrypted_parameter(password) login(sign, username, encrypted_password) if __name__ == "__main__": main()
参考资料: RFC 4772:https://datatracker.ietf.org/doc/rfc4772/ DES 维基百科:https://en.wikipedia.org/wiki/Data_Encryption_Standard RFC 3268:https://datatracker.ietf.org/doc/rfc3268/ AES 维基百科:https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
孙中山经典语录国家之本,在于人民。讲到国家的政治,根本上要人民有权。民生是社会进化的重心。让我们将事前的忧虑,换为事前的思考和计划吧。人生以服务为目的,当有能力为千万人服务时,就要为千万人服务,
我们应该怎样保护听力?第一减少噪声刺激。为了能够更好的维持听力健康,首先要做的就是避免接触过大的声音,减少噪声刺激,这样才能更好的保护听力耳朵中有成千上万个听毛细胞,它们对于噪声异常敏感,如果长期生活在
减肥养身计划我的养生食谱饮食计划及建议早上起床后温开水一杯,约150ml。800(1)鸡蛋白全麦面包玉米脱脂牛奶都可以中午12001230米饭一小碗或面食半碗,肉类牛肉鱼肉鸡肉最佳(注意鸡皮鱼
在彼尔姆,他们找到了避免飞机部件出现缺陷的方法如今,在许多工业领域中,成功使用了通过3D打印获得的金属部件。尤其是逐层堆焊,可以获得航空工业的各种大尺寸产品发动机整流罩飞机机身部件和其他结构件。但它们通常有缺陷尤其是结构不均匀
巴基斯坦女性为何要戴面纱?当她揭下面纱那一刻,游客原来如此中国地广物博地形复杂,造就了许多壮丽辽阔的自然景观,况且中国拥有五千年的历史,加之保护得当,便留存着许多历史人文景观,并且随着中国经济的不断发展,吸引了大批来自海外的游客。他们体验
那些年世界杯东道主的奇葩事夺冠必有悬案,有人狂欢有人哭四年一届的世界杯即将拉开帷幕,东道主卡塔尔率先出战。这次独特的世界杯中,神秘的东道主卡塔尔会给出怎样的答卷,很快就会揭晓。世界杯历史中,有6支球队在成为东道主后,拿到了世界杯的冠军
千亿小巨头,只剩零头文荆玉按照此前一段时间创投圈流行的话术,随着5G人工智能大数据等技术快速推广,世界正在进入一个万物互联的时代。投资人和创业者们对此预期非常乐观,国家的顶层战略规划适时出台,中外科技
女版乔布斯因欺诈罪被判入狱11年,曾吹嘘只需几滴血就能诊断出疾病极目新闻记者胡莉据CNN11月19日报道,美国血液检测公司Theranos创始人现年38岁的伊丽莎白霍姆斯(ElizabethHolmes)因欺诈投资者罪名获刑11年零3个月。霍姆
年利率高达36,58同城旗下借贷平台,越过了24的红线6月起,多地监管部门向辖区内消费金融机构进行窗口指导,要求在一年内将个人贷款产品年利率降至24以内。很多互联网消金公司,已经纷纷将借款利息降至24以内。不少助贷公司在去年四季度也均
主打智能网联,江铃域虎9带来怎样的高端体验?智能化历来是高端乘用车新能源汽车的专属,也是未来汽车的发展方向。江铃汽车锐意进取打造出高端智能的皮卡车型,通过先锋设计前沿科技配备,为皮卡插上了新的翅膀。那么皮卡的智能化该怎么玩呢
iPhoneSE4渲染图3499元就能体验灵动岛,库克真会这么大方吗iiPhoneSE这款机型的存在,可以说是非常奇特的,因为每次iPhoneSE的机型都是独立发布,并没有和iPhone的主力机型同时发布。除了独立发布之外,iPhoneSE的售价也