简介
兽音加密为对称加密
明文为字符串的Unicode码 秘钥为字符位置索引
得到密文后简单的变形再去查表得到具体的字符
通常表设置为['嗷', '呜', '啊', '~']这四个字符
简单的说你只需要~!@# 再 $%^& 再 *()_ 就得到结果了
加密过程
- 原字符串→
原神启动- 查Unicode→ u539f\u795e\u542f\u52a8
- 转数组→ [539f, 795e, 542f, 52a8]
- 可以用字符串存储也可以用数字存储
- 第一次拆→ [{5,3,9,f}, {7,9,5,e}, {5,4,2,f}, {5,2,a,8}]
- 可以按字符串位置拆也可以用位运算得到4个位置上的数字
- 扁平化→ [5, 3, 9, f, 7, 9, 5, e, 5, 4, 2, f, 5, 2, a, 8]
- 加上索引→ [5+0, 3+1, 9+2, f+3, 7+4, 9+5, 5+6, e+7, 5+8, 4+9, 2+a, f+b, 5+c, 2+d, a+e, 8+f]
- 示例中使用16进制数据
- 计算结果→ [5, 4, b, 12, b, e, b, 15, d, d, c, 1a, 11, f, 18, 17]
- 去掉溢出→ [5, 4, b, 2, b, e, b, 5, d, d, c, a, 1, f, 8, 7]
- 第二次拆→ [{1,1}, {1,0}, {2,3}, {0,2}, {2,3}, {3,2}, {2,3}, {1,1}, {3,1}, {3,1}, {3,0}, {2,2}, {0,1}, {3,3}, {2,0}, {1,3}]
- 将1个16进制数拆成2个4进制数
- 扁平化→ 11102302233223113131302201332013
- 加上头尾→ \310111023022332231131313022013320132
- 开头固定310 结尾固定2
- 查表→ ~呜嗷呜呜呜嗷啊~嗷啊啊~~啊啊~呜呜~呜~呜~嗷啊啊嗷呜~~啊嗷呜~啊
- 一般用['嗷', '呜', '啊', '~']作为字典 将上面数字映射为字典里对应的字符
- 最终结果→
~呜嗷呜呜呜嗷啊~嗷啊啊~~啊啊~呜呜~呜~呜~嗷啊啊嗷呜~~啊嗷呜~啊
解密过程
- 原字符串→
~呜嗷呜呜呜嗷啊~嗷啊啊~~啊啊~呜呜~呜~呜~嗷啊啊嗷呜~~啊嗷呜~啊- 拆分字符→ ['~呜嗷', '呜呜呜嗷啊~嗷啊啊~~啊啊~呜呜~呜~呜~嗷啊啊嗷呜~~啊嗷呜~', '啊']
- 把原字符串索引为0、1、2和最后一位单独拆出来
- 取字典→ ['嗷呜啊~', '呜呜呜嗷啊~嗷啊啊~~啊啊~呜呜~呜~呜~嗷啊啊嗷呜~~啊嗷呜~']
- 根据规则前三位实际上是字典表中的310 最后一位是2 重新排个序直观一点
并非所有人用默认表加密取表只需固定取前三位和最后一位 就能知道原来是什么了
- 字典映射→ 11102302233223113131302201332013
- 把除字典以外的字符通过字典映射为字典索引数字
- 两两一组→ [{1,1}, {1,0}, {2,3}, {0,2}, {2,3}, {3,2}, {2,3}, {1,1}, {3,1}, {3,1}, {3,0}, {2,2}, {0,1}, {3,3}, {2,0}, {1,3}]
- 由于加密特性长度一定是偶数 放心大胆的拆
- 合并→ [5, 4, b, 2, b, e, b, 5, d, d, c, a, 1, f, 8, 7]
- 第一个数字是高位 第二个数字是低位 新数=高位x进制+低位
- 减去索引→ [5-0, 4-1, b-2, 2-3, b-4, e-5, b-6, 5-7, d-8, d-9, c-a, a-b, 1-c, f-d, 8-e, 7-f]
- 计算结果→ [5, 3, 9, f, 7, 9, 5, -2, 5, 4, 2, -1, -b, 2, -6, -8]
- 去掉溢出→ [5, 3, 9, f, 7, 9, 5, e, 5, 4, 2, f, 5, 2, a, 8]
- 计算机存储负数原理不多赘述
- 四个一组→ [{5,3,9,f}, {7,9,5,e}, {5,4,2,f}, {5,2,a,8}]
- 合并→ [539f, 795e, 542f, 52a8]
- Unicode→ \u539f\u795e\u542f\u52a8
- 原文→ 原神启动
- 拆分字符→ ['~呜嗷', '呜呜呜嗷啊~嗷啊啊~~啊啊~呜呜~呜~呜~嗷啊啊嗷呜~~啊嗷呜~', '啊']
- 最终结果→
原神启动
代码实现
// 默认加密字典
const defaultMap = ['嗷', '呜', '啊', '~']
// 加密
const enc = (data, map = defaultMap) => {
const nums = [...data]
// 获取unicode码
.map(value => value.codePointAt(0))
// 拆分为4位
.map(num => [(num >> 12) & 0xf, (num >> 8) & 0xf, (num >> 4) & 0xf, (num >> 0) & 0xf])
.flatMap(i => i)
// 变形一下
.map((num, index) => index + num)
// 拆分为2位
.map(num => [((num & 0xf) >> 2) & 0x3, ((num & 0xf) >> 0) & 0x3])
.flatMap(i => i)
return [3, 1, 0, ...nums, 2]
// 取字典
.map(index => map[index])
// 拼接
.join('')
}
// 解密
const dec = (data) => {
const map = {
[data.at(0)]: 3,
[data.at(1)]: 1,
[data.at(2)]: 0,
[data.at(-1)]: 2
}
return [...data.slice(3, -1)]
// 还原
.map(value => map[value])
// 两个一组
.reduce((acc, cur, index) => {
const i = index % 2
i === 0 && acc.push([])
acc.at(-1)[i] = cur
return acc
}, [])
// 合并为16进制
.map(([a, b]) => (parseInt(a) << 2) + parseInt(b))
// 变形
.map((num, index) => (num - index) & 0xf)
// 四个一组
.reduce((acc, cur, index) => {
const i = index % 4
i === 0 && acc.push([])
acc.at(-1)[i] = cur
return acc
}, [])
// 合并
.map(([a, b, c, d]) => (a << 12) + (b << 8) + (c << 4) + (d << 0))
// 还原
.map(value => String.fromCodePoint(value))
// 拼接
.join('')
}