关于一次测试中的加密算法解读
字数 2876 2025-08-15 21:33:28

Base64加密算法逆向解析与实现教学文档

1. 加密算法概述

本教学文档基于FreeBuf文章描述的加密算法进行详细解析,该算法用于前端用户名和密码的加密传输,主要特点如下:

  • 使用Base64编码作为基础
  • 通过随机字符插入增加复杂度
  • 前后添加随机字符串增强安全性
  • 采用栈式处理保持原始数据顺序

2. 加密函数结构分析

2.1 函数定义

function getBase64Data(data) {
    var base = new Base64();
    var newDataArr = [];
    // form data is json object
    var formDataArr = base.encode(JSON.stringify(data)).split("");
    var forLength = formDataArr.length * 2;
    
    for (var i = 0; i < forLength; i++) {
        if (formDataArr.length == 0) {
            break;
        } else {
            if (!(i % 2)) {
                newDataArr.push(Math.random().toString(36).slice(-1));
            } else {
                newDataArr.push(formDataArr[formDataArr.length - 1]);
                formDataArr.pop();
            }
        }
    }
    
    var h = Math.random().toString(36).substr(2, 4);
    var f = Math.random().toString(36).substr(2, 8);
    return h + newDataArr.join("") + f;
}

2.2 关键变量说明

变量名 类型 描述
base Base64对象 用于Base64编码/解码
newDataArr Array 存储最终加密结果的数组
formDataArr Array 存储原始数据Base64编码后拆分的结果
forLength Number 循环次数的2倍
h String 前导随机字符串(4字符)
f String 后缀随机字符串(8字符)

3. 加密过程详解

3.1 初始处理阶段

  1. JSON字符串化JSON.stringify(data)

    • 将输入数据转换为JSON字符串格式
    • 例如:user10"user10"
  2. Base64编码base.encode()

    • 对JSON字符串进行Base64编码
    • 例如:"user10"InVzZXIxMCI=
  3. 字符串拆分.split("")

    • 将Base64编码结果拆分为字符数组
    • 例如:"InVzZXIxMCI="["I","n","V","z","Z","X","I","x","M","C","I","="]

3.2 核心加密循环

循环逻辑:

  • 循环次数为原始数据长度的2倍(formDataArr.length * 2
  • 当原始数据数组为空时终止循环(formDataArr.length == 0

循环体行为:

  1. 奇数索引(i%2 == 0)

    • 生成随机字符并添加到结果数组
    • Math.random().toString(36).slice(-1)
      • 生成0-1的随机数
      • 转换为36进制字符串(0-9a-z)
      • 取最后一位字符
  2. 偶数索引(i%2 != 0)

    • 从原始数据数组末尾取一个字符添加到结果数组
    • 移除原始数据数组的最后一个元素(formDataArr.pop()

示例处理过程

原始数据:user10 → Base64:InVzZXIxMCI= → 拆分:["I","n","V","z","Z","X","I","x","M","C","I","="]

循环处理:

  1. i=0(偶): 添加随机字符,如"k"
  2. i=1(奇): 添加"=",移除"="
  3. i=2(偶): 添加随机字符,如"j"
  4. i=3(奇): 添加"I",移除"I"
  5. ...依次处理所有字符

3.3 最终处理阶段

  1. 生成随机前后缀

    • 前导4字符:Math.random().toString(36).substr(2, 4)
    • 后缀8字符:Math.random().toString(36).substr(2, 8)
  2. 组合最终结果

    • 格式:h + newDataArr.join("") + f
    • 例如:7kv5 + bIvndVczhZcXhIfxsMuCwIjIinkVpztZ6XxI5x9MtC6IhI4n8VwzdZeXqIvxkM3CeI + n0zobdxjawj

4. 解密算法实现

4.1 解密步骤

  1. 去除前后缀

    • 去掉前4个字符和后8个字符
    • 获取中间核心加密数据
  2. 提取有效字符

    • 从核心数据中提取所有奇数位字符(JavaScript数组从0开始计数)
    • 因为加密时偶数索引插入的是随机字符,奇数索引才是原始数据
  3. Base64解码

    • 将提取的字符组合后进行Base64解码
    • 得到JSON格式的原始字符串
  4. 去除JSON引号

    • 去掉结果字符串的首尾双引号
    • 得到最终原始数据

4.2 JavaScript解密实现

function decryptBase64Data(encrypted) {
    // 1. 去除前后缀
    const coreData = encrypted.slice(4, -8);
    
    // 2. 提取有效字符(原加密时的偶数索引,现在是奇数索引)
    let originalBase64 = '';
    for (let i = 0; i < coreData.length; i++) {
        if (i % 2 !== 0) { // 注意原加密时奇数索引是有效数据
            originalBase64 = coreData[i] + originalBase64; // 反向拼接
        }
    }
    
    // 3. Base64解码
    const base = new Base64();
    const jsonStr = base.decode(originalBase64);
    
    // 4. 去除JSON引号
    return jsonStr.slice(1, -1);
}

4.3 解密示例

加密结果:7kv5bIvndVczhZcXhIfxsMuCwI121wwl12fuh7jIinkVpztZ6XxI5x9MtC6In0zobdxjawjwhI4n8VwzdZeXqIvxkM3CeI9pvs94cc

解密步骤:

  1. 去除前后缀:

    • 前4字符:7kv5
    • 后8字符:9pvs94cc
    • 核心数据:bIvndVczhZcXhIfxsMuCwI121wwl12fuh7jIinkVpztZ6XxI5x9MtC6In0zobdxjawjwhI4n8VwzdZeXqIvxkM3CeI
  2. 提取奇数位字符(反向):

    • 得到:lnVzZXlxMCl
  3. Base64解码:

    • lnVzZXlxMCl"user10"
  4. 去除引号:

    • "user10"user10

5. 关键知识点详解

5.1 Base64编码特性

  • 编码原理:将3个8位字节转换为4个6位字节(3×8=4×6=24)
  • 填充规则:不足3字节用0填充,输出使用'='表示
  • 本文实现中=可以忽略,不影响解码

5.2 Math.random().toString(36)

  • Math.random():生成0-1的伪随机数
  • toString(36):将数字转换为36进制字符串(0-9a-z)
  • slice(-1):取字符串最后一位
  • substr(2,4):从第2位开始取4个字符

5.3 数组操作方法

  • split(""):将字符串拆分为字符数组
  • push():向数组末尾添加元素
  • pop():移除并返回数组最后一个元素
  • join(""):将数组元素合并为字符串

5.4 栈式处理顺序

虽然加密时从后向前取出原始数据字符,但由于push()始终添加到数组末尾,最终字符顺序保持不变:

原始: [a,b,c,d]
处理:
1. 取d → push → [d]
2. 取c → push → [d,c]
3. 取b → push → [d,c,b]
4. 取a → push → [d,c,b,a]
反转后: a,b,c,d (保持原序)

6. 实际应用与安全分析

6.1 算法优缺点

优点

  1. 增加随机字符干扰,防止简单Base64解码
  2. 前后随机字符串增加破解难度
  3. 保持原始数据顺序,便于处理

缺点

  1. 随机字符位置固定(奇数位),模式可识别
  2. 前后缀长度固定,易于去除
  3. 依赖客户端JavaScript,可被逆向分析

6.2 增强建议

  1. 随机化插入位置(不固定奇偶)
  2. 使用动态长度的前后缀
  3. 增加多层加密或混淆
  4. 结合HTTPS传输防止中间人攻击

7. 完整实现代码

7.1 加密实现

class Base64 {
    // 简化的Base64实现
    static chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    
    encode(data) {
        let result = '';
        let i = 0;
        const len = data.length;
        
        while (i < len) {
            const c1 = data.charCodeAt(i++) & 0xff;
            const c2 = i < len ? data.charCodeAt(i++) & 0xff : 0;
            const c3 = i < len ? data.charCodeAt(i++) & 0xff : 0;
            
            const b1 = c1 >> 2;
            const b2 = ((c1 & 0x3) << 4) | (c2 >> 4);
            const b3 = ((c2 & 0xf) << 2) | (c3 >> 6);
            const b4 = c3 & 0x3f;
            
            result += Base64.chars.charAt(b1) + Base64.chars.charAt(b2) + 
                      Base64.chars.charAt(b3) + Base64.chars.charAt(b4);
        }
        
        // 处理填充
        const pad = len % 3;
        if (pad > 0) {
            result = result.slice(0, result.length - (3 - pad)) + '='.repeat(3 - pad);
        }
        
        return result;
    }
    
    decode(data) {
        // 简化解码实现
        let result = '';
        data = data.replace(/=+$/, '');
        let i = 0;
        const len = data.length;
        
        while (i < len) {
            const b1 = Base64.chars.indexOf(data.charAt(i++));
            const b2 = Base64.chars.indexOf(data.charAt(i++));
            const b3 = Base64.chars.indexOf(data.charAt(i++));
            const b4 = Base64.chars.indexOf(data.charAt(i++));
            
            const c1 = (b1 << 2) | (b2 >> 4);
            const c2 = ((b2 & 0xf) << 4) | (b3 >> 2);
            const c3 = ((b3 & 0x3) << 6) | b4;
            
            result += String.fromCharCode(c1);
            if (b3 !== 64) result += String.fromCharCode(c2);
            if (b4 !== 64) result += String.fromCharCode(c3);
        }
        
        return result;
    }
}

function getBase64Data(data) {
    const base = new Base64();
    const newDataArr = [];
    const formDataArr = base.encode(JSON.stringify(data)).split("");
    const forLength = formDataArr.length * 2;
    
    for (let i = 0; i < forLength; i++) {
        if (formDataArr.length === 0) break;
        
        if (i % 2 === 0) {
            newDataArr.push(Math.random().toString(36).slice(-1));
        } else {
            newDataArr.push(formDataArr.pop());
        }
    }
    
    const h = Math.random().toString(36).substr(2, 4);
    const f = Math.random().toString(36).substr(2, 8);
    return h + newDataArr.join("") + f;
}

7.2 解密实现

function decryptBase64Data(encrypted) {
    if (encrypted.length < 12) {
        throw new Error("Invalid encrypted data - too short");
    }
    
    const coreData = encrypted.slice(4, -8);
    let originalBase64 = '';
    
    // 反向处理,因为加密时是倒序pop的
    for (let i = coreData.length - 1; i >= 0; i--) {
        if (i % 2 !== 0) { // 原加密时的奇数位是有效数据
            originalBase64 += coreData[i];
        }
    }
    
    const base = new Base64();
    let jsonStr;
    try {
        jsonStr = base.decode(originalBase64);
    } catch (e) {
        throw new Error("Base64 decode failed - invalid encrypted data");
    }
    
    if (!jsonStr.startsWith('"') || !jsonStr.endsWith('"')) {
        throw new Error("Invalid JSON string format");
    }
    
    return jsonStr.slice(1, -1);
}

8. 测试用例

// 测试加密解密
const testCases = [
    "user10",
    "password123",
    "admin",
    "test@example.com",
    "a", // 短字符串
    "VeryLongStringWithSpecialChars!@#$%^&*()" // 长字符串
];

testCases.forEach(testCase => {
    const encrypted = getBase64Data(testCase);
    const decrypted = decryptBase64Data(encrypted);
    
    console.log(`Original: ${testCase}`);
    console.log(`Encrypted: ${encrypted}`);
    console.log(`Decrypted: ${decrypted}`);
    console.log(`Match: ${testCase === decrypted ? "✓" : "✗"}`);
    console.log("---------------------");
});

9. 总结

本教学文档详细解析了一种基于Base64的增强型加密算法,涵盖以下关键内容:

  1. 完整算法逆向分析过程
  2. 加密/解密的具体实现步骤
  3. JavaScript核心函数详解
  4. 完整可运行代码实现
  5. 安全性与改进建议

通过本教学,读者可以深入理解:

  • 如何分析复杂的加密算法
  • JavaScript加密技术的实现方式
  • Base64编码的扩展应用
  • 前端数据保护的基本方法

此知识可用于安全测试、加密算法分析和前端开发中的数据处理场景。

Base64加密算法逆向解析与实现教学文档 1. 加密算法概述 本教学文档基于FreeBuf文章描述的加密算法进行详细解析,该算法用于前端用户名和密码的加密传输,主要特点如下: 使用Base64编码作为基础 通过随机字符插入增加复杂度 前后添加随机字符串增强安全性 采用栈式处理保持原始数据顺序 2. 加密函数结构分析 2.1 函数定义 2.2 关键变量说明 | 变量名 | 类型 | 描述 | |--------|------|------| | base | Base64对象 | 用于Base64编码/解码 | | newDataArr | Array | 存储最终加密结果的数组 | | formDataArr | Array | 存储原始数据Base64编码后拆分的结果 | | forLength | Number | 循环次数的2倍 | | h | String | 前导随机字符串(4字符) | | f | String | 后缀随机字符串(8字符) | 3. 加密过程详解 3.1 初始处理阶段 JSON字符串化 : JSON.stringify(data) 将输入数据转换为JSON字符串格式 例如: user10 → "user10" Base64编码 : base.encode() 对JSON字符串进行Base64编码 例如: "user10" → InVzZXIxMCI= 字符串拆分 : .split("") 将Base64编码结果拆分为字符数组 例如: "InVzZXIxMCI=" → ["I","n","V","z","Z","X","I","x","M","C","I","="] 3.2 核心加密循环 循环逻辑: 循环次数为原始数据长度的2倍( formDataArr.length * 2 ) 当原始数据数组为空时终止循环( formDataArr.length == 0 ) 循环体行为: 奇数索引(i%2 == 0) : 生成随机字符并添加到结果数组 Math.random().toString(36).slice(-1) : 生成0-1的随机数 转换为36进制字符串(0-9a-z) 取最后一位字符 偶数索引(i%2 != 0) : 从原始数据数组末尾取一个字符添加到结果数组 移除原始数据数组的最后一个元素( formDataArr.pop() ) 示例处理过程 : 原始数据: user10 → Base64: InVzZXIxMCI= → 拆分: ["I","n","V","z","Z","X","I","x","M","C","I","="] 循环处理: i=0(偶): 添加随机字符,如"k" i=1(奇): 添加"=",移除"=" i=2(偶): 添加随机字符,如"j" i=3(奇): 添加"I",移除"I" ...依次处理所有字符 3.3 最终处理阶段 生成随机前后缀 : 前导4字符: Math.random().toString(36).substr(2, 4) 后缀8字符: Math.random().toString(36).substr(2, 8) 组合最终结果 : 格式: h + newDataArr.join("") + f 例如: 7kv5 + bIvndVczhZcXhIfxsMuCwIjIinkVpztZ6XxI5x9MtC6IhI4n8VwzdZeXqIvxkM3CeI + n0zobdxjawj 4. 解密算法实现 4.1 解密步骤 去除前后缀 : 去掉前4个字符和后8个字符 获取中间核心加密数据 提取有效字符 : 从核心数据中提取所有奇数位字符(JavaScript数组从0开始计数) 因为加密时偶数索引插入的是随机字符,奇数索引才是原始数据 Base64解码 : 将提取的字符组合后进行Base64解码 得到JSON格式的原始字符串 去除JSON引号 : 去掉结果字符串的首尾双引号 得到最终原始数据 4.2 JavaScript解密实现 4.3 解密示例 加密结果: 7kv5bIvndVczhZcXhIfxsMuCwI121wwl12fuh7jIinkVpztZ6XxI5x9MtC6In0zobdxjawjwhI4n8VwzdZeXqIvxkM3CeI9pvs94cc 解密步骤: 去除前后缀: 前4字符: 7kv5 后8字符: 9pvs94cc 核心数据: bIvndVczhZcXhIfxsMuCwI121wwl12fuh7jIinkVpztZ6XxI5x9MtC6In0zobdxjawjwhI4n8VwzdZeXqIvxkM3CeI 提取奇数位字符(反向): 得到: lnVzZXlxMCl Base64解码: lnVzZXlxMCl → "user10" 去除引号: "user10" → user10 5. 关键知识点详解 5.1 Base64编码特性 编码原理:将3个8位字节转换为4个6位字节(3×8=4×6=24) 填充规则:不足3字节用0填充,输出使用'='表示 本文实现中 = 可以忽略,不影响解码 5.2 Math.random().toString(36) Math.random() :生成0-1的伪随机数 toString(36) :将数字转换为36进制字符串(0-9a-z) slice(-1) :取字符串最后一位 substr(2,4) :从第2位开始取4个字符 5.3 数组操作方法 split("") :将字符串拆分为字符数组 push() :向数组末尾添加元素 pop() :移除并返回数组最后一个元素 join("") :将数组元素合并为字符串 5.4 栈式处理顺序 虽然加密时从后向前取出原始数据字符,但由于 push() 始终添加到数组末尾,最终字符顺序保持不变: 6. 实际应用与安全分析 6.1 算法优缺点 优点 : 增加随机字符干扰,防止简单Base64解码 前后随机字符串增加破解难度 保持原始数据顺序,便于处理 缺点 : 随机字符位置固定(奇数位),模式可识别 前后缀长度固定,易于去除 依赖客户端JavaScript,可被逆向分析 6.2 增强建议 随机化插入位置(不固定奇偶) 使用动态长度的前后缀 增加多层加密或混淆 结合HTTPS传输防止中间人攻击 7. 完整实现代码 7.1 加密实现 7.2 解密实现 8. 测试用例 9. 总结 本教学文档详细解析了一种基于Base64的增强型加密算法,涵盖以下关键内容: 完整算法逆向分析过程 加密/解密的具体实现步骤 JavaScript核心函数详解 完整可运行代码实现 安全性与改进建议 通过本教学,读者可以深入理解: 如何分析复杂的加密算法 JavaScript加密技术的实现方式 Base64编码的扩展应用 前端数据保护的基本方法 此知识可用于安全测试、加密算法分析和前端开发中的数据处理场景。