@honeybbq/teamspeak-client 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{crypt-init2-BIbQ7TN0.cjs → crypt-init2-C2oihZ7e.cjs} +2 -2
- package/dist/crypt-init2-C2oihZ7e.cjs.map +1 -0
- package/dist/{crypt-init2-C63eypta.js → crypt-init2-DWX7Tp-_.js} +36 -41
- package/dist/crypt-init2-DWX7Tp-_.js.map +1 -0
- package/dist/crypto/identity.d.ts.map +1 -1
- package/dist/crypto/index.cjs +1 -1
- package/dist/crypto/index.mjs +3 -3
- package/dist/crypto/primitives.d.ts +17 -2
- package/dist/crypto/primitives.d.ts.map +1 -1
- package/dist/{crypto-C3gBJkh2.cjs → crypto-2veVY1fC.cjs} +2 -2
- package/dist/{crypto-C3gBJkh2.cjs.map → crypto-2veVY1fC.cjs.map} +1 -1
- package/dist/{crypto-IGJlkTAl.js → crypto-VC7n6YJb.js} +12 -12
- package/dist/{crypto-IGJlkTAl.js.map → crypto-VC7n6YJb.js.map} +1 -1
- package/dist/{handler-C2vxlHYC.js → handler-C_JhqGTd.js} +2 -5
- package/dist/handler-C_JhqGTd.js.map +1 -0
- package/dist/{handler-DQteUMKT.cjs → handler-CqCD93f0.cjs} +2 -2
- package/dist/handler-CqCD93f0.cjs.map +1 -0
- package/dist/handshake/index.cjs +1 -1
- package/dist/handshake/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +72 -72
- package/dist/index.mjs.map +1 -1
- package/dist/{primitives-CmIK1O7L.js → primitives-BIAYfJ2Y.js} +12 -6
- package/dist/primitives-BIAYfJ2Y.js.map +1 -0
- package/dist/primitives-bj-ml31v.cjs +2 -0
- package/dist/primitives-bj-ml31v.cjs.map +1 -0
- package/dist/transport/handler.d.ts.map +1 -1
- package/dist/transport/index.cjs +1 -1
- package/dist/transport/index.mjs +1 -1
- package/package.json +4 -4
- package/dist/crypt-init2-BIbQ7TN0.cjs.map +0 -1
- package/dist/crypt-init2-C63eypta.js.map +0 -1
- package/dist/handler-C2vxlHYC.js.map +0 -1
- package/dist/handler-DQteUMKT.cjs.map +0 -1
- package/dist/primitives-BxtDMP7x.cjs +0 -2
- package/dist/primitives-BxtDMP7x.cjs.map +0 -1
- package/dist/primitives-CmIK1O7L.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`./primitives-
|
|
2
|
-
//# sourceMappingURL=crypt-init2-
|
|
1
|
+
const e=require(`./primitives-bj-ml31v.cjs`);var t=new Uint8Array([205,13,226,174,212,99,69,80,154,126,60,253,143,104,179,220,117,85,178,157,204,236,115,205,24,117,15,153,56,18,64,138]),n=function(e){return e[e.Intermediate=0]=`Intermediate`,e[e.Server=2]=`Server`,e[e.Ts5Server=8]=`Ts5Server`,e[e.Ephemeral=32]=`Ephemeral`,e}(n||{}),r=class{blocks;constructor(e){this.blocks=e}deriveKey(){let e=Uint8Array.from(t);for(let t of this.blocks)e=c(t,e);return e}};function i(e){if(e.length<1)throw Error(`license too short`);if(e[0]!==1)throw Error(`unsupported license version`);let t=e.slice(1),n=[];for(;t.length>0;){let{block:e,consumed:r}=a(t);n.push(e),t=t.slice(r)}return new r(n)}function a(t){if(t.length<42)throw Error(`license too short`);if(t[0]!==0)throw Error(`wrong key kind in license: ${t[0]}`);let n=t[33],r=1356998400,i=new DataView(t.buffer,t.byteOffset,t.byteLength),a=new Date((i.getUint32(34,!1)+r)*1e3),s=new Date((i.getUint32(38,!1)+r)*1e3);if(s<a)throw Error(`license times are invalid`);let c=Uint8Array.from(t.slice(1,33)),{payload:l,payloadRead:u}=o(n,t,42),d=42+u,f=t.slice(1,d),p=e.f(Uint8Array.from(f));return{block:{key:c,hash:Uint8Array.from(p.slice(0,32)),properties:l.properties,issuer:l.issuer,notValidBefore:a,notValidAfter:s,blockType:n,serverType:l.serverType},consumed:d}}function o(e,t,r){switch(e){case n.Intermediate:{let{str:e,read:n}=s(t.slice(46));return{payload:{issuer:e,serverType:0,properties:[],read:5+n},payloadRead:5+n}}case n.Server:{let{str:e,read:n}=s(t.slice(47));return{payload:{issuer:e,serverType:t[42]??0,properties:[],read:6+n},payloadRead:6+n}}case n.Ts5Server:{let e=t[43]===void 0?0:t[43],n=44,i=[];for(let r=0;r<e;r++){if(n>=t.length)throw Error(`license too short`);let e=t[n++];if(n+e>t.length)throw Error(`license too short`);i.push(Uint8Array.from(t.slice(n,n+e))),n+=e}return{payload:{issuer:``,serverType:t[42]??0,properties:i,read:n-r},payloadRead:n-r}}case n.Ephemeral:return{payload:{issuer:``,serverType:0,properties:[],read:0},payloadRead:0};default:throw Error(`invalid license block type: ${e}`)}}function s(e){for(let t=0;t<e.length;t++)if(e[t]===0)return{str:new TextDecoder().decode(e.slice(0,t)),read:t};throw Error(`non-null-terminated issuer string`)}function c(t,n){let r=Uint8Array.from(t.hash);e.n(r);let i=e.t(r),a=e.c.Point.fromBytes(t.key).negate(),o=e.c.Point.fromBytes(n).negate(),s=e.a(a,i).add(o).toBytes(),c=new Uint8Array(s.length);return c.set(s),c[31]=(c[31]===void 0?0:c[31])^128,c}function l(t,n,r,a,o,s){if(t.alphaTmp.length===0)throw Error(`alpha is not initialized`);let c=Buffer.from(n,`base64`),l=Buffer.from(r,`base64`),u=Buffer.from(a,`base64`),d=Buffer.from(o,`base64`);if(!e.s(e.m(l),c,u))throw Error(`init proof is not valid`);let f=e.i(i(c).deriveKey(),s);t.setSharedSecret(t.alphaTmp,d,f)}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return l}});
|
|
2
|
+
//# sourceMappingURL=crypt-init2-C2oihZ7e.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypt-init2-C2oihZ7e.cjs","names":[],"sources":["../src/handshake/license.ts","../src/handshake/crypt-init2.ts"],"sourcesContent":["import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alphaTmp.length === 0) {\n throw new Error(\"alpha is not initialized\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new Error(\"init proof is not valid\");\n }\n\n const licenses = parseLicenses(licenseBytes);\n const key = licenses.deriveKey();\n\n const sharedSecret = getSharedSecret2(key, privateKey);\n\n crypt.setSharedSecret(crypt.alphaTmp, betaBytes, sharedSecret);\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as e,
|
|
1
|
+
import { a as e, c as t, f as n, i as r, m as i, n as a, s as o, t as s } from "./primitives-BIAYfJ2Y.js";
|
|
2
2
|
//#region src/handshake/license.ts
|
|
3
|
-
var
|
|
3
|
+
var c = new Uint8Array([
|
|
4
4
|
205,
|
|
5
5
|
13,
|
|
6
6
|
226,
|
|
@@ -33,42 +33,42 @@ var o = new Uint8Array([
|
|
|
33
33
|
18,
|
|
34
34
|
64,
|
|
35
35
|
138
|
|
36
|
-
]),
|
|
36
|
+
]), l = /* @__PURE__ */ function(e) {
|
|
37
37
|
return e[e.Intermediate = 0] = "Intermediate", e[e.Server = 2] = "Server", e[e.Ts5Server = 8] = "Ts5Server", e[e.Ephemeral = 32] = "Ephemeral", e;
|
|
38
|
-
}(
|
|
38
|
+
}(l || {}), u = class {
|
|
39
39
|
blocks;
|
|
40
40
|
constructor(e) {
|
|
41
41
|
this.blocks = e;
|
|
42
42
|
}
|
|
43
43
|
deriveKey() {
|
|
44
|
-
let e = Uint8Array.from(
|
|
45
|
-
for (let t of this.blocks) e =
|
|
44
|
+
let e = Uint8Array.from(c);
|
|
45
|
+
for (let t of this.blocks) e = h(t, e);
|
|
46
46
|
return e;
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
|
-
function
|
|
49
|
+
function d(e) {
|
|
50
50
|
if (e.length < 1) throw Error("license too short");
|
|
51
51
|
if (e[0] !== 1) throw Error("unsupported license version");
|
|
52
52
|
let t = e.slice(1), n = [];
|
|
53
53
|
for (; t.length > 0;) {
|
|
54
|
-
let { block: e, consumed: r } =
|
|
54
|
+
let { block: e, consumed: r } = f(t);
|
|
55
55
|
n.push(e), t = t.slice(r);
|
|
56
56
|
}
|
|
57
|
-
return new
|
|
57
|
+
return new u(n);
|
|
58
58
|
}
|
|
59
|
-
function
|
|
59
|
+
function f(e) {
|
|
60
60
|
if (e.length < 42) throw Error("license too short");
|
|
61
61
|
if (e[0] !== 0) throw Error(`wrong key kind in license: ${e[0]}`);
|
|
62
|
-
let t = e[33],
|
|
63
|
-
if (o <
|
|
64
|
-
let s = Uint8Array.from(e.slice(1, 33)), { payload: c, payloadRead: l } =
|
|
62
|
+
let t = e[33], r = 1356998400, i = new DataView(e.buffer, e.byteOffset, e.byteLength), a = /* @__PURE__ */ new Date((i.getUint32(34, !1) + r) * 1e3), o = /* @__PURE__ */ new Date((i.getUint32(38, !1) + r) * 1e3);
|
|
63
|
+
if (o < a) throw Error("license times are invalid");
|
|
64
|
+
let s = Uint8Array.from(e.slice(1, 33)), { payload: c, payloadRead: l } = p(t, e, 42), u = 42 + l, d = e.slice(1, u), f = n(Uint8Array.from(d));
|
|
65
65
|
return {
|
|
66
66
|
block: {
|
|
67
67
|
key: s,
|
|
68
|
-
hash: Uint8Array.from(
|
|
68
|
+
hash: Uint8Array.from(f.slice(0, 32)),
|
|
69
69
|
properties: c.properties,
|
|
70
70
|
issuer: c.issuer,
|
|
71
|
-
notValidBefore:
|
|
71
|
+
notValidBefore: a,
|
|
72
72
|
notValidAfter: o,
|
|
73
73
|
blockType: t,
|
|
74
74
|
serverType: c.serverType
|
|
@@ -76,10 +76,10 @@ function u(e) {
|
|
|
76
76
|
consumed: u
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
function
|
|
79
|
+
function p(e, t, n) {
|
|
80
80
|
switch (e) {
|
|
81
|
-
case
|
|
82
|
-
let { str: e, read: n } =
|
|
81
|
+
case l.Intermediate: {
|
|
82
|
+
let { str: e, read: n } = m(t.slice(46));
|
|
83
83
|
return {
|
|
84
84
|
payload: {
|
|
85
85
|
issuer: e,
|
|
@@ -90,8 +90,8 @@ function d(e, t, n) {
|
|
|
90
90
|
payloadRead: 5 + n
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
case
|
|
94
|
-
let { str: e, read: n } =
|
|
93
|
+
case l.Server: {
|
|
94
|
+
let { str: e, read: n } = m(t.slice(47));
|
|
95
95
|
return {
|
|
96
96
|
payload: {
|
|
97
97
|
issuer: e,
|
|
@@ -102,7 +102,7 @@ function d(e, t, n) {
|
|
|
102
102
|
payloadRead: 6 + n
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
case
|
|
105
|
+
case l.Ts5Server: {
|
|
106
106
|
let e = t[43] === void 0 ? 0 : t[43], r = 44, i = [];
|
|
107
107
|
for (let n = 0; n < e; n++) {
|
|
108
108
|
if (r >= t.length) throw Error("license too short");
|
|
@@ -120,7 +120,7 @@ function d(e, t, n) {
|
|
|
120
120
|
payloadRead: r - n
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
|
-
case
|
|
123
|
+
case l.Ephemeral: return {
|
|
124
124
|
payload: {
|
|
125
125
|
issuer: "",
|
|
126
126
|
serverType: 0,
|
|
@@ -132,34 +132,29 @@ function d(e, t, n) {
|
|
|
132
132
|
default: throw Error(`invalid license block type: ${e}`);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
function
|
|
135
|
+
function m(e) {
|
|
136
136
|
for (let t = 0; t < e.length; t++) if (e[t] === 0) return {
|
|
137
137
|
str: new TextDecoder().decode(e.slice(0, t)),
|
|
138
138
|
read: t
|
|
139
139
|
};
|
|
140
140
|
throw Error("non-null-terminated issuer string");
|
|
141
141
|
}
|
|
142
|
-
function
|
|
143
|
-
let
|
|
144
|
-
i
|
|
145
|
-
let
|
|
146
|
-
return
|
|
147
|
-
}
|
|
148
|
-
function m(e) {
|
|
149
|
-
let t = 0n;
|
|
150
|
-
for (let n = e.length - 1; n >= 0; n--) t = t << 8n | BigInt(e[n]);
|
|
151
|
-
return t;
|
|
142
|
+
function h(n, r) {
|
|
143
|
+
let i = Uint8Array.from(n.hash);
|
|
144
|
+
a(i);
|
|
145
|
+
let o = s(i), c = t.Point.fromBytes(n.key).negate(), l = t.Point.fromBytes(r).negate(), u = e(c, o).add(l).toBytes(), d = new Uint8Array(u.length);
|
|
146
|
+
return d.set(u), d[31] = (d[31] === void 0 ? 0 : d[31]) ^ 128, d;
|
|
152
147
|
}
|
|
153
148
|
//#endregion
|
|
154
149
|
//#region src/handshake/crypt-init2.ts
|
|
155
|
-
function
|
|
156
|
-
if (
|
|
157
|
-
let
|
|
158
|
-
if (!
|
|
159
|
-
let m = r(l
|
|
160
|
-
|
|
150
|
+
function g(e, t, n, a, s, c) {
|
|
151
|
+
if (e.alphaTmp.length === 0) throw Error("alpha is not initialized");
|
|
152
|
+
let l = Buffer.from(t, "base64"), u = Buffer.from(n, "base64"), f = Buffer.from(a, "base64"), p = Buffer.from(s, "base64");
|
|
153
|
+
if (!o(i(u), l, f)) throw Error("init proof is not valid");
|
|
154
|
+
let m = r(d(l).deriveKey(), c);
|
|
155
|
+
e.setSharedSecret(e.alphaTmp, p, m);
|
|
161
156
|
}
|
|
162
157
|
//#endregion
|
|
163
|
-
export {
|
|
158
|
+
export { u as n, d as r, g as t };
|
|
164
159
|
|
|
165
|
-
//# sourceMappingURL=crypt-init2-
|
|
160
|
+
//# sourceMappingURL=crypt-init2-DWX7Tp-_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypt-init2-DWX7Tp-_.js","names":[],"sources":["../src/handshake/license.ts","../src/handshake/crypt-init2.ts"],"sourcesContent":["import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alphaTmp.length === 0) {\n throw new Error(\"alpha is not initialized\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new Error(\"init proof is not valid\");\n }\n\n const licenses = parseLicenses(licenseBytes);\n const key = licenses.deriveKey();\n\n const sharedSecret = getSharedSecret2(key, privateKey);\n\n crypt.setSharedSecret(crypt.alphaTmp, betaBytes, sharedSecret);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAOrB,qBAAa,QAAQ;IACnB,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;gBAEH,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM;IAKjD,eAAe,IAAI,MAAM;IAoBzB,QAAQ,IAAI,MAAM;IAUlB,aAAa,IAAI,MAAM;IAOjB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAe/E;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CA+BtD;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAc9D;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAEpD;
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAOrB,qBAAa,QAAQ;IACnB,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;gBAEH,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM;IAKjD,eAAe,IAAI,MAAM;IAoBzB,QAAQ,IAAI,MAAM;IAUlB,aAAa,IAAI,MAAM;IAOjB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAe/E;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CA+BtD;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAc9D;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAEpD;AA+BD;mDACmD;AACnD,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,CAS3D"}
|
package/dist/crypto/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../primitives-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../primitives-bj-ml31v.cjs`),t=require(`../crypto-2veVY1fC.cjs`);exports.Crypt=t.t,exports.EAX=t.n,exports.Identity=e.l,exports.aesCmac=t.r,exports.clampScalar=e.n,exports.generateIdentity=e.u,exports.generateTemporaryKey=e.r,exports.getSharedSecret2=e.i,exports.getUidFromPublicKey=e.d,exports.hash512=e.f,exports.identityFromString=e.p,exports.importPublicKey=e.m,exports.sign=e.o,exports.verifySign=e.s;
|
package/dist/crypto/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as d, r as f, t as p } from "../crypto-
|
|
3
|
-
export { p as Crypt, d as EAX,
|
|
1
|
+
import { d as e, f as t, i as n, l as r, m as i, n as a, o, p as s, r as c, s as l, u } from "../primitives-BIAYfJ2Y.js";
|
|
2
|
+
import { n as d, r as f, t as p } from "../crypto-VC7n6YJb.js";
|
|
3
|
+
export { p as Crypt, d as EAX, r as Identity, f as aesCmac, a as clampScalar, u as generateIdentity, c as generateTemporaryKey, n as getSharedSecret2, e as getUidFromPublicKey, t as hash512, s as identityFromString, i as importPublicKey, o as sign, l as verifySign };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type KeyObject } from "node:crypto";
|
|
2
|
+
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
2
3
|
/** Clamp a Curve25519 scalar in-place (required before scalar multiplication). */
|
|
3
4
|
export declare function clampScalar(key: Uint8Array): void;
|
|
4
5
|
/**
|
|
@@ -16,13 +17,27 @@ export declare function sign(privateKey: KeyObject, data: Uint8Array): Uint8Arra
|
|
|
16
17
|
export declare function verifySign(publicKey: KeyObject, data: Uint8Array, sig: Uint8Array): boolean;
|
|
17
18
|
/**
|
|
18
19
|
* TS3-specific shared secret derivation using Ed25519 point arithmetic.
|
|
19
|
-
* Mirrors
|
|
20
|
+
* Mirrors NaCl's ge_scalarmult_vartime:
|
|
20
21
|
* 1. Negate the public point
|
|
21
|
-
* 2. Scalar-multiply by clamped private key (
|
|
22
|
+
* 2. Scalar-multiply by clamped private key bytes (NOT reduced mod n)
|
|
22
23
|
* 3. Flip sign bit of result
|
|
23
24
|
* 4. SHA-512 the resulting point bytes
|
|
25
|
+
*
|
|
26
|
+
* The scalar must NOT be reduced mod n: Ed25519 has cofactor 8, so the server's
|
|
27
|
+
* public key may have a small-order component, and P*s ≠ P*(s mod n) in that case.
|
|
28
|
+
* We use scalarMultFull to handle scalars >= n without losing the cofactor term.
|
|
24
29
|
*/
|
|
25
30
|
export declare function getSharedSecret2(publicKeyBytes: Uint8Array, privateKeyBytes: Uint8Array): Uint8Array;
|
|
31
|
+
/**
|
|
32
|
+
* Multiply an Ed25519 point by a scalar that may be >= curve order n.
|
|
33
|
+
* Decomposes as: P*s = P*(s mod n) + (P*n)*q where q = floor(s/n).
|
|
34
|
+
* This preserves the small-order component (cofactor 8) that would be
|
|
35
|
+
* lost by reducing mod n first.
|
|
36
|
+
*
|
|
37
|
+
* For a clamped 255-bit scalar, q is at most 7 (since maxScalar / n < 8),
|
|
38
|
+
* so the second term is computed with at most one extra scalar multiplication.
|
|
39
|
+
*/
|
|
40
|
+
export declare function scalarMultFull(point: InstanceType<typeof ed25519.Point>, scalar: bigint): InstanceType<typeof ed25519.Point>;
|
|
26
41
|
/** Interpret a little-endian byte array as an unsigned BigInt. */
|
|
27
42
|
export declare function bytesToBigIntLE(bytes: Uint8Array): bigint;
|
|
28
43
|
//# sourceMappingURL=primitives.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/crypto/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/crypto/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AASnD,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAKjD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAU/D;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,CAIxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAQ3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,UAAU,EAC1B,eAAe,EAAE,UAAU,GAC1B,UAAU,CA4BZ;AAID;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC,EACzC,MAAM,EAAE,MAAM,GACb,YAAY,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC,CAgBpC;AAED,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMzD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`./primitives-
|
|
2
|
-
//# sourceMappingURL=crypto-
|
|
1
|
+
const e=require(`./primitives-bj-ml31v.cjs`);let t=require(`node:crypto`);var n=8,r=16,i=class{#e;constructor(e){if(e.length!==16)throw Error(`EAX requires a 16-byte key`);this.#e=e}encrypt(e,t,r){let i=this.#t(0,e),o=this.#t(1,t),s=a(this.#e,i,r),c=this.#t(2,s),l=new Uint8Array(n);for(let e=0;e<n;e++)l[e]=i[e]^o[e]^c[e];return[s,l]}decrypt(r,i,o,s){let c=this.#t(0,r),l=this.#t(1,i),u=this.#t(2,o),d=new Uint8Array(n);for(let e=0;e<n;e++)d[e]=c[e]^l[e]^u[e];if(!(0,t.timingSafeEqual)(Buffer.from(d),Buffer.from(s.slice(0,n))))throw new e.v;return a(this.#e,c,o)}#t(e,t){let n=new Uint8Array(r+t.length);return n[r-1]=e,n.set(t,r),d(this.#e,n)}};function a(e,n,r){let i=(0,t.createCipheriv)(`aes-128-ctr`,Buffer.from(e),Buffer.from(n));return Buffer.concat([i.update(Buffer.from(r)),i.final()])}function o(e,n){let r=(0,t.createCipheriv)(`aes-128-ecb`,Buffer.from(e),null);return r.setAutoPadding(!1),Buffer.concat([r.update(Buffer.from(n)),r.final()])}function s(e,t){let n=new Uint8Array(r);for(let i=0;i<r;i++)n[i]=e[i]^t[i];return n}function c(e){let t=new Uint8Array(r),n=0;for(let i=r-1;i>=0;i--){let r=(e[i]<<1|n)&255;n=e[i]>>7,t[i]=r}return t}var l=new Uint8Array(r);l[r-1]=135;function u(e){let t=o(e,new Uint8Array(r)),n=c(t);t[0]&128&&(n=s(n,l));let i=c(n);return n[0]&128&&(i=s(i,l)),[n,i]}function d(e,t){let[n,i]=u(e),a=Math.max(1,Math.ceil(t.length/r)),c=t.length>0&&t.length%r===0,l=new Uint8Array(r);for(let n=0;n<a-1;n++){let i=t.slice(n*r,(n+1)*r);l=Uint8Array.from(o(e,s(l,i)))}let d=new Uint8Array(r),f=(a-1)*r,p=t.slice(f);d.set(p);let m;return c?m=s(d,n):(p.length<r&&(d[p.length]=128),m=s(d,i)),Uint8Array.from(o(e,s(l,m)))}var f=8,p=10,m=8,h=15,g=Buffer.from(`TS3INIT1`),_=Buffer.from(`c:\\windows\\syste`),v=Buffer.from(`m\\firewall32.cpl`),y=class{identity;ivStruct=new Uint8Array;fakeSignature=new Uint8Array(f);alphaTmp=new Uint8Array;cryptoInitComplete=!1;#e=new Map;constructor(e){this.identity=e}solveRsaChallenge(e,t,n){if(n<0||n>1e6)throw Error(`RSA challenge level out of range`);let r=e.slice(t,t+64),i=e.slice(t+64,t+128),a=x(r),o=x(i);for(let e=0;e<n;e++)a=a*a%o;return S(a,64)}initCrypto(t,n,r){let i=Buffer.from(t,`base64`),a=Buffer.from(n,`base64`),o=e.m(Buffer.from(r,`base64`)),s=this.#t(o);this.setSharedSecret(i,a,s)}setSharedSecret(e,n,r){this.ivStruct=new Uint8Array(p+n.length);for(let t=0;t<p;t++){let n=r[t],i=e[t];this.ivStruct[t]=((n===void 0?0:n)^(i===void 0?0:i))&255}for(let e=0;e<n.length;e++){let t=r[p+e],i=n[e];this.ivStruct[p+e]=((t===void 0?0:t)^(i===void 0?0:i))&255}let i=(0,t.createHash)(`sha1`).update(this.ivStruct).digest();this.fakeSignature=new Uint8Array(i.buffer,i.byteOffset,f),this.cryptoInitComplete=!0}getKeyNonce(e,n,r,i,a){if(a)return[Uint8Array.from(_),Uint8Array.from(v)];let o=b(e,i,r),s=this.#e.get(o);if(s===void 0){let n=new Uint8Array(6+this.ivStruct.length);n[0]=e?48:49,n[1]=i&h,new DataView(n.buffer).setUint32(2,r,!1),n.set(this.ivStruct,6);let a=(0,t.createHash)(`sha256`).update(n).digest();s={key:Uint8Array.from(a.slice(0,16)),nonce:Uint8Array.from(a.slice(16,32)),gen:r},this.#e.set(o,s)}let c=Uint8Array.from(s.key);return c[0]=(c[0]===void 0?0:c[0])^n>>8&255,c[1]=(c[1]===void 0?0:c[1])^n&255,[c,s.nonce]}encrypt(e,t,n,r,a,o,s){if(e===m)return[a,g];if(s)return[a,this.fakeSignature];let[c,l]=this.getKeyNonce(!1,t,n,e,o);return new i(c).encrypt(l,r,a)}decrypt(t,n,r,a,o,s,c,l){if(t===m)return o;if(l){let t=s.slice(0,f);if(!Buffer.from(t).equals(Buffer.from(this.fakeSignature)))throw new e.y;return o}let[u,d]=this.getKeyNonce(!0,n,r,t,c);return new i(u).decrypt(d,a,o,s)}#t(e){let n=this.identity.privateKey.export({format:`jwk`}),r=e.export({format:`jwk`}),i=(0,t.createECDH)(`prime256v1`),a=Buffer.from(n.d,`base64url`);i.setPrivateKey(a);let o=C(r.x,32),s=C(r.y,32),c=Buffer.alloc(65);c[0]=4,o.copy(c,1),s.copy(c,33);let l=i.computeSecret(c);return(0,t.createHash)(`sha1`).update(l).digest()}};function b(e,t,n){let r=0n;return e&&(r|=1n<<40n),r|=BigInt(t&h)<<32n,r|=BigInt(n),r}function x(e){let t=0n;for(let n of e)t=t<<8n|BigInt(n);return t}function S(e,t){let n=new Uint8Array(t),r=e;for(let e=t-1;e>=0;e--)n[e]=Number(r&255n),r>>=8n;return n}function C(e,t){let n=Buffer.from(e,`base64url`);if(n.length===t)return n;let r=Buffer.alloc(t);return n.copy(r,t-n.length),r}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return y}});
|
|
2
|
+
//# sourceMappingURL=crypto-2veVY1fC.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-C3gBJkh2.cjs","names":["#key","#cmac","#cachedKeys","#getSharedSecret"],"sources":["../src/crypto/eax.ts","../src/crypto/crypt.ts"],"sourcesContent":["import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH } from \"node:crypto\";\nimport { FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\nexport class Crypt {\n readonly identity: Identity;\n\n ivStruct: Uint8Array = new Uint8Array(0);\n fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n alphaTmp: Uint8Array = new Uint8Array(0);\n cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (level < 0 || level > 1_000_000) {\n throw new Error(\"RSA challenge level out of range\");\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n const sharedSecret = this.#getSharedSecret(serverPubKey);\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n const digest = createHash(\"sha1\").update(this.ivStruct).digest();\n this.fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = this.identity.privateKey.export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"crypto-2veVY1fC.cjs","names":["#key","#cmac","#cachedKeys","#getSharedSecret"],"sources":["../src/crypto/eax.ts","../src/crypto/crypt.ts"],"sourcesContent":["import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH } from \"node:crypto\";\nimport { FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\nexport class Crypt {\n readonly identity: Identity;\n\n ivStruct: Uint8Array = new Uint8Array(0);\n fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n alphaTmp: Uint8Array = new Uint8Array(0);\n cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (level < 0 || level > 1_000_000) {\n throw new Error(\"RSA challenge level out of range\");\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n const sharedSecret = this.#getSharedSecret(serverPubKey);\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n const digest = createHash(\"sha1\").update(this.ivStruct).digest();\n this.fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = this.identity.privateKey.export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as e, v as t, y as n } from "./primitives-BIAYfJ2Y.js";
|
|
2
2
|
import { createCipheriv as r, createECDH as i, createHash as a, timingSafeEqual as o } from "node:crypto";
|
|
3
3
|
//#region src/crypto/eax.ts
|
|
4
4
|
var s = 8, c = 16, l = class {
|
|
@@ -12,10 +12,10 @@ var s = 8, c = 16, l = class {
|
|
|
12
12
|
for (let e = 0; e < s; e++) c[e] = r[e] ^ i[e] ^ o[e];
|
|
13
13
|
return [a, c];
|
|
14
14
|
}
|
|
15
|
-
decrypt(e,
|
|
16
|
-
let a = this.#t(0, e), c = this.#t(1,
|
|
15
|
+
decrypt(e, n, r, i) {
|
|
16
|
+
let a = this.#t(0, e), c = this.#t(1, n), l = this.#t(2, r), d = new Uint8Array(s);
|
|
17
17
|
for (let e = 0; e < s; e++) d[e] = a[e] ^ c[e] ^ l[e];
|
|
18
|
-
if (!o(Buffer.from(d), Buffer.from(i.slice(0, s)))) throw new
|
|
18
|
+
if (!o(Buffer.from(d), Buffer.from(i.slice(0, s)))) throw new t();
|
|
19
19
|
return u(this.#e, a, r);
|
|
20
20
|
}
|
|
21
21
|
#t(e, t) {
|
|
@@ -81,8 +81,8 @@ var _ = 8, v = 10, y = 8, b = 15, x = Buffer.from("TS3INIT1"), S = Buffer.from("
|
|
|
81
81
|
for (let e = 0; e < n; e++) a = a * a % o;
|
|
82
82
|
return D(a, 64);
|
|
83
83
|
}
|
|
84
|
-
initCrypto(
|
|
85
|
-
let i = Buffer.from(
|
|
84
|
+
initCrypto(t, n, r) {
|
|
85
|
+
let i = Buffer.from(t, "base64"), a = Buffer.from(n, "base64"), o = e(Buffer.from(r, "base64")), s = this.#t(o);
|
|
86
86
|
this.setSharedSecret(i, a, s);
|
|
87
87
|
}
|
|
88
88
|
setSharedSecret(e, t, n) {
|
|
@@ -120,14 +120,14 @@ var _ = 8, v = 10, y = 8, b = 15, x = Buffer.from("TS3INIT1"), S = Buffer.from("
|
|
|
120
120
|
let [s, c] = this.getKeyNonce(!1, t, n, e, a);
|
|
121
121
|
return new l(s).encrypt(c, r, i);
|
|
122
122
|
}
|
|
123
|
-
decrypt(
|
|
124
|
-
if (
|
|
123
|
+
decrypt(e, t, r, i, a, o, s, c) {
|
|
124
|
+
if (e === y) return a;
|
|
125
125
|
if (c) {
|
|
126
|
-
let
|
|
127
|
-
if (!Buffer.from(
|
|
126
|
+
let e = o.slice(0, _);
|
|
127
|
+
if (!Buffer.from(e).equals(Buffer.from(this.fakeSignature))) throw new n();
|
|
128
128
|
return a;
|
|
129
129
|
}
|
|
130
|
-
let [u, d] = this.getKeyNonce(!0,
|
|
130
|
+
let [u, d] = this.getKeyNonce(!0, t, r, e, s);
|
|
131
131
|
return new l(u).decrypt(d, i, a, o);
|
|
132
132
|
}
|
|
133
133
|
#t(e) {
|
|
@@ -162,4 +162,4 @@ function O(e, t) {
|
|
|
162
162
|
//#endregion
|
|
163
163
|
export { l as n, g as r, w as t };
|
|
164
164
|
|
|
165
|
-
//# sourceMappingURL=crypto-
|
|
165
|
+
//# sourceMappingURL=crypto-VC7n6YJb.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-IGJlkTAl.js","names":["#key","#cmac","#cachedKeys","#getSharedSecret"],"sources":["../src/crypto/eax.ts","../src/crypto/crypt.ts"],"sourcesContent":["import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH } from \"node:crypto\";\nimport { FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\nexport class Crypt {\n readonly identity: Identity;\n\n ivStruct: Uint8Array = new Uint8Array(0);\n fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n alphaTmp: Uint8Array = new Uint8Array(0);\n cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (level < 0 || level > 1_000_000) {\n throw new Error(\"RSA challenge level out of range\");\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n const sharedSecret = this.#getSharedSecret(serverPubKey);\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n const digest = createHash(\"sha1\").update(this.ivStruct).digest();\n this.fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = this.identity.privateKey.export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"crypto-VC7n6YJb.js","names":["#key","#cmac","#cachedKeys","#getSharedSecret"],"sources":["../src/crypto/eax.ts","../src/crypto/crypt.ts"],"sourcesContent":["import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH } from \"node:crypto\";\nimport { FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\nexport class Crypt {\n readonly identity: Identity;\n\n ivStruct: Uint8Array = new Uint8Array(0);\n fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n alphaTmp: Uint8Array = new Uint8Array(0);\n cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (level < 0 || level > 1_000_000) {\n throw new Error(\"RSA challenge level out of range\");\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n const serverPubKey = importPublicKey(omegaBytes);\n const sharedSecret = this.#getSharedSecret(serverPubKey);\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n const digest = createHash(\"sha1\").update(this.ivStruct).digest();\n this.fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = this.identity.privateKey.export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n"],"mappings":"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"}
|
|
@@ -317,10 +317,7 @@ var h = 500, g = 1024, _ = 5e3, v = 6e4, y = 1e3, b = 5, x = 8, S = 3, C = 500,
|
|
|
317
317
|
dummyUsed: !0
|
|
318
318
|
};
|
|
319
319
|
} catch {}
|
|
320
|
-
return
|
|
321
|
-
type: d,
|
|
322
|
-
id: e.id
|
|
323
|
-
}), null;
|
|
320
|
+
return null;
|
|
324
321
|
}
|
|
325
322
|
}
|
|
326
323
|
#w(e, t) {
|
|
@@ -455,4 +452,4 @@ function D(e, t) {
|
|
|
455
452
|
//#endregion
|
|
456
453
|
export { r as a, o as c, l as d, i, a as l, p as n, c as o, d as r, s, T as t, u };
|
|
457
454
|
|
|
458
|
-
//# sourceMappingURL=handler-
|
|
455
|
+
//# sourceMappingURL=handler-C_JhqGTd.js.map
|