关于一次测试中的加密算法解读
字数 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 初始处理阶段
-
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)
- 前导4字符:
-
组合最终结果:
- 格式:
h + newDataArr.join("") + f - 例如:
7kv5+bIvndVczhZcXhIfxsMuCwIjIinkVpztZ6XxI5x9MtC6IhI4n8VwzdZeXqIvxkM3CeI+n0zobdxjawj
- 格式:
4. 解密算法实现
4.1 解密步骤
-
去除前后缀:
- 去掉前4个字符和后8个字符
- 获取中间核心加密数据
-
提取有效字符:
- 从核心数据中提取所有奇数位字符(JavaScript数组从0开始计数)
- 因为加密时偶数索引插入的是随机字符,奇数索引才是原始数据
-
Base64解码:
- 将提取的字符组合后进行Base64解码
- 得到JSON格式的原始字符串
-
去除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
解密步骤:
-
去除前后缀:
- 前4字符:
7kv5 - 后8字符:
9pvs94cc - 核心数据:
bIvndVczhZcXhIfxsMuCwI121wwl12fuh7jIinkVpztZ6XxI5x9MtC6In0zobdxjawjwhI4n8VwzdZeXqIvxkM3CeI
- 前4字符:
-
提取奇数位字符(反向):
- 得到:
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()始终添加到数组末尾,最终字符顺序保持不变:
原始: [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 算法优缺点
优点:
- 增加随机字符干扰,防止简单Base64解码
- 前后随机字符串增加破解难度
- 保持原始数据顺序,便于处理
缺点:
- 随机字符位置固定(奇数位),模式可识别
- 前后缀长度固定,易于去除
- 依赖客户端JavaScript,可被逆向分析
6.2 增强建议
- 随机化插入位置(不固定奇偶)
- 使用动态长度的前后缀
- 增加多层加密或混淆
- 结合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的增强型加密算法,涵盖以下关键内容:
- 完整算法逆向分析过程
- 加密/解密的具体实现步骤
- JavaScript核心函数详解
- 完整可运行代码实现
- 安全性与改进建议
通过本教学,读者可以深入理解:
- 如何分析复杂的加密算法
- JavaScript加密技术的实现方式
- Base64编码的扩展应用
- 前端数据保护的基本方法
此知识可用于安全测试、加密算法分析和前端开发中的数据处理场景。