• python爬虫之js逆向入门:常用加密算法的逆向和实践


    一、强大的Chrome DevTools

    Chrome DevTools是一组内置于Google Chrome浏览器中的开发者工具,用于帮助开发人员调试、分析和优化Web应用程序。它提供了一系列功能强大的工具,用于检查和编辑HTML、CSS和JavaScript代码,监视网络请求、性能分析,以及模拟移动设备等。(就是查看页面的组成代码和静态文件,也能调试js。)

    1、Chrome DevTools的常用功能

    1、元素面板(可以查看、修改html):用于检查和编辑页面的HTML和CSS代码,可以实时修改和预览效果。
    2、控制台(执行js代码、打印log):用于在浏览器中执行JavaScript代码,并查看输出结果、错误信息和警告。
    3、源码面板(可以查看和调试所有构成页面的代码,主要是可以调试js)面板用于查看和调试页面的源代码。
    3、网络面板(浏览器自带的抓包工具):用于监视页面的网络请求,包括请求和响应的详细信息、加载时间、资源大小等。
    4、性能面板(Performance Panel):用于分析页面的性能瓶颈,包括CPU和内存使用情况、页面加载时间、JavaScript执行时间等。
    5、应用面板(Application Panel):用于查看和编辑浏览器的存储、缓存和Cookie信息,以及模拟离线状态和移动设备。
    6、安全面板(Security Panel):用于检查网站的安全性设置,包括HTTPS证书、混合内容警告等。

    2、最常用的两个面板-Sources面板和Networks面板

    1、Chrome DevTools中的Sources面板

    是一个强大的调试工具,它可以让你检查和调试JavaScript代码。Sources面板中提供了一些工具,如断点、调试、网络请求等,以帮助开发人员更好地理解和调试JavaScript代码。功能包括:
    代码编辑器:Sources面板包含一个内置的代码编辑器,可以查看和编辑JavaScript源文件。
    调试功能:可以在代码中设置断点,以便在执行到特定行时暂停代码的执行。还可以使用调试工具来逐步执行代码,并检查变量的值和执行结果。
    监视功能:可以监视变量的值,并在值更改时自动暂停代码执行。
    网络请求:Sources面板可以捕获和查看浏览器发出的网络请求,以及它们的响应。
    控制台:Sources面板集成了控制台,可以在其中运行和调试JavaScript代码,以及查看打印的日志消息。
    在使用Sources面板时,可以通过按F1键打开设置面板,以选择和配置特定的功能和快捷键。此外,Sources面板还支持导入和导出断点、黑盒脚本、预处理脚本等功能,以方便开发人员进行代码调试和管理。

    2、Chrome DevTools中的Networks面板

    是一个强大的工具,用于监视和分析浏览器发出的网络请求和响应。它提供了详细的网络性能信息,帮助开发人员优化网页加载速度和网络请求的效率。
    请求监视:Networks面板会显示浏览器发出的每个网络请求,包括URL、请求方法、状态码、请求头、响应头等信息。你可以点击每个请求来查看其详细信息。
    请求过滤:可以根据不同的类型(例如XHR、图片、CSS等)过滤和显示请求,以便更好地分析和检查特定类型的请求。
    性能分析:Networks面板提供了丰富的性能数据,如请求时间、传输时间、响应大小等,以帮助你分析和优化网页的加载性能。
    请求详细信息:你可以查看每个请求的详细信息,包括请求和响应的头部、查询参数、Cookies等。还可以查看请求的响应内容和预览。
    延迟模拟:Networks面板允许你模拟不同的网络条件,如慢速3G、2G等,以便测试网页在不同网络环境下的性能表现。
    WebSocket和Server-Sent Events监视:Networks面板可以监视和显示通过WebSocket和Server-Sent Events协议建立的实时连接。
    通过使用Networks面板,你可以深入了解网页的网络请求和响应情况,识别性能瓶颈,优化网页加载速度,并确保网络请求的效率。它是Web开发过程中非常有用的调试和优化工具。

    二、HTTP协议

    1、http请求报文格式

    request.png
    抓包
    image.png

    2、http回应报文格式

    response.png
    抓包
    image.png

    3、代码中http组包

    GET /login HTTP/1.1
    Host: renren.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    三、处理数据常见算法

    1、Base64

    Base64是一种编码方式,用于将二进制数据转换为可打印的ASCII字符序列。一般用于二进制数据在网络传输或存储时进行编码,ASCII字符序列可以跨平台传输和存储。编码过程中,如果二进制数据不足3个字节的,将被’='填充。
    新浪登录接口用户名使用Base64进行编码 https://weibo.com/login.php
    乐居 https://my.leju.com/web/sso/loginView#wt_source=bzdh_login

    // 浏览器中
    var str = '我是一只爬虫';
    var encode_result = window.btoa(unescape(encodeURIComponent(str))); // 编码
    var decode_result = decodeURIComponent(escape(window.atob('5oiR5piv5LiA5Y+q54is6Jmr')));
    
    /*node 中 
    修改源 npm config set registry https://registry.npm.taobao.org
    查看修改结果 npm config get registry
    */
    
    // 先安装 npm install base64 --save
    // 编码字符串为base64
    const base64 = require('base64');
    let encodedString = base64.encode(str);
    // 解码base64字符串
    let decodedString = base64.decode(encodedString);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    import base64
    data = '我是一只爬虫'
    # 编码
    base64.b64encode(data.encode()) # b'5oiR5piv5LiA5Y+q54is6Jmr'
    # 解码
    base64.b64decode(b'5oiR5piv5LiA5Y+q54is6Jmr').decode()
    
    """
    1、避坑 有的时候你会发现用在调试过程中明明是base64编码过的,
    但是用python进行编码的时候,结果和浏览器中不一样,原因是十六进制的字符串数据,
    转换成二进制时,使用的是bytes.fromhex()方法,而不是str.encode(),两者的结果截然不同的,
    这种方法常用在对RSA、AES等加密结果进行编码的时候。
    """
    data = 'a45737a515466fc33986f6e4717db9f3'
    data.encode() # b'a45737a515466fc33986f6e4717db9f3'
    bytes.fromhex(data) # b'\xa4W7\xa5\x15Fo\xc39\x86\xf6\xe4q}\xb9\xf3'
    
    base64.b64encode(data.encode()) # b'YTQ1NzM3YTUxNTQ2NmZjMzM5ODZmNmU0NzE3ZGI5ZjM='
    base64.b64encode(bytes.fromhex(data)) # b'pFc3pRVGb8M5hvbkcX258w=='
    
    # 二进制转换成 js中类似charCodeAt()
    data = b'\xa4W7\xa5\x15Fo\xc39\x86\xf6\xe4q}\xb9\xf3'
    list(data) # 
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2、哈希算法

    哈希算法是一种将任意长度的输入数据转换为固定长度哈希值的算法。它通常用于对数据进行摘要、签名、验证等操作,具有以下特点:
    不可逆性:哈希算法是单向的,即无法从哈希值还原出原始数据。无论输入数据有多长,生成的哈希值长度是固定的。
    相同输入生成相同哈希值:对于相同的输入数据,无论何时何地进行哈希计算,都会得到相同的哈希值。这使得哈希算法非常适合用于数据的完整性验证。
    雪崩效应:输入数据的微小改变会导致生成的哈希值发生巨大变化。即使原始数据只有一个字节的差异,哈希值也会完全不同。

    1、MD5

    MD5可以将任意长度的信息映射成16字节128位的二进制字符串(长度为32的十六进制字符串)。安全系数低,计算速度快。一般用在密码学、数字签名、数据完整性校验等领域。
    (雪崩效应:MD5算法将输入的消息分成一系列512位的块,并对每个块进行一系列的操作,最终生成128位的哈希值。在每个块的处理过程中,MD5使用了四个非线性函数(F、G、H和I函数)以及一系列位操作(位移、异或等),这些操作使得输入数据的微小变化会导致输出哈希值的显著差异)
    搜狐密码使用MD5 https://v4.passport.sohu.com/fe/login
    人人网 签名 http://renren.com/login

    // 引用CryptoJS
    <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    
    // 加密
    var hash = CryptoJS.MD5("hello world");
    
    // 输出加密结果
    console.log(hash.toString()); // 5eb63bbbe01eeed093cb22bb8f5acdc3
    
    // 抖音X-Bogus参数过程中 会对Uint8Array进行MD5
    uint8Array = new Uint8Array([1, 2, 3, 4]);
    wordArray = CryptoJS.lib.WordArray.create(uint8Array);
    CryptoJS.MD5(wordArray).toString(); // 08d6c05a21512a79a1dfeb9d2a8f262f
    
    const CryptoJS  = require("crypto-js");
    var res = CryptoJS.MD5(1);
    console.log(res.toString())
    
    /*
    避坑指南 如果数据不是字符串,结果将是相同的 487f7b22f68312d2c1bbc93b1aea445b
    Crypto.MD5(1).toString()
    Crypto.MD5(2).toString()
    Crypto.MD5([]).toString()
    Crypto.MD5({}).toString()
    CryptoJS.MD5(new Uint8Array()).toString()
    Crypto.MD5([32, 0, 0, 0]).toString()
    
    */
    https://github.com/brix/crypto-js/pull/296
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    import hashlib
    
    message = b"hello world"
    
    # 创建一个MD5对象
    md5 = hashlib.md5()
    # 更新MD5对象的内容
    md5.update(message)  # 使用字节串进行更新
    # 获取MD5的摘要值
    digest = md5.hexdigest() # 5eb63bbbe01eeed093cb22bb8f5acdc3
    
    
    # 另一种调用方式
    md5 = hashlib.md5(message.encode()).hexdigest()
    
    
    # 对Uint8Array进行MD5
    hashlib.md5(bytes([1,2,3,4])).hexdigest() # 08d6c05a21512a79a1dfeb9d2a8f262f
    # 利用numpy
    import numpy as np
    data = np.array([1,2,3,4], dtype=np.uint8)
    hashlib.md5(data).hexdigest() # 08d6c05a21512a79a1dfeb9d2a8f262f
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2、SHA1

    SHA-1用于将任意长度的数据转换为固定长度的摘要值,通常为20字节160位的二进制字符串(长度为40的十六进制字符串),安全系数和计算速度适中。
    春秋旅游网 签名 https://my.springtour.com/member/login

    // 引用CryptoJS
    <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    
    
    // 计算SHA-1哈希
    var hash = CryptoJS.SHA1("hello world");
    // 输出加密结果
    console.log(hash.toString()); // 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    import hashlib
    
    # 计算SHA-1哈希
    message = 'hello world'
    sha1 = hashlib.sha1(message.encode()).hexdigest() 
    print(sha1) # 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、SHA256

    SHA-256是一种安全哈希算法,用于将任意长度的数据转换为32字节256位的二进制摘要值(长度为64的十六进制字符串),安全系数高,计算速度慢。
    中旅旅行 登录 (综合加密)https://www.ourtour.com/zl/login
    易付宝 登录aes 签名sha256 https://paypassport.suning.com/ids/login

    // 引用CryptoJS
    <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    
    
    // 计算SHA-1哈希
    var hash = CryptoJS.SHA256("hello world");
    // 输出加密结果
    hash.toString() // b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
    
    
    
    npm install jsrsasign
    npm install node-rsa
    npm install crypto-js
    
    
    s = '2201f0c68a55-153a-43e7-b057-a031651c1e9d16858873806711.0'
    var key = '-----BEGIN PRIVATE KEY-----MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8gphg1cvDP45rAHzA1GmVc9+zTckvDQL4UK7zZHGHXmtClq0/KtPFw6jL9YoB7z6m1WPOE5JBm3dKgqK1KgEODXXf58cYexaE0dM0L/6XVPw57aomTgg8KFpRsKQb31b3gndP3OFXasu71NCVKLu+Rn9p4Qpa6syzWzfFsVR7KyJ1WY/vwVgviGfhVGAbtmKvOGEB6xR70joLVthxYPDP7cHpkabJU1CNWG/ZRzd06iW2odm+MrhHKl1VOhQVcqZF2D97El9waC0GEjnP/r2HVRZ/nmeKH2OeNPsQmyrYoGSKBJ8+QqwGpit6nFOSVDLFaNJg4OLkwiL9YFYvnhg5AgMBAAECggEAXpTfw2ZBsBsJZ+J8tXtd5mCXEq2qjXLn1JMW1IPG+naDNovHLPReANHktUDjF4lkU+ypANKNBWHtfnMBFAiZMuXKCKeQG1ZWvBlS8NJL2L4JNz9pqYJpW1Wby3TnQhzS06igGG/omCW7RujGJrCjUhqo/wSsX2WDg1H3L7eDfbAPqvipfvB/dtCy9SEbRJJCKuMpb50dOfUCRtRWtBEVa+HCRnJTl+W1gijzpgc9xme14oljExiviMO7pYt1+AC3DxGVXPqivOyc2qI0wDQqR2NOD0IQTRBRS2F5k8BjYM9o/gbjUIuxIcJOiDJFtzbi6lpV2YrNzFSwwYOtuXhYqQKBgQDtDvTkq34vKcyFNbwNe/7tXqh3AtGvXznR3mT7sePNtMNcJWjE1CgNJAbRcVoQkhr6t/bWU2lK+jLzAl4dfKpcg3G5VCuY2Fpm5oJC6JakzF8S0U65al4WOiC8B/lCW8/CFag8Z7xNm0bsTlsDZTBCbHMs1NLdhrV2uTaSEUFhzwKBgQDLkpSnmFRM8xwlZIOAX51+9a4yYRUHUfxiqi0Y7RT06l9+KgT13vxqUuykuFfAVtjZyn7vc5oOOr0dbMqm/MHhV9QnpfGhffpL6emgR7x4nnQ8XrJXIvky5EiGjnrFFfKsiIKuDKwhbslUHJmlrgP0kre0Tyb0etISSOSvKrmPdwKBgGSwAZxOqt3lZxT9ac5gaDryBaPm8qEGVUyqpUGyoQtyR7gPu5w+cHSEZND40ERRilwLXzBRZVuPQaytyMPFe6anvdn1wj69RkiGh7VbjQCaPZeEh2eBokzWi6jRyjFBRdEt2bMubHCaD1m3PjkG9aSA47qa+qVU3iZ7LI6F/btJAoGBAJh6cl4V+w6oCaz4XIcLFyzBWHjjvpx9DE3aqWzCJ7BK3LvjPVPscaQx+I5ohVHLuyFmSy2PqRR/aqdflWr+ZzoiTwZjhVkwwwmZayRilwjBps6RH4Ok7oLv+mLO1aZJijsxBLDZTRS9po8Z3Pv8G3pVasPjhYoZdL+9WYzas6KBAoGASBMQ1f2fu4agHVwYVI23xDJNPAktezX/K/xubJvU6umNpQhX8KMb2lb61+2tIYpgzVvG5rw3J9UVx4GmvuKO1l820u4gxd5mhwrQDS0r+DKTZDpzLvfoV4MRauS0n0asMHH/7unFStWCQ2jVvGVRUu2fcrFvEDcljFv9G29rBlc=-----END PRIVATE KEY-----'
    
    var key = rs.KEYUTIL.getKey(key);
    
      // 创建 Signature 对象,设置签名编码算法
    var signature = new rs.KJUR.crypto.Signature({ alg: "SHA256withRSA" });
    // 初始化
    signature.init(key);
    
    signature.updateString(s);
    // 生成密文
    const originSign = signature.sign();
    console.log(rs.hextob64(originSign))
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    import hashlib
    
    # 计算SHA-256哈希
    message = 'hello world'
    sha256 = hashlib.sha256(message.encode()).hexdigest()
    print(sha256) # b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3、加密算法

    1、DES

    DES是一种对称加密算法,它采用了分组密码的方式,将明文按固定长度的块进行加密。密钥长度为64位(8位字符串)
    UU跑腿服务平台 http://open.uupt.com/#/

    // 引用CryptoJS
    <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    
    message = 'hello world'
    key = '4706d6c8c3d8dd5a';
     // 只有8位
    
    CryptoJS.enc.Hex.parse(key) // 将每2个16进制字符转换成1个2进制字符 对应python中的 bytes.fromhex(str) 
    CryptoJS.enc.Utf8.parse(key) // 对数据进行UTF8编码 对应python中的 str.encode('utf-8')
    
    // ECB 加密
    ecb_encrypted = CryptoJS.DES.encrypt(message, CryptoJS.enc.Hex.parse(key), {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    encryptedText = ecb_encrypted.toString() // tWXmK1ju9f2ObhV/U8IUXA==
    
    // ECB 解密
    decryptedBytes = CryptoJS.DES.decrypt({ ciphertext: cipherText }, CryptoJS.enc.Hex.parse(key), {
        mode: CryptoJS.mode.ECB,
      });
    decryptedText = decryptedBytes.toString(CryptoJS.enc.Utf8); // 'hello world'
    
    key = '4706d6c8';
    iv = '5eb63bbb'; // 只有8位
    
    // CBC模式加密
    cbc_encrypted = CryptoJS.DES.encrypt(message, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
    });
    encryptedText = cbc_encrypted.toString(); // kjKZ7UXWaATiot8anmcsbQ==
    
    // CBC解密
    cipherText = CryptoJS.enc.Base64.parse(encryptedText);
    decryptedBytes = CryptoJS.DES.decrypt(encryptedText, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
    });
    decryptedText = decryptedBytes.toString(CryptoJS.enc.Utf8); // 'hello world'
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    from Crypto.Cipher import DES3
    from Crypto.Cipher import DES
    from Crypto.Util.Padding import pad, unpad
    import base64
    
    message = 'hello world'
    key = '4706d6c8c3d8dd5a'
    """
    避坑指南
    js 中key为4706d6c8也能加密,但是python中会报错,因为JS加密过程,key长度不够8位时会用0补齐长度
    python 中将key赋值为 4706d6c800000000 即可,
    因为bytes.fromhex会将将每两个十六进制字符转换为一个字节
    """
    
    # ECB 加密
    cipher = DES.new(bytes.fromhex(key), DES.MODE_ECB)
    ciphertext = cipher.encrypt(pad(message.encode(), DES.block_size))
    encrypted_text = base64.b64encode(ciphertext).decode() # tWXmK1ju9f2ObhV/U8IUXA==
    
    # ECB 解密
    cipher = DES.new(bytes.fromhex(key), DES.MODE_ECB)
    decrypted_bytes = cipher.decrypt(base64.b64decode(encrypted_text))
    decrypted_text = unpad(decrypted_bytes, DES.block_size).decode("utf-8")
    
    
    # CBC 加密
    key = '4706d6c8'
    iv = '5eb63bbb' # 只有8位
    
    cipher = DES.new(key.encode(), DES.MODE_CBC, iv.encode())
    ciphertext = cipher.encrypt(pad(message.encode(), DES.block_size))
    encrypted_text = base64.b64encode(ciphertext).decode() # jKlxcg9R8X1i/SJU4w1CJQ==
    
    # CBC 解密
    cipher = DES.new(key.encode(), DES.MODE_CBC, iv.encode())
    decrypted_bytes = cipher.decrypt(base64.b64decode(encrypted_text))
    decrypted_text = unpad(decrypted_bytes, DES.block_size).decode("utf-8")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2、3DES

    3DES是DES算法的加强版。它使用了三次DES加密操作来增强数据的安全性,密钥长度为128位(16位字符串)
    加密过程和DES类似。

    3、AES

    AES是一种对称加密算法,被广泛用于保护数据的机密性。它支持多种密钥长度,包括128位(16位字符串)、192位(24位字符串)和256位(32位),其中CBC模式需要一个初始向量(IV)作为第一个密文块的输入,长度必须为128位(16位字符串)。
    锦江之星 登录密码 http://hotel.bestwehotel.com/NewLogin/
    UU跑腿企业版 http://es.test.uupt.com/admin/#/login
    超星云盘 https://passport2.chaoxing.com/login

    // 引用CryptoJS
    <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    
    message = 'hello world'
    const key = '4706d6c8c3d8dd5af1dfcb661a0db335';
    const iv = '5eb63bbbe01eeed093cb22bb8f5acdc3';
    
    // ECB模式加密
    ecb_encrypted = CryptoJS.AES.encrypt(message, CryptoJS.enc.Hex.parse(key), {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    encryptedText = ecb_encrypted.toString()  // Zd5b5CjKKhR3rOE/2gBGYw==
    // ECB解密
    cipherText = CryptoJS.enc.Base64.parse(encryptedText);
    decryptedBytes = CryptoJS.AES.decrypt({ ciphertext: cipherText }, CryptoJS.enc.Hex.parse(key), {
        mode: CryptoJS.mode.ECB,
      });
    decryptedText = decryptedBytes.toString(CryptoJS.enc.Utf8); // 'hello world'
    
    /*
    避开坑指南
    js CBC模式IV 超过16位时,加密过程中只截取前16位,通过processBlock方法可以看到处理过程。
    */
    // CBC模式加密
    cbc_encrypted = CryptoJS.AES.encrypt(message, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
    });
    encryptedText = cbc_encrypted.toString(); // kjKZ7UXWaATiot8anmcsbQ==
    // CBC解密
    cipherText = CryptoJS.enc.Base64.parse(encryptedText);
    decryptedBytes = CryptoJS.AES.decrypt(encryptedText, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
    });
    decryptedText = decryptedBytes.toString(CryptoJS.enc.Utf8); // 'hello world'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import pad, unpad
    import base64
    import binascii
    
    key = '4706d6c8c3d8dd5af1dfcb661a0db335'
    iv = '5eb63bbbe01eeed093cb22bb8f5acdc3'
    message = 'hello world'
    """
    必坑指南,加密的时候key由16进制到2机制有两种方法,并且加密结果不同
    1. key.encode() # b'4706d6c8c3d8dd5af1dfcb661a0db335'
    2. bytes.fromhex(key) # b'G\x06\xd6\xc8\xc3\xd8\xddZ\xf1\xdf\xcbf\x1a\r\xb35'
    3. binascii.unhexlify(key) # b'G\x06\xd6\xc8\xc3\xd8\xddZ\xf1\xdf\xcbf\x1a\r\xb35'
    其中2 3 对应 js中的 CryptoJS.enc.Hex.parse(key)
    """
    # ECB 加密
    cipher = AES.new(bytes.fromhex(key), AES.MODE_ECB)
    encrypted_bytes = cipher.encrypt(pad(message.encode(), AES.block_size))
    encrypted_text = base64.b64encode(encrypted_bytes).decode() # Zd5b5CjKKhR3rOE/2gBGYw== 
    
    # ECB 解密
    cipher = AES.new(bytes.fromhex(key), AES.MODE_ECB)
    decrypted_bytes = cipher.decrypt(base64.b64decode(encrypted_text))
    decrypted_text = unpad(decrypted_bytes, AES.block_size).decode("utf-8")
    
    """
    python CBC 模式如果IV 超过16位加密会报错,所以必须是16位长度
    """
    # CBC 加密
    cipher = AES.new(bytes.fromhex(key), AES.MODE_CBC, bytes.fromhex(iv))
    encrypted_bytes = cipher.encrypt(pad(message.encode("utf-8"), AES.block_size))
    encrypted_text = base64.b64encode(encrypted_bytes).decode()
    
    # CBC 解密
    cipher = AES.new(bytes.fromhex(key), AES.MODE_CBC, bytes.fromhex(iv))
    decrypted_bytes = cipher.decrypt(base64.b64decode(encrypted_text))
    decrypted_text = unpad(decrypted_bytes, AES.block_size).decode("utf-8")
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    4、RSA

    RSA是一种非对称加密算法,常用于数据加密和数字签名,会生成一对密钥,公开的是公钥,私钥的是私钥。
    1、数字签名,用于确保数据的完整性和认证发送方的身份,一般使用私钥加密,公钥解密。
    2、数据加密,一般使用公钥加密,私钥加密。
    链家(贝壳) 登录密码 https://xa.lianjia.com/
    新浪密码 https://www.sina.com.cn/
    房天下 https://passport.fang.com/
    东方财富 https://passport2.eastmoney.com/pub/login

    var encryptor = new JSEncrypt();
    
    
    // 生成密钥对
    var encryptor = new JSEncrypt({ default_key_size: 2048 });
    var keyPair = encryptor.getKey();
    // 获取公钥和私钥
    var publicKey = keyPair.getPublicKey();
    var privateKey = keyPair.getPrivateKey();
    console.log(publicKey);
    console.log(privateKey);
    
    // 设置公钥
    var publicKey = '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgtcLM2er6q7JlT/GFs55\nVAsf2ONVMFFQKTYWHgmpxp+UI0fqhRr6oLsuepy6ilcIfaHpjobX3MLLCrW4fSRG\nLiBW+ZiU8JLm8W7hQ3n36hyywRrTLbgelWvcg5z9wx2epneAQQSddoyBp9A9JaAc\nyPdIQbqb48n2T2QmZ+qZY7vvvIJ2lB0gdljmYTKB6y+eXZtzXOJ2drwh2QjmIxeL\nwH+LxQxQhkduE9nqKicc8c72GpgG1I96GHIXH2NfH3mBRSkVjX4UG9zdiNhgqxZo\nqHnPhYuj6IhB9LTTVwNItagg9gcT2d0NmuDLHg1xSuyNY6ZG88ryNj1DzVWvPhzw\nhwIDAQAB\n-----END PUBLIC KEY-----'
    
    // 设置私钥
    var privateKey = '-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAgtcLM2er6q7JlT/GFs55VAsf2ONVMFFQKTYWHgmpxp+UI0fq\nhRr6oLsuepy6ilcIfaHpjobX3MLLCrW4fSRGLiBW+ZiU8JLm8W7hQ3n36hyywRrT\nLbgelWvcg5z9wx2epneAQQSddoyBp9A9JaAcyPdIQbqb48n2T2QmZ+qZY7vvvIJ2\nlB0gdljmYTKB6y+eXZtzXOJ2drwh2QjmIxeLwH+LxQxQhkduE9nqKicc8c72GpgG\n1I96GHIXH2NfH3mBRSkVjX4UG9zdiNhgqxZoqHnPhYuj6IhB9LTTVwNItagg9gcT\n2d0NmuDLHg1xSuyNY6ZG88ryNj1DzVWvPhzwhwIDAQABAoIBAAD8OI/fCHrgbREs\nJUQ3ss8wtEEwWQxfmGBvEVSRkw81VWq8mGX/MYLzVeLDel4fUKeNiBI0LrzxVJEU\nlDqRAtxHDxCbFwgGuyl3Qcf9y6GeLLRqjMuL1uMeKE9vZ7PH7dFoFfWnYL4rSbCn\nT0aQwZa70fX4v0LEWw/2+5kNubD4DxDzPvMMIPaextKzmWSBalNBsjt9So7ae4sW\n+tafKyu1BFa0ZLJ1X/LuLJBPadiiiw9PdN8IHBHgpPrdNk4O5Zm2OnfaNhqZfRmI\nofWt6+D+yB4lMxgJC2RXZVmNJmzS9TFHhOpVoR0hdYss08A2tw7giSi8ikmT/RD1\nXgbyr2kCgYEAtX72jyEo3a6zEdoxmz0Q9DAzCzJJKAG4WQaJF86qRadRX5Tnn3oK\nIWLCfIpJNU3NsWI/ItMHpRJYheRcF5sGmu+YfUh7T7hQDblQdVTynz3NdXvOXonR\nxcr3uMVUG1kig1cdwOuD6up0mZgu/FGZMlLc5tz/RxhY8r53ClkT+4kCgYEAuIzA\nm9HX+9eatOUyIgWgsqW+yI5x23r1kpN1uk4yw3B9xqihgBp3tM0KNA1VZORi81py\nNwLWXn9f7lczSO7yK0VQLV3RP/Ks3te11N5fJxfZruP3PwXvlaQDS1u8KHJes4tZ\nRYUFIDhLrnhy2yUtWK70aYto1doNe1z5oFJhN48CgYAetlderQvPR4rB0JxoWpMN\n30Ij+ORsQq5BUlvMjYo+syuP8xCm6e3g7Gdgz73HqVzPUYLBj9hRVKNqNNRoojEh\n8r1pJeTH/rZ9PAijcjaEP98OrF6lnMjEoa39tFahMhonA4zjYnc2P2pvu1LoG57C\n50a+QlNoYnRaz2QxehVpkQKBgDcBzQ8ktunb08MDZbP6VXGqMXl567ntpnCv/zEu\nybazOuoRrUGPogqD6vyk1MUjxdKfLNf0woycDq3t091zSz9Wg5ViF1KmNJyfUxVF\nyrrOQxX74OAqFsVVg53ck/LCVDPT3yH3ihWWcgho4mMra565VyR2ZyMGwWn5xnXg\n2BVFAoGAbuARCuT4AiWv9NksHvyvcWl7LvXMeNvc/GvT8VhGwtqXWTebVUNB5Z9a\nefCRktAlNhZNarvMl2sOo3FKYEb0fmoFMVddZaHfJ/5PVCRg6i/LoN9DZaQE4sGb\n1LRflR9v1vwMLj4gsznzd4Uyjiy5VBICPCk4xib7yMGk8ivatzw=\n-----END RSA PRIVATE KEY-----'
    
    // 加载公钥
    encryptor.setPublicKey(publicKey);
    
    // 加载私钥
    encryptor.setPrivateKey(privateKey);
    
    // 待加密的数据
    var text = 'hello world'
    
    // 加密
    var encrypted = encryptor.encrypt(text);
    console.log(encrypted);
    
    // 解密
    var decrypted = encryptor.decrypt(encrypted);
    console.log(decrypted);
    
    
    
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/8.0.20/jsrsasign-all-min.js"></script>
    // 签名
    signature = new KJUR.crypto.Signature({ alg: "SHA256withRSA" })
    signature.init(privateKey);
    signature.updateString(text);
    sign = signature.sign()
    
    // 验签
    verified = new KJUR.crypto.Signature({ alg: "SHA256withRSA", prvkeypem: publicKey })
    verified.updateString(text)
    res = verified.verify(sign)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_v1_5
    from Crypto.Hash import SHA256
    
    # 生成密钥对
    keys = RSA.generate(2048)
    private_key = keys.export_key()
    public_key = keys.publickey().export_key()
    
    text = 'hello world'
    public_key = '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgtcLM2er6q7JlT/GFs55\nVAsf2ONVMFFQKTYWHgmpxp+UI0fqhRr6oLsuepy6ilcIfaHpjobX3MLLCrW4fSRG\nLiBW+ZiU8JLm8W7hQ3n36hyywRrTLbgelWvcg5z9wx2epneAQQSddoyBp9A9JaAc\nyPdIQbqb48n2T2QmZ+qZY7vvvIJ2lB0gdljmYTKB6y+eXZtzXOJ2drwh2QjmIxeL\nwH+LxQxQhkduE9nqKicc8c72GpgG1I96GHIXH2NfH3mBRSkVjX4UG9zdiNhgqxZo\nqHnPhYuj6IhB9LTTVwNItagg9gcT2d0NmuDLHg1xSuyNY6ZG88ryNj1DzVWvPhzw\nhwIDAQAB\n-----END PUBLIC KEY-----'
    private_key = '-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAgtcLM2er6q7JlT/GFs55VAsf2ONVMFFQKTYWHgmpxp+UI0fq\nhRr6oLsuepy6ilcIfaHpjobX3MLLCrW4fSRGLiBW+ZiU8JLm8W7hQ3n36hyywRrT\nLbgelWvcg5z9wx2epneAQQSddoyBp9A9JaAcyPdIQbqb48n2T2QmZ+qZY7vvvIJ2\nlB0gdljmYTKB6y+eXZtzXOJ2drwh2QjmIxeLwH+LxQxQhkduE9nqKicc8c72GpgG\n1I96GHIXH2NfH3mBRSkVjX4UG9zdiNhgqxZoqHnPhYuj6IhB9LTTVwNItagg9gcT\n2d0NmuDLHg1xSuyNY6ZG88ryNj1DzVWvPhzwhwIDAQABAoIBAAD8OI/fCHrgbREs\nJUQ3ss8wtEEwWQxfmGBvEVSRkw81VWq8mGX/MYLzVeLDel4fUKeNiBI0LrzxVJEU\nlDqRAtxHDxCbFwgGuyl3Qcf9y6GeLLRqjMuL1uMeKE9vZ7PH7dFoFfWnYL4rSbCn\nT0aQwZa70fX4v0LEWw/2+5kNubD4DxDzPvMMIPaextKzmWSBalNBsjt9So7ae4sW\n+tafKyu1BFa0ZLJ1X/LuLJBPadiiiw9PdN8IHBHgpPrdNk4O5Zm2OnfaNhqZfRmI\nofWt6+D+yB4lMxgJC2RXZVmNJmzS9TFHhOpVoR0hdYss08A2tw7giSi8ikmT/RD1\nXgbyr2kCgYEAtX72jyEo3a6zEdoxmz0Q9DAzCzJJKAG4WQaJF86qRadRX5Tnn3oK\nIWLCfIpJNU3NsWI/ItMHpRJYheRcF5sGmu+YfUh7T7hQDblQdVTynz3NdXvOXonR\nxcr3uMVUG1kig1cdwOuD6up0mZgu/FGZMlLc5tz/RxhY8r53ClkT+4kCgYEAuIzA\nm9HX+9eatOUyIgWgsqW+yI5x23r1kpN1uk4yw3B9xqihgBp3tM0KNA1VZORi81py\nNwLWXn9f7lczSO7yK0VQLV3RP/Ks3te11N5fJxfZruP3PwXvlaQDS1u8KHJes4tZ\nRYUFIDhLrnhy2yUtWK70aYto1doNe1z5oFJhN48CgYAetlderQvPR4rB0JxoWpMN\n30Ij+ORsQq5BUlvMjYo+syuP8xCm6e3g7Gdgz73HqVzPUYLBj9hRVKNqNNRoojEh\n8r1pJeTH/rZ9PAijcjaEP98OrF6lnMjEoa39tFahMhonA4zjYnc2P2pvu1LoG57C\n50a+QlNoYnRaz2QxehVpkQKBgDcBzQ8ktunb08MDZbP6VXGqMXl567ntpnCv/zEu\nybazOuoRrUGPogqD6vyk1MUjxdKfLNf0woycDq3t091zSz9Wg5ViF1KmNJyfUxVF\nyrrOQxX74OAqFsVVg53ck/LCVDPT3yH3ihWWcgho4mMra565VyR2ZyMGwWn5xnXg\n2BVFAoGAbuARCuT4AiWv9NksHvyvcWl7LvXMeNvc/GvT8VhGwtqXWTebVUNB5Z9a\nefCRktAlNhZNarvMl2sOo3FKYEb0fmoFMVddZaHfJ/5PVCRg6i/LoN9DZaQE4sGb\n1LRflR9v1vwMLj4gsznzd4Uyjiy5VBICPCk4xib7yMGk8ivatzw=\n-----END RSA PRIVATE KEY-----'
    
    # 加密
    public_key = RSA.import_key(public_key.encode())
    cipher = PKCS1_v1_5.new(public_key)
    encrypted = cipher.encrypt(text.encode())
    result = base64.b64encode(encrypted)
    
    # 解密
    private_key = RSA.import_key(private_key.encode())
    cipher = PKCS1_v1_5.new(private_key)
    decrypted = cipher.decrypt(encrypted, 'ValueError')
    decrypted .decode()
    
    # 签名 私钥签名 公钥验签
    
    # 读取 RSA 私钥
    private_key = RSA.importKey(private_key)
    # 使用 PKCS1_v1_5 签名算法进行签名
    hash_obj = SHA256.new(text.encode())
    signer = PKCS1_v1_5.new(private_key)
    signature = signer.sign(hash_obj)
    
    print("签名结果为:", signature.hex())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4、算法的搜索特征

    1、MD5输出长度固定为32位16进制的字符串
    2、MD5算法源码中几个大数可作为关键字进行识别,1732584193、4023233417、2562383102、271733878
    3、RSA 加密需要设置公钥,setPublicKey方法,加密调用方法一般为getKey().encrypt(),RSA每次加密结果不一样
    4、一般签名使用hash算法进行计算的

    5、python实现js中的函数

    1、字符串转ASCII

    1、字符串转换成ASCII码
    text = 'hello world'
    
    js 代码
    function strtoascii(str){
      var asciiArr = [];
      
      for (let i = 0; i < str.length; i++) {
        var charCode = str.charCodeAt(i);
        asciiArr.push(charCode);
      }
      
      console.log(asciiArr);
      return asciiArr
    }
    strtoascii(text) // [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]
    
    python 代码
    def strtoascii(string):
        result = []
        for row in list(string):
            result.append(ord(row))
        return result
    strtoascii(text) # [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    2、json转换

    data = {'name':'python', 'type':1}
    jsondata = JSON.stringify(data) // 对应python json.dumps(data)
    JSON.parse(jsondata)						// 对应python json.loads(jsondata)
    
    
    • 1
    • 2
    • 3
    • 4

    3、Unicode和字符互转

    // unicode 转字符
    String.fromCharCode(65)  // A 对应python中的 chr(65)
    // 字符转 Unicode
    'ABC'.charCodeAt(0) // 65 对应python中的 ord('A')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4、常用函数

    message = 'hello world'
    // 索引
    message.charAt(4) // o 
    // 切片
    message.substring(0,4) // hell 对应python message[0:4]
    
    //周期执行, 每1秒执行一次函数,直到执行 clearInterval()
    setInterval(function(){ console.log("Hello"); }, 1000);
    
    // 延迟执行,延迟3秒后执行函数
    setTimeout(function(){ console.log("Hello"); }, 3000 )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    Navicat:显示的行数与表中实际的行数不一致
    Android Studio中BitmapDrawable的使用2-1
    高等数学求导积分公式
    Matlab 点云迭代加权最小二乘法(IRLS)
    Git代码提交规范
    美团面试拷打:ConcurrentHashMap 为何不能插入 null?HashMap 为何可以?
    vulnhub Potato: 1
    递归算法JAVA实现
    电脑硬盘分区表的两种格式:MBR 和 GPT
    HMS Core热门Kit Top问题合集,你要问的,这里全都有!
  • 原文地址:https://blog.csdn.net/u010442378/article/details/133975753