TS实现charles注册机

仅仅是将已有的注册机go语言版本转换为js版本。

go代码来自 www.zzzmode.com/mytools/cha...

代码中大量使用 int32ToInt32 函数主要为了防止数值超出 int32 类型可表示的范围。

1.主函数

ts 复制代码
import crypto from "crypto";
import { bigIntUnsignedRightShift, byte, int32ToInt32, rotateLeft, transform } from "./utils.js";
import ckCipher from "./ckCipher.js";

function main() {
  const name = "charles";
  console.log(`name: ${name}    key: ${crack(name)}`);
  console.log("程序正在运行,按任意键退出...");
  process.stdin.setRawMode(true);
  process.stdin.resume();
  process.stdin.on("data", () => process.exit());
}

function crack(text: string) {
  const name = byte(Buffer.from(text, "ascii"));
  const length = name.length + 4;
  const padded = length + (-length & (8 - 1));
  const bs = byte(4);
  const _bs = Buffer.from(bs);
  _bs.writeUInt32BE(transform(BigInt(name.length), "int64", "uint32"), 0);
  bs.set(_bs);
  const buff = byte(Buffer.concat([bs, name]));

  const ckName = BigInt("0x7a21c951691cd470");
  const ckKey = BigInt("-5408575981733630035");
  const ck = new ckCipher(ckName);
  let outBuff = byte(padded);

  for (let i = 0; i < padded; i += 8) {
    const bf = buff.subarray(i, i + 8);
    let fixBf = byte(0);
    if (bf.byteLength < 8) fixBf = byte(8 - bf.byteLength);
    const buf = Buffer.concat([Buffer.from(bf), Buffer.from(fixBf)]);
    const nowVar = buf.readBigInt64BE() as Int64;
    const dd: Int64 = ck.encrypt(nowVar);
    outBuff[i] = transform(dd >> 56n, "int64", "uint8");
    outBuff[i + 1] = transform(dd >> 48n, "int64", "uint8");
    outBuff[i + 2] = transform(dd >> 40n, "int64", "uint8");
    outBuff[i + 3] = transform(dd >> 32n, "int64", "uint8");
    outBuff[i + 4] = transform(dd >> 24n, "int64", "uint8");
    outBuff[i + 5] = transform(dd >> 16n, "int64", "uint8");
    outBuff[i + 6] = transform(dd >> 8n, "int64", "uint8");
    outBuff[i + 7] = transform(dd, "int64", "uint8");
  }

  let n = 0 as Int32;
  for (const b of outBuff) {
    const signedB: Int32 = transform(transform(b, "uint8", "int8"), "int8", "int32");
    n = rotateLeft(int32ToInt32(n ^ signedB), 0x3);
  }
  const prefix: Int32 = int32ToInt32(n ^ 0x54882f8a);
  const suffixBuffer = crypto.randomBytes(4);
  const suffix: Int32 = suffixBuffer.readInt32LE();
  let inVal: Int64 = transform(prefix, "int32", "int64") << 32n;
  const s: Int64 = transform(suffix, "int32", "int64");

  const suffixHigh: Int32 = suffix >> 16;
  if (suffixHigh === 0x0401 || suffixHigh === 0x0402 || suffixHigh === 0x0403) {
    inVal |= s;
  } else {
    inVal |= 0x01000000n | (s & 0xffffffn);
  }
  const out: Int64 = new ckCipher(ckKey).decrypt(inVal);

  let n2: Int64 = 0n;
  for (let i = 56; i >= 0; i -= 8) {
    n2 ^=
      transform(
        bigIntUnsignedRightShift(transform(inVal, "int64", "uint64"), BigInt(i)),
        "uint64",
        "int64"
      ) & 0xffn;
  }

  let vv: Int32 = transform(n2 & 0xffn, "int64", "int32");
  if (vv < 0) vv = -vv;

  return `${vv.toString(16).padStart(2, "0")}${BigInt.asUintN(64, out)
    .toString(16)
    .padStart(16, "0")}`;
}

main();

2.工具函数

rotateLeftrotateRightpkLong 为原来代码中的辅助函数。

transform 函数实现了简单的 int64uint64int32uint32int8uint8 数据类型互转功能。

byteint32ToInt32 为工具函数。

bigIntUnsignedRightShift 函数让 bigint 类型支持无符号右移。

ts 复制代码
// utils.ts
export function rotateLeft(x: Int32, y: Int32): Int32 {
  return int32ToInt32(
    int32ToInt32(x << int32ToInt32(y & 31)) |
      int32ToInt32(transform(x, "int32", "uint32") >>> int32ToInt32(32 - int32ToInt32(y & 31)))
  );
}

export function rotateRight(x: Int32, y: Int32): Int32 {
  return int32ToInt32(
    int32ToInt32(transform(x, "int32", "uint32") >>> int32ToInt32(y & 31)) |
      int32ToInt32(x << int32ToInt32(32 - int32ToInt32(y & 31)))
  );
}

