第7章 day07 了解常见的加密算法

NodeJs

V8引擎

我们知道,js是一种可以直接运行在浏览器中的脚本语言。那么为什么浏览器可以直接运行js脚本程序呢?原因就在于浏览器中内置了“V8”引擎。

什么是V8引擎?

V8引擎是一款专门解释和执行JavaScript代码的虚拟机。任何程序只要集成了V8引擎,就可以执行JavaScript代码。浏览器集成了V8引擎,可以执行JavaScript代码;

Node.js

由于浏览器内部集成了V8引擎,因此js程序可以直接运行在浏览器中。那么,如果想要在浏览器外部运行js代码可以吗?

试想一下,如果我们想在自己电脑上运行Python代码,是不是必须事先要装好Pyhon的运行环境(Python解释器)呢。同样,如果我们想在自己电脑上运行js程序的话,也要事先装好js的运行环境。那么这个执行js程序的运行环境就是“Node.js”。

什么是Node.js?

Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,它使得JavaScript能够在浏览器外部运行。Node.js的出现将JavaScript从浏览器中解放出来。

Node.js环境安装

1、下载Node.js
打开官网下载链接:https://nodejs.org/zh-cn/
Snipaste_2024-07-14_18-02-25

2、安装

下载完成后,双击“node-v12.16.1-x64.msi”,开始安装Node.js
①点击【Next】按钮
②勾选复选框(I accept the…),点击【Next】按钮
Snipaste_2024-07-14_18-05-06

一直【next】就完了,然后【install】安装,安装完后点击【Finish】按钮完成安装

Snipaste_2024-07-14_18-05-40

安装成功后简单一下测试安装是否成功:

在键盘按下【win+R】键,输入cmd,然后回车,打开cmd窗口

Snipaste_2024-07-14_18-07-39

3、环境变量配置

Snipaste_2024-07-14_18-10-32

4、pycharm配置node环境

  1. 打开PyCharm,点击菜单栏中的“File” > “Settings”(对于Mac用户,是“PyCharm” > “Preferences”)。
  2. 在弹出的设置窗口中,选择“Languages & Frameworks” > “Node.js and NPM”。
  3. 在“Node Interpreter”字段中,点击右侧的“…”按钮,然后选择您安装Node.js的路径。这通常是在您的系统路径下的“node”可执行文件。
  4. 确认设置无误后,点击“OK”保存配置。
Snipaste_2024-07-18_19-17-19

base64编码

base64是什么

Base64编码,是由64个字符组成编码集:26个大写字母AZ,26个小写字母az,10个数字0~9,符号“+”与符号“/”。Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节,然后根据Base64的对应表,得到对应的编码数据。

当原始数据凑不够三个字节时,编码结果中会使用额外的符号“=”来表示这种情况。

base64原理

每一个base64的字符会对应有一个索引值(0-63)

image-20230916190327552-4862209

将you进行base64编码过程如下:

image-20230427174804644-4862253-4862254

小于3个字符为一组的编码方式如:

image-20230427174356120-4862276-4862277

ASCII:

Snipaste_2024-07-21_09-13-37

base64测试

base64编码示例:

import base64

# 将原始数据转化为二进制/字节数据
data = "you".encode("utf-8")
print(data)

# 把字节转化成b64
bs = base64.b64encode(data).decode()
print(bs)

bs = "yo".encode("utf-8")
# 把字节转化成b64
print(base64.b64encode(bs).decode())

# 猜测结果
bs = "y".encode("utf-8")
# 把字节转化成b64
print(base64.b64encode(bs).decode())

base64解码示例:

注意, base64编码处理后的字符串长度. 一定是4的倍数(因为Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节). 如果在网页上看到有些密文的b64长度不是4的倍数. 会报错

import base64

s = "eW91"
ret = base64.b64decode(s)
print(ret) #正确

s = "eW91eQ=="
ret = base64.b64decode(s)
print(ret) #正确

s = "eW91eQ"
ret = base64.b64decode(s)
print(ret) #报错,s不是4的倍数

如果不是4的倍数如何处理呢?解决思路. 使用=填充为4的倍数即可

s = "eW91eQ"
#填充为4的倍数
s += ("=" * (4 - len(s) % 4))
print("填充后", s)
ret = base64.b64decode(s).decode()
print(ret)

base64 编码的优点:

  • 算法是编码,不是压缩,编码后只会增加字节数(一般是比之前的多1/3,比如之前是3, 编码后是4)
  • 算法简单,基本不影响效率
  • 算法可逆,解码很方便,不用于私密传输。

js常见的加密方式

  • 加密在前端开发和爬虫中是经常遇见的。掌握了加密、解密算法也是你从一个编程小白到大神级别质的一个飞跃。且加密算法的熟练和剖析也是很有助于帮助我们实现高效的js逆向。下述只把我们常用的加密方法进行总结。不去深究加密的具体实现方式。

  • 常见的加密算法基本分为这几类,

    • 线性散列算法(签名算法)MD5
    • 对称性加密算法 AES DES
    • 非对称性加密算法 RSA

Md5加密(不可逆)

  • MD5是一种被广泛使用的线性散列算法,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整的一致性。且MD5加密之后产生的是一个固定长度(32位或16位)的数据。

    • 结论:一旦看到了一个长度为32位的密文数据,该数据极有可能是通过md5算法进行的加密!
  • 解密:

    • 常规讲MD5是不存在解密的。但是理论上MD5是可以进行反向暴力破解的。暴力破解的大致原理就是用很多不同的数据进行加密后跟已有的加密数据进行对比,由此来寻找规律。理论上只要数据量足够庞大MD5是可以被破解的。但是要注意,破解MD5是需要考虑破解的成本(时间和机器性能)。假设破解当前的MD5密码需要目前计算能力最优秀的计算机工作100年才能破解完成。那么当前的MD5密码就是安全的。
  • 增加破解成本的方法(方法很多,这里只说我常用的)。

    • 使用一段无意义且随机的私匙进行MD5加密会生成一个加密串,我们暂且称之为串1
    • 将要加密的的数据跟串1拼接,再进行一次MD5,这时会生成串2
    • 将串2再次进行MD5加密,这时生成的串3就是我们加密后的数据。
  • 我们在注册账号时的密码一般都是用的MD5加密。

  • 代码实操:

    • Python版本:

      from hashlib import md5
      
      obj = md5()
      obj.update("bobo".encode("utf-8"))
      
      bs = obj.hexdigest()
      print(bs)
      
    • JS版本:下载安装crypto-js(npm install crypto-js)

      var CryptoJS = require('crypto-js');
      // 原始数据
      var data = '123456';
      // 生成MD5摘要
      var md5Digest = CryptoJS.MD5(data).toString();
      
      console.log(md5Digest);
      
  • 上述代码的核心关键字:md5

DES/AES加密(可逆)

  • DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的算法。该加密算法是一种对称加密方式,其加密运算、解密运算需要使用的是同样的密钥(一组字符串)即可。

  • 注意:

    • 现在用AES这个标准来替代原先的DES。
    • AES和DES的区别:
      • 加密后密文长度的不同:
        • DES加密后密文长度是8的整数倍
        • AES加密后密文长度是16的整数倍
      • 应用场景的不同:
        • 企业级开发使用DES足够安全
        • 如果要求高使用AES
  • DES算法的入口参数有三个:

    • Key、Data、Mode,padding、iv。
      • Key为DES算法的工作密钥;
      • Data为要被加密或被解密的数据;
      • Mode为DES的工作模式。最常用的模式就是 CBC 模式和 ECB模式
        • ECB:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
        • CBC:是一种循环模式,前一个分组的密文和当前分组的明文异或后再加密,这样做的目的是增强破解难度。
      • padding为填充模式,如果加密后密文长度如果达不到指定整数倍(8个字节、16个字节),填充对应字符
      • iv:参数中的iv主要用于CBC模式,确保即使加密相同的明文,每次产生的密文也不相同,增强加密的安全性。iv通常是一个16字节的随机字符串。这个字符串在解密时也需要用到,因此需要妥善保存。
  • Python版本:

    • 环境安装:

      pip install pycryptodome
      
    • 加密代码:

      from Crypto.Cipher import AES
      from Crypto.Util.Padding import pad
      import base64
      
      key = '0123456789abcdef'.encode()  # 秘钥: 必须16字节
      iv = b'abcdabcdabcdabcd'  # 偏移量:16位/字节(字节类型)
      text = 'alex is a monkey!'  # 加密内容
      #设置加密内容的长度填充(位数为16的整数倍)
      text = pad(text.encode(), 16)
      #创建加密对象
      aes = AES.new(key, AES.MODE_CBC, iv)  # 创建一个aes对象
      
      en_text = aes.encrypt(text)  # 加密明文
      print("aes加密数据:::", en_text) #返回二进制类型数据
      
      #二进制密文转换成字符串格式
      en_text = base64.b64encode(en_text).decode()  # 将返回的字节型数据转进行base64编码
      print(en_text) 
      
    • 解密代码:

      from Crypto.Cipher import AES
      import base64
      from Crypto.Util.Padding import unpad
      
      key = '0123456789abcdef'.encode()
      iv = b'abcdabcdabcdabcd'
      aes = AES.new(key, AES.MODE_CBC, iv)
      #需要解密的文本
      text = 'X/A0fy9S7+kUI3HYQRKO46WTlid6T1DBhXutwmPdboY='.encode()  
      #将密文数据转换为二进制类型
      ecrypted_base64 = base64.b64decode(text)  
      
      source = aes.decrypt(ecrypted_base64)  # 解密
      #未填充数据
      print("aes解密数据:::", source.decode())
      #取消填充数据
      print("aes解密数据:::", unpad(source, 16).decode())
      
  • JS版本:

    • 加密:

      const CryptoJS = require("crypto-js")
      
      // 密钥(128位,16字节)
      var key = CryptoJS.enc.Utf8.parse('0123456789abcdef');
      
      // 初始化向量(IV)(128位,16字节)
      var iv = CryptoJS.enc.Utf8.parse('1234567890abcdef');
      
      // 待加密的数据
      var plaintext = 'Hello, bobo!';
      
      // 进行AES-128加密,使用CBC模式和PKCS7填充
      var encrypted = CryptoJS.AES.encrypt(plaintext, key, {
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7
      });
      
      // 获取加密后的密文
      var ciphertext = encrypted.toString();
      
      console.log(ciphertext);
      
    • 解密:

      const CryptoJS = require("crypto-js")
      
      // 密钥(128位,16字节)
      var key = CryptoJS.enc.Utf8.parse('0123456789abcdef');
      
      // 初始化向量(IV)(128位,16字节)
      var iv = CryptoJS.enc.Utf8.parse('1234567890abcdef');
      
      // 密文数据
      var encrypText = 'GYc9oxlZB/PeyfFG3ppK6Q==';
      
      // 进行加密,使用CBC模式和PKCS7填充
      var decrypted = CryptoJS.AES.decrypt(encrypText, key, {
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7
      });
      
      // 解密
      var plaintext = decrypted.toString(CryptoJS.enc.Utf8);
      
      console.log(plaintext);
      
  • 上述代码的关键字:

    • AES,DES
    • encrypt(用于加密的函数名),decrypt(用于解密的函数名)
    • xxxkey:秘钥一般是单独生成的,一定不会傻到明文的写在代码中!

RSA加密(可逆)

  • RSA加密:
    • RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。
  • 非对称加密算法:
    • 非对称加密算法需要两个密钥:
      • 公开密钥(publickey:简称公钥)
      • 私有密钥(privatekey:简称私钥)
      • 公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
  • 注意:
    • 使用时都是使用公匙加密使用私匙解密。公匙可以公开,私匙自己保留。
    • 算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。
  • 使用流程和场景介绍
    • 通过公匙加密,使用私匙解密。私匙是通过公匙计算生成的。假设ABC三方之间相互要进行加密通信。大家相互之间使用公匙进行信息加密,信息读取时使用各自对应的私匙进行信息解密
    • 用户输入的支付密码会通过RSA加密
  • 公钥私钥生成方式:
  • 环境安装:npm install jsencrypt

JS代码示例:

window = globalThis;

const JSEncrypt = require('jsencrypt');


var PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyBJ6kZ/VFJYTV3vOC07jqWIqgyvHulv6us/8wzlSBqQ2+eOTX7s5zKfXY40yZWDoCaIGk+tP/sc0D6dQzjaxECAwEAAQ==-----END PUBLIC KEY-----';
        //私钥
var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvIEnqRn9UUlhNXe84LTuOpYiqDK8e6W/q6z/zDOVIGpDb545NfuznMp9djjTJlYOgJogaT60/+xzQPp1DONrEQIDAQABAkEAu7DFsqQEDDnKJpiwYfUE9ySiIWNTNLJWZDN/Bu2dYIV4DO2A5aHZfMe48rga5BkoWq2LALlY3tqsOFTe3M6yoQIhAOSfSAU3H6jIOnlEiZabUrVGqiFLCb5Ut3Jz9NN+5p59AiEA0xQDMrxWBBJ9BYq6RRY4pXwa/MthX/8Hy+3GnvNw/yUCIG/3Ee578KVYakq5pih8KSVeVjO37C2qj60d3Ok3XPqBAiEAqGPvxTsAuBDz0kcBIPqASGzArumljkrLsoHHkakOfU0CIDuhxKQwHlXFDO79ppYAPcVO3bph672qGD84YUaHF+pQ-----END PRIVATE KEY-----';
//使用公钥加密
var encrypt = new JSEncrypt();//实例化加密对象
encrypt.setPublicKey(PUBLIC_KEY);//设置公钥
var encrypted = encrypt.encrypt('hello bobo!');//对指定数据进行加密
console.log(encrypted);//使用私钥解密

//使用私钥解密
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(PRIVATE_KEY);//设置私钥
var uncrypted = decrypt.decrypt(encrypted);//解密
console.log(uncrypted);

Python代码示例:

1.创建公钥和私钥

from Crypto.PublicKey import RSA

# 通过相关算法生成唯一秘钥
rsakey = RSA.generate(1024)
#将秘钥保存到文件中
with open("rsa.public.pem", mode="wb") as f:
    f.write(rsakey.publickey().exportKey())

with open("rsa.private.pem", mode="wb") as f:
    f.write(rsakey.exportKey())

2.加密算法实现

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

# 加密
data = "我喜欢你"
with open("rsa.public.pem", mode="r") as f:
    pk = f.read()
    rsa_pk = RSA.importKey(pk)
    #基于公钥创建加密对象
    rsa = PKCS1_v1_5.new(rsa_pk)

    result = rsa.encrypt(data.encode("utf-8"))
    # 处理成b64方便传输
    b64_result = base64.b64encode(result).decode("utf-8")
    print(b64_result)

3.解密算法实现

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

data = '17wJJtBBujJurHRu3teDC44jSllmqcB9a22U1DQ5/IsI0m3NuShPTxBq8pLTWRdszPapiXfjvOh47P9u5+7U4hvNZL+kKqs3H5m4BKKphORUUfqb9zTowoHb1mM9ji2LuMAYmc1l70ZR+s9XsV3HrHCV/S2FzGWngcWpNVtsTJg='
# 解密
with open("rsa.private.pem", mode="r") as f:
    prikey = f.read()
    rsa_pk = RSA.importKey(prikey)
    #创建解密对象
    rsa = PKCS1_v1_5.new(rsa_pk)
    result = rsa.decrypt(base64.b64decode(data), None)
    print("rsa解密数据:::", result.decode("utf-8"))
  • 上述代码提取关键字:
    • RSA
    • setPublicKey(设置公钥)
    • setPrivateKey(设置私钥)
    • encrypt,decrypt
posted @ 2025-09-29 17:09  凫弥  阅读(42)  评论(0)    收藏  举报