export function pkLong(a: Int32, b: Int32): Int64 {
  return (BigInt(a) & 0xffffffffn) | (BigInt(b) << 32n);
}

/**数据类型转换
 * @param num 要转换的数字
 * @param type 转换类型
 */
export function transform(num: Int8, originType: "int8", type: "int8"): Int8;
export function transform(num: Int8, originType: "int8", type: "uint8"): UInt8;
export function transform(num: Int8, originType: "int8", type: "int32"): Int32;
export function transform(num: Int8, originType: "int8", type: "uint32"): UInt32;
export function transform(num: Int8, originType: "int8", type: "int64"): Int64;
export function transform(num: Int8, originType: "int8", type: "uint64"): UInt64;
export function transform(num: UInt8, originType: "uint8", type: "int8"): Int8;
export function transform(num: UInt8, originType: "uint8", type: "uint8"): UInt8;
export function transform(num: UInt8, originType: "uint8", type: "int32"): Int32;
export function transform(num: UInt8, originType: "uint8", type: "uint32"): UInt32;
export function transform(num: UInt8, originType: "uint8", type: "int64"): Int64;
export function transform(num: UInt8, originType: "uint8", type: "uint64"): UInt64;
export function transform(num: Int32, originType: "int32", type: "int8"): Int8;
export function transform(num: Int32, originType: "int32", type: "uint8"): UInt8;
export function transform(num: Int32, originType: "int32", type: "int32"): Int32;
export function transform(num: Int32, originType: "int32", type: "uint32"): UInt32;
export function transform(num: Int32, originType: "int32", type: "int64"): Int64;
export function transform(num: Int32, originType: "int32", type: "uint64"): UInt64;
export function transform(num: UInt32, originType: "uint32", type: "int8"): Int8;
export function transform(num: UInt32, originType: "uint32", type: "uint8"): UInt8;
export function transform(num: UInt32, originType: "uint32", type: "int32"): Int32;
export function transform(num: UInt32, originType: "uint32", type: "uint32"): UInt32;
export function transform(num: UInt32, originType: "uint32", type: "int64"): Int64;
export function transform(num: UInt32, originType: "uint32", type: "uint64"): UInt64;
export function transform(num: Int64, originType: "int64", type: "int8"): Int8;
export function transform(num: Int64, originType: "int64", type: "uint8"): UInt8;
export function transform(num: Int64, originType: "int64", type: "int32"): Int32;
export function transform(num: Int64, originType: "int64", type: "uint32"): UInt32;
export function transform(num: Int64, originType: "int64", type: "int64"): Int64;
export function transform(num: Int64, originType: "int64", type: "uint64"): UInt64;
export function transform(num: UInt64, originType: "uint64", type: "int8"): Int8;
export function transform(num: UInt64, originType: "uint64", type: "uint8"): UInt8;
export function transform(num: UInt64, originType: "uint64", type: "int32"): Int32;
export function transform(num: UInt64, originType: "uint64", type: "uint32"): UInt32;
export function transform(num: UInt64, originType: "uint64", type: "int64"): Int64;
export function transform(num: UInt64, originType: "uint64", type: "uint64"): UInt64;
export function transform(
  num: Int8 | UInt8 | Int32 | UInt32 | Int64 | UInt64,
  originType: "int8" | "uint8" | "int32" | "uint32" | "int64" | "uint64",
  type: "int8" | "uint8" | "int32" | "uint32" | "int64" | "uint64"
): Int8 | UInt8 | Int32 | UInt32 | Int64 | UInt64 | undefined {
  const buffer = Buffer.alloc(8);

  if (originType === "int8" || originType === "int32" || originType === "int64")
    buffer.writeBigInt64LE(typeof num === "bigint" ? num : BigInt(num));
  else if (originType === "uint8" || originType === "uint32" || originType === "uint64")
    buffer.writeBigUInt64LE(typeof num === "bigint" ? num : BigInt(num));

  if (type === "int32") return buffer.readInt32LE();
  else if (type === "uint32") return buffer.readUInt32LE();
  else if (type === "int8") return buffer.readInt8();
  else if (type === "uint8") return buffer.readUInt8();
  else if (type === "int64") return buffer.readBigInt64LE();
  else if (type === "uint64") return buffer.readBigUInt64LE();
}

export function byte(length: number): Uint8Array<ArrayBuffer>;
export function byte(buffer: Buffer<ArrayBuffer>): Uint8Array<ArrayBuffer>;
export function byte(arg: Buffer<ArrayBuffer> | number) {
  if (typeof arg === "number") return new Uint8Array(arg);
  else if (arg instanceof Buffer) return new Uint8Array(arg);
}

/**bigint类型无符号右移
 * @param bigIntValue 要执行无符号右移的 BigInt 值
 * @param shiftAmount 右移的位数
 */
export function bigIntUnsignedRightShift(bigIntValue: bigint, shiftAmount: bigint) {
  // 将 shiftAmount 转换为 BigInt 类型
  const shift = BigInt(shiftAmount);
  // 执行右移操作
  const result = bigIntValue >> shift;
  // 处理负数情况,如果是负数则需要额外处理
  if (bigIntValue < 0n) {
    // 计算掩码,用于清除高位的符号扩展
    const mask = (1n << (64n - shift)) - 1n;
    return result & mask;
  }
  return result;
}

export function int32ToInt32(num: Int32) {
  return transform(num, "int32", "int32");
}

3.ckCipher类的封装

ts 复制代码
// ckCipher.ts
import {
  bigIntUnsignedRightShift,
  int32ToInt32,
  pkLong,
  rotateLeft,
  rotateRight,
  transform,
} from "./utils.js";

export default class ckCipher {
  rk: Int32[];
  rounds = 12;
  roundKeys = 2 * (this.rounds + 1);
  constructor(ckKey: bigint) {
    this.rk = [this.roundKeys];
    const ld = new Int32Array(2);
    ld[0] = transform(ckKey, "int64", "int32");
    ld[1] = transform(
      bigIntUnsignedRightShift(transform(ckKey, "int64", "uint64"), 32n),
      "uint64",
      "int32"
    );

    this.rk[0] = -1209970333;
    for (let i = 1; i < this.roundKeys; i++) {
      this.rk[i] = int32ToInt32(this.rk[i - 1]! + -1640531527);
    }
    let a = 0;
    let b = 0;
    let i = 0;
    let j = 0;

    for (let k = 0; k < 3 * this.roundKeys; k++) {
      this.rk[i] = rotateLeft(this.rk[i]! + (a + b), 3);
      a = this.rk[i]!;
      ld[j] = rotateLeft(ld[j]! + (a + b), a + b);
      b = ld[j]!;
      i = (i + 1) % this.roundKeys;
      j = (j + 1) % 2;
    }
  }
  encrypt(num: Int64): Int64 {
    let a: Int32 = transform(
      BigInt(transform(num, "int64", "int32") + this.rk[0]!),
      "int64",
      "int32"
    );
    let b: Int32 = int32ToInt32(
      transform(
        bigIntUnsignedRightShift(transform(num, "int64", "uint64"), 32n),
        "uint64",
        "int32"
      ) + this.rk[1]!
    );
    for (let r = 1; r <= this.rounds; r++) {
      a = int32ToInt32(rotateLeft(int32ToInt32(a ^ b), b) + this.rk[2 * r]!);
      b = int32ToInt32(rotateLeft(int32ToInt32(b ^ a), a) + this.rk[2 * r + 1]!);
    }
    return pkLong(a, b);
  }
  decrypt(num: Int64): Int64 {
    let a: Int32 = transform(num, "int64", "int32");
    let b: Int32 = transform(
      bigIntUnsignedRightShift(transform(num, "int64", "uint64"), 32n),
      "uint64",
      "int32"
    );

    for (let i = this.rounds; i > 0; i--) {
      b = int32ToInt32(rotateRight(int32ToInt32(b - this.rk[2 * i + 1]!), a) ^ a);
      a = int32ToInt32(rotateRight(int32ToInt32(a - this.rk[2 * i]!), b) ^ b);
    }

    a = int32ToInt32(a - this.rk[0]!);
    b = int32ToInt32(b - this.rk[1]!);
    return pkLong(a, b);
  }
}

4.其他

类型别名

ts 复制代码
type Int32 = number;
type Int64 = bigint;
type UInt32 = number;
type UInt64 = bigint;
type Int8 = number;
type UInt8 = number;
相关推荐
栀秋6663 分钟前
深入浅出链表操作:从Dummy节点到快慢指针的实战精要
前端·javascript·算法
狗哥哥19 分钟前
Vue 3 动态菜单渲染优化实战:从白屏到“零延迟”体验
前端·vue.js
青青很轻_21 分钟前
Vue自定义拖拽指令架构解析:从零到一实现元素自由拖拽
前端·javascript·vue.js
树下水月28 分钟前
纯HTML 调用摄像头 获取拍照后的图片的base64
前端·javascript·html
蜗牛攻城狮32 分钟前
Vue 中 `scoped` 样式的实现原理详解
前端·javascript·vue.js
豆苗学前端37 分钟前
前端工程化终极指南(Webpack + Gulp + Vite + 实战项目)
前端·javascript
比老马还六38 分钟前
Bipes项目二次开发/海龟编程(六)
前端·javascript
梨子同志38 分钟前
Node.js 文件系统 fs
前端
码农胖大海39 分钟前
微前端架构(二):封装与实现
前端
瘦的可以下饭了40 分钟前
2 数组 递归 复杂度 字符串
前端·javascript