ai-remote 0.1.0

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.
Files changed (114) hide show
  1. package/README.md +50 -0
  2. package/dist/index.js +7 -0
  3. package/dist/index.js.map +7 -0
  4. package/dist/protocols/index.js +35 -0
  5. package/dist/protocols/index.js.map +7 -0
  6. package/dist/protocols/rdp/buffer.js +170 -0
  7. package/dist/protocols/rdp/buffer.js.map +7 -0
  8. package/dist/protocols/rdp/caps.js +260 -0
  9. package/dist/protocols/rdp/caps.js.map +7 -0
  10. package/dist/protocols/rdp/cert.js +135 -0
  11. package/dist/protocols/rdp/cert.js.map +7 -0
  12. package/dist/protocols/rdp/client.js +1068 -0
  13. package/dist/protocols/rdp/client.js.map +7 -0
  14. package/dist/protocols/rdp/cliprdr.js +240 -0
  15. package/dist/protocols/rdp/cliprdr.js.map +7 -0
  16. package/dist/protocols/rdp/credssp.js +254 -0
  17. package/dist/protocols/rdp/credssp.js.map +7 -0
  18. package/dist/protocols/rdp/crypto.js +369 -0
  19. package/dist/protocols/rdp/crypto.js.map +7 -0
  20. package/dist/protocols/rdp/display.js +589 -0
  21. package/dist/protocols/rdp/display.js.map +7 -0
  22. package/dist/protocols/rdp/gcc.js +132 -0
  23. package/dist/protocols/rdp/gcc.js.map +7 -0
  24. package/dist/protocols/rdp/keymap.js +132 -0
  25. package/dist/protocols/rdp/keymap.js.map +7 -0
  26. package/dist/protocols/rdp/mcs.js +223 -0
  27. package/dist/protocols/rdp/mcs.js.map +7 -0
  28. package/dist/protocols/rdp/ntlm.js +305 -0
  29. package/dist/protocols/rdp/ntlm.js.map +7 -0
  30. package/dist/protocols/rdp/pdu.js +444 -0
  31. package/dist/protocols/rdp/pdu.js.map +7 -0
  32. package/dist/protocols/rdp/rail.js +383 -0
  33. package/dist/protocols/rdp/rail.js.map +7 -0
  34. package/dist/protocols/rdp/rle.js +276 -0
  35. package/dist/protocols/rdp/rle.js.map +7 -0
  36. package/dist/protocols/rdp/sec.js +156 -0
  37. package/dist/protocols/rdp/sec.js.map +7 -0
  38. package/dist/protocols/rdp/session.js +307 -0
  39. package/dist/protocols/rdp/session.js.map +7 -0
  40. package/dist/protocols/rdp/tls.js +354 -0
  41. package/dist/protocols/rdp/tls.js.map +7 -0
  42. package/dist/protocols/rdp/vchannel.js +59 -0
  43. package/dist/protocols/rdp/vchannel.js.map +7 -0
  44. package/dist/protocols/rdp/x224.js +110 -0
  45. package/dist/protocols/rdp/x224.js.map +7 -0
  46. package/dist/protocols/ssh/kex.js +177 -0
  47. package/dist/protocols/ssh/kex.js.map +7 -0
  48. package/dist/protocols/ssh/messages.js +55 -0
  49. package/dist/protocols/ssh/messages.js.map +7 -0
  50. package/dist/protocols/ssh/session.js +608 -0
  51. package/dist/protocols/ssh/session.js.map +7 -0
  52. package/dist/protocols/ssh/terminal.js +191 -0
  53. package/dist/protocols/ssh/terminal.js.map +7 -0
  54. package/dist/protocols/ssh/transport.js +611 -0
  55. package/dist/protocols/ssh/transport.js.map +7 -0
  56. package/dist/protocols/ssh/wire.js +189 -0
  57. package/dist/protocols/ssh/wire.js.map +7 -0
  58. package/dist/protocols/types.js +1 -0
  59. package/dist/protocols/types.js.map +7 -0
  60. package/dist/protocols/vnc/input.js +16 -0
  61. package/dist/protocols/vnc/input.js.map +7 -0
  62. package/dist/protocols/vnc/session.js +259 -0
  63. package/dist/protocols/vnc/session.js.map +7 -0
  64. package/dist/shared/connection.js +114 -0
  65. package/dist/shared/connection.js.map +7 -0
  66. package/dist/shared/device.js +1 -0
  67. package/dist/shared/device.js.map +7 -0
  68. package/dist/shared/hosts.js +133 -0
  69. package/dist/shared/hosts.js.map +7 -0
  70. package/dist/shared/icons.js +42 -0
  71. package/dist/shared/icons.js.map +7 -0
  72. package/dist/shared/protocol.js +40 -0
  73. package/dist/shared/protocol.js.map +7 -0
  74. package/dist/shared/signals.js +42 -0
  75. package/dist/shared/signals.js.map +7 -0
  76. package/package.json +82 -0
  77. package/src/index.ts +14 -0
  78. package/src/protocols/index.ts +72 -0
  79. package/src/protocols/rdp/buffer.ts +204 -0
  80. package/src/protocols/rdp/caps.ts +304 -0
  81. package/src/protocols/rdp/cert.ts +190 -0
  82. package/src/protocols/rdp/client.ts +1363 -0
  83. package/src/protocols/rdp/cliprdr.ts +344 -0
  84. package/src/protocols/rdp/credssp.ts +319 -0
  85. package/src/protocols/rdp/crypto.ts +416 -0
  86. package/src/protocols/rdp/display.ts +750 -0
  87. package/src/protocols/rdp/gcc.ts +162 -0
  88. package/src/protocols/rdp/keymap.ts +68 -0
  89. package/src/protocols/rdp/mcs.ts +283 -0
  90. package/src/protocols/rdp/ntlm.ts +380 -0
  91. package/src/protocols/rdp/pdu.ts +497 -0
  92. package/src/protocols/rdp/rail.ts +480 -0
  93. package/src/protocols/rdp/rle.ts +343 -0
  94. package/src/protocols/rdp/sec.ts +184 -0
  95. package/src/protocols/rdp/session.ts +393 -0
  96. package/src/protocols/rdp/tls.ts +452 -0
  97. package/src/protocols/rdp/vchannel.ts +89 -0
  98. package/src/protocols/rdp/x224.ts +139 -0
  99. package/src/protocols/ssh/kex.ts +227 -0
  100. package/src/protocols/ssh/messages.ts +54 -0
  101. package/src/protocols/ssh/session.ts +878 -0
  102. package/src/protocols/ssh/terminal.ts +242 -0
  103. package/src/protocols/ssh/transport.ts +732 -0
  104. package/src/protocols/ssh/wire.ts +220 -0
  105. package/src/protocols/types.ts +146 -0
  106. package/src/protocols/vnc/input.ts +13 -0
  107. package/src/protocols/vnc/novnc.d.ts +75 -0
  108. package/src/protocols/vnc/session.ts +367 -0
  109. package/src/shared/connection.ts +206 -0
  110. package/src/shared/device.ts +28 -0
  111. package/src/shared/hosts.ts +240 -0
  112. package/src/shared/icons.ts +49 -0
  113. package/src/shared/protocol.ts +55 -0
  114. package/src/shared/signals.ts +67 -0
@@ -0,0 +1,254 @@
1
+ import { concatBytes } from "./buffer";
2
+ import { NtlmSealer, authenticateMessage, negotiateMessage, parseChallengeMessage } from "./ntlm";
3
+ const CREDSSP_VERSION = 6;
4
+ const CLIENT_TO_SERVER_MAGIC = "CredSSP Client-To-Server Binding Hash\0";
5
+ const SERVER_TO_CLIENT_MAGIC = "CredSSP Server-To-Client Binding Hash\0";
6
+ const NT_STATUS_MESSAGES = {
7
+ 3221225581: "The host rejected the username or password (STATUS_LOGON_FAILURE).",
8
+ 3221225582: "The account is not allowed to sign in right now (STATUS_ACCOUNT_RESTRICTION).",
9
+ 3221225583: "The account is outside its permitted logon hours.",
10
+ 3221225584: "The account is not allowed to sign in from this machine (STATUS_INVALID_WORKSTATION).",
11
+ 3221225585: "The account password has expired.",
12
+ 3221225586: "The account is disabled.",
13
+ 3221225819: "The account is not allowed the Remote Desktop logon type -- add it to the Remote Desktop Users group.",
14
+ 3221225875: "The account has expired.",
15
+ 3221226020: "The account must change its password before signing in.",
16
+ 3221226036: "The account is locked out.",
17
+ 2148074252: "The host denied the logon (SEC_E_LOGON_DENIED).",
18
+ 2148074248: "The host rejected the authentication token (SEC_E_INVALID_TOKEN).",
19
+ 2148074242: "The host rejected the CredSSP exchange (SEC_E_UNSUPPORTED_FUNCTION) -- usually a public-key binding mismatch."
20
+ };
21
+ function derLength(length) {
22
+ if (length < 128) return new Uint8Array([length]);
23
+ if (length <= 255) return new Uint8Array([129, length]);
24
+ if (length <= 65535) return new Uint8Array([130, length >> 8, length & 255]);
25
+ return new Uint8Array([131, length >> 16 & 255, length >> 8 & 255, length & 255]);
26
+ }
27
+ const derTlv = (tag, content) => concatBytes(new Uint8Array([tag]), derLength(content.length), content);
28
+ const derSequence = (...parts) => derTlv(48, concatBytes(...parts));
29
+ const derOctetString = (bytes) => derTlv(4, bytes);
30
+ const derContext = (index, content) => derTlv(160 | index, content);
31
+ function derInteger(value) {
32
+ const bytes = [];
33
+ let remaining = value;
34
+ do {
35
+ bytes.unshift(remaining & 255);
36
+ remaining >>>= 8;
37
+ } while (remaining > 0);
38
+ if (bytes[0] & 128) bytes.unshift(0);
39
+ return derTlv(2, new Uint8Array(bytes));
40
+ }
41
+ function derRead(bytes, offset) {
42
+ const tag = bytes[offset];
43
+ let cursor = offset + 1;
44
+ let length = bytes[cursor++];
45
+ if (length & 128) {
46
+ const count = length & 127;
47
+ length = 0;
48
+ for (let i = 0; i < count; i++) length = length << 8 | bytes[cursor++];
49
+ }
50
+ return { tag, content: bytes.subarray(cursor, cursor + length), end: cursor + length };
51
+ }
52
+ function derElementLength(bytes, offset = 0) {
53
+ if (bytes.length - offset < 2) return 0;
54
+ let cursor = offset + 1;
55
+ let length = bytes[cursor++];
56
+ if (length & 128) {
57
+ const count = length & 127;
58
+ if (bytes.length - cursor < count) return 0;
59
+ length = 0;
60
+ for (let i = 0; i < count; i++) length = length << 8 | bytes[cursor++];
61
+ }
62
+ const total = cursor - offset + length;
63
+ return bytes.length - offset < total ? 0 : total;
64
+ }
65
+ function encodeTsRequest({ version, negoToken, authInfo, pubKeyAuth, clientNonce }) {
66
+ const parts = [derContext(0, derInteger(version))];
67
+ if (negoToken) {
68
+ parts.push(derContext(1, derSequence(derSequence(derContext(0, derOctetString(negoToken))))));
69
+ }
70
+ if (authInfo) parts.push(derContext(2, derOctetString(authInfo)));
71
+ if (pubKeyAuth) parts.push(derContext(3, derOctetString(pubKeyAuth)));
72
+ if (clientNonce) parts.push(derContext(5, derOctetString(clientNonce)));
73
+ return derSequence(...parts);
74
+ }
75
+ function decodeTsRequest(bytes) {
76
+ const outer = derRead(bytes, 0);
77
+ const result = { version: 0, negoToken: null, authInfo: null, pubKeyAuth: null, errorCode: 0 };
78
+ let offset = 0;
79
+ while (offset < outer.content.length) {
80
+ const field = derRead(outer.content, offset);
81
+ offset = field.end;
82
+ const index = field.tag & 31;
83
+ if (index === 0) {
84
+ result.version = derRead(field.content, 0).content[0];
85
+ continue;
86
+ }
87
+ if (index === 1) {
88
+ const sequence = derRead(field.content, 0);
89
+ const item = derRead(sequence.content, 0);
90
+ const token = derRead(item.content, 0);
91
+ result.negoToken = derRead(token.content, 0).content;
92
+ continue;
93
+ }
94
+ if (index === 2) {
95
+ result.authInfo = derRead(field.content, 0).content;
96
+ continue;
97
+ }
98
+ if (index === 3) {
99
+ result.pubKeyAuth = derRead(field.content, 0).content;
100
+ continue;
101
+ }
102
+ if (index === 4) {
103
+ const value = derRead(field.content, 0).content;
104
+ let code = 0;
105
+ for (const byte of value) code = (code << 8 | byte) >>> 0;
106
+ result.errorCode = code;
107
+ continue;
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ function encodeCredentials(domain, username, password) {
113
+ const utf16 = (text) => {
114
+ const out = new Uint8Array(text.length * 2);
115
+ const view = new DataView(out.buffer);
116
+ for (let i = 0; i < text.length; i++) view.setUint16(i * 2, text.charCodeAt(i), true);
117
+ return out;
118
+ };
119
+ const passwordCreds = derSequence(
120
+ derContext(0, derOctetString(utf16(domain))),
121
+ derContext(1, derOctetString(utf16(username))),
122
+ derContext(2, derOctetString(utf16(password)))
123
+ );
124
+ return derSequence(
125
+ derContext(0, derInteger(1)),
126
+ // credType: password
127
+ derContext(1, derOctetString(passwordCreds))
128
+ );
129
+ }
130
+ class CredSspClient {
131
+ username;
132
+ domain;
133
+ password;
134
+ serverPublicKey;
135
+ send;
136
+ log;
137
+ inbound;
138
+ waiters;
139
+ constructor({ username, domain, password, serverPublicKey, send, log }) {
140
+ this.username = username || "";
141
+ this.domain = domain || "";
142
+ this.password = password || "";
143
+ this.serverPublicKey = serverPublicKey;
144
+ this.send = send;
145
+ this.log = log || (() => {
146
+ });
147
+ this.inbound = new Uint8Array(0);
148
+ this.waiters = [];
149
+ }
150
+ /** Feed decrypted TLS application data. */
151
+ receive(bytes) {
152
+ this.inbound = this.inbound.length === 0 ? bytes : concatBytes(this.inbound, bytes);
153
+ for (; ; ) {
154
+ const length = derElementLength(this.inbound);
155
+ if (length === 0) return;
156
+ const request = decodeTsRequest(this.inbound.subarray(0, length));
157
+ this.inbound = this.inbound.subarray(length).slice();
158
+ const waiter = this.waiters.shift();
159
+ if (waiter) waiter.resolve(request);
160
+ }
161
+ }
162
+ #next(timeoutMs = 15e3) {
163
+ return new Promise((resolve, reject) => {
164
+ const timer = setTimeout(
165
+ () => reject(new Error("CredSSP: the host did not answer within 15s")),
166
+ timeoutMs
167
+ );
168
+ this.waiters.push({
169
+ resolve: (value) => {
170
+ clearTimeout(timer);
171
+ resolve(value);
172
+ }
173
+ });
174
+ });
175
+ }
176
+ async #bindingHash(magic, nonce) {
177
+ const digest = await crypto.subtle.digest(
178
+ "SHA-256",
179
+ concatBytes(new TextEncoder().encode(magic), nonce, this.serverPublicKey)
180
+ );
181
+ return new Uint8Array(digest);
182
+ }
183
+ async authenticate() {
184
+ const negotiate = negotiateMessage();
185
+ this.send(encodeTsRequest({ version: CREDSSP_VERSION, negoToken: negotiate }));
186
+ this.log("CredSSP", "sent NTLM NEGOTIATE");
187
+ const challengeRequest = await this.#next();
188
+ if (challengeRequest.errorCode) throw new Error(this.#statusMessage(challengeRequest.errorCode));
189
+ if (!challengeRequest.negoToken) throw new Error("CredSSP: the host sent no NTLM challenge");
190
+ const challengeBytes = challengeRequest.negoToken.slice();
191
+ const challenge = parseChallengeMessage(challengeBytes);
192
+ const targetName = new TextDecoder("utf-16le").decode(challenge.targetName);
193
+ this.log("CredSSP", `received NTLM CHALLENGE from "${targetName}" (host CredSSP version ${challengeRequest.version})`);
194
+ if (!this.username) {
195
+ return {
196
+ authenticated: false,
197
+ reachedChallenge: true,
198
+ hostVersion: challengeRequest.version,
199
+ targetName,
200
+ note: "no credentials supplied, stopping after the challenge"
201
+ };
202
+ }
203
+ const { message, keys } = authenticateMessage({
204
+ username: this.username,
205
+ domain: this.domain,
206
+ password: this.password,
207
+ challenge,
208
+ negotiateBytes: negotiate,
209
+ challengeBytes
210
+ });
211
+ const sealer = new NtlmSealer(keys);
212
+ const clientNonce = new Uint8Array(32);
213
+ crypto.getRandomValues(clientNonce);
214
+ const legacy = challengeRequest.version < 5;
215
+ const binding = legacy ? this.serverPublicKey : await this.#bindingHash(CLIENT_TO_SERVER_MAGIC, clientNonce);
216
+ this.send(encodeTsRequest({
217
+ version: CREDSSP_VERSION,
218
+ negoToken: message,
219
+ pubKeyAuth: sealer.seal(binding),
220
+ clientNonce: legacy ? null : clientNonce
221
+ }));
222
+ this.log("CredSSP", `sent NTLM AUTHENTICATE with the ${legacy ? "legacy" : "hashed"} public-key binding`);
223
+ const response = await this.#next();
224
+ if (response.errorCode) throw new Error(this.#statusMessage(response.errorCode));
225
+ if (!response.pubKeyAuth) throw new Error("CredSSP: the host returned no public-key confirmation");
226
+ const confirmed = sealer.unseal(response.pubKeyAuth);
227
+ const expected = legacy ? this.#incrementedPublicKey() : await this.#bindingHash(SERVER_TO_CLIENT_MAGIC, clientNonce);
228
+ if (confirmed.length !== expected.length || !expected.every((byte, i) => byte === confirmed[i])) {
229
+ throw new Error(
230
+ "CredSSP: the host public-key confirmation did not match. The TLS session is not the one the host authenticated, which is what this check exists to catch."
231
+ );
232
+ }
233
+ this.log("CredSSP", "host confirmed the public-key binding");
234
+ this.send(encodeTsRequest({
235
+ version: CREDSSP_VERSION,
236
+ authInfo: sealer.seal(encodeCredentials(this.domain, this.username, this.password))
237
+ }));
238
+ this.log("CredSSP", "sent credentials");
239
+ return { authenticated: true, hostVersion: challengeRequest.version, targetName };
240
+ }
241
+ /** Legacy confirmation is the public key with its first byte incremented. */
242
+ #incrementedPublicKey() {
243
+ const expected = this.serverPublicKey.slice();
244
+ expected[0] = expected[0] + 1 & 255;
245
+ return expected;
246
+ }
247
+ #statusMessage(errorCode) {
248
+ return NT_STATUS_MESSAGES[errorCode] || `CredSSP: the host reported error 0x${errorCode.toString(16).padStart(8, "0")}.`;
249
+ }
250
+ }
251
+ export {
252
+ CredSspClient
253
+ };
254
+ //# sourceMappingURL=credssp.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/protocols/rdp/credssp.ts"],
4
+ "sourcesContent": ["// CredSSP (MS-CSSP): the protocol behind RDP's Network Level Authentication.\n//\n// It runs inside the TLS channel and does three things in order: authenticate\n// with NTLM, prove to the host that the TLS certificate we were shown is the\n// one the host actually holds, and only then hand over the credentials. The\n// second step is why this gateway needs its own TLS client -- the proof is\n// computed over the host certificate's public key, which no runtime here\n// exposes for a TLS session it established on our behalf.\n\nimport { concatBytes } from './buffer';\nimport { NtlmSealer, authenticateMessage, negotiateMessage, parseChallengeMessage } from './ntlm';\n\nconst CREDSSP_VERSION = 6;\n\n// MS-CSSP 3.1.5: from version 5 the binding is a hash over a client nonce and\n// the public key, rather than the bare public key.\nconst CLIENT_TO_SERVER_MAGIC = 'CredSSP Client-To-Server Binding Hash\\0';\nconst SERVER_TO_CLIENT_MAGIC = 'CredSSP Server-To-Client Binding Hash\\0';\n\nconst NT_STATUS_MESSAGES = {\n 0xc000006d: 'The host rejected the username or password (STATUS_LOGON_FAILURE).',\n 0xc000006e: 'The account is not allowed to sign in right now (STATUS_ACCOUNT_RESTRICTION).',\n 0xc000006f: 'The account is outside its permitted logon hours.',\n 0xc0000070: 'The account is not allowed to sign in from this machine (STATUS_INVALID_WORKSTATION).',\n 0xc0000071: 'The account password has expired.',\n 0xc0000072: 'The account is disabled.',\n 0xc000015b: 'The account is not allowed the Remote Desktop logon type -- add it to the Remote Desktop Users group.',\n 0xc0000193: 'The account has expired.',\n 0xc0000224: 'The account must change its password before signing in.',\n 0xc0000234: 'The account is locked out.',\n 0x8009030c: 'The host denied the logon (SEC_E_LOGON_DENIED).',\n 0x80090308: 'The host rejected the authentication token (SEC_E_INVALID_TOKEN).',\n 0x80090302: 'The host rejected the CredSSP exchange (SEC_E_UNSUPPORTED_FUNCTION) -- usually a public-key binding mismatch.',\n};\n\n// --- DER --------------------------------------------------------------------\n\nfunction derLength(length: number) {\n if (length < 0x80) return new Uint8Array([length]);\n if (length <= 0xff) return new Uint8Array([0x81, length]);\n if (length <= 0xffff) return new Uint8Array([0x82, length >> 8, length & 0xff]);\n return new Uint8Array([0x83, (length >> 16) & 0xff, (length >> 8) & 0xff, length & 0xff]);\n}\n\nconst derTlv = (tag, content: Uint8Array) => concatBytes(new Uint8Array([tag]), derLength(content.length), content);\nconst derSequence = (...parts) => derTlv(0x30, concatBytes(...parts));\nconst derOctetString = (bytes: Uint8Array) => derTlv(0x04, bytes);\nconst derContext = (index, content: Uint8Array) => derTlv(0xa0 | index, content);\n\nfunction derInteger(value) {\n const bytes = [];\n let remaining = value;\n do {\n bytes.unshift(remaining & 0xff);\n remaining >>>= 8;\n } while (remaining > 0);\n // A leading bit of 1 would read as negative.\n if (bytes[0] & 0x80) bytes.unshift(0x00);\n return derTlv(0x02, new Uint8Array(bytes));\n}\n\nfunction derRead(bytes: Uint8Array, offset: number) {\n const tag = bytes[offset];\n let cursor = offset + 1;\n let length = bytes[cursor++];\n\n if (length & 0x80) {\n const count = length & 0x7f;\n length = 0;\n for (let i = 0; i < count; i++) length = (length << 8) | bytes[cursor++];\n }\n\n return { tag, content: bytes.subarray(cursor, cursor + length), end: cursor + length };\n}\n\n/** Total encoded length of the DER element starting at `offset`, or 0 if partial. */\nfunction derElementLength(bytes: Uint8Array, offset = 0) {\n if (bytes.length - offset < 2) return 0;\n let cursor = offset + 1;\n let length = bytes[cursor++];\n\n if (length & 0x80) {\n const count = length & 0x7f;\n if (bytes.length - cursor < count) return 0;\n length = 0;\n for (let i = 0; i < count; i++) length = (length << 8) | bytes[cursor++];\n }\n\n const total = cursor - offset + length;\n return bytes.length - offset < total ? 0 : total;\n}\n\nfunction encodeTsRequest({ version, negoToken, authInfo, pubKeyAuth, clientNonce }) {\n const parts = [derContext(0, derInteger(version))];\n\n if (negoToken) {\n parts.push(derContext(1, derSequence(derSequence(derContext(0, derOctetString(negoToken))))));\n }\n if (authInfo) parts.push(derContext(2, derOctetString(authInfo)));\n if (pubKeyAuth) parts.push(derContext(3, derOctetString(pubKeyAuth)));\n if (clientNonce) parts.push(derContext(5, derOctetString(clientNonce)));\n\n return derSequence(...parts);\n}\n\nfunction decodeTsRequest(bytes: Uint8Array) {\n const outer = derRead(bytes, 0);\n const result = { version: 0, negoToken: null, authInfo: null, pubKeyAuth: null, errorCode: 0 };\n\n let offset = 0;\n while (offset < outer.content.length) {\n const field = derRead(outer.content, offset);\n offset = field.end;\n const index = field.tag & 0x1f;\n\n if (index === 0) {\n result.version = derRead(field.content, 0).content[0];\n continue;\n }\n if (index === 1) {\n const sequence = derRead(field.content, 0); // SEQUENCE OF\n const item = derRead(sequence.content, 0); // SEQUENCE\n const token = derRead(item.content, 0); // [0] OCTET STRING\n result.negoToken = derRead(token.content, 0).content;\n continue;\n }\n if (index === 2) {\n result.authInfo = derRead(field.content, 0).content;\n continue;\n }\n if (index === 3) {\n result.pubKeyAuth = derRead(field.content, 0).content;\n continue;\n }\n if (index === 4) {\n const value = derRead(field.content, 0).content;\n let code = 0;\n for (const byte of value) code = ((code << 8) | byte) >>> 0;\n result.errorCode = code;\n continue;\n }\n }\n\n return result;\n}\n\n/** TSCredentials wrapping TSPasswordCreds (MS-CSSP 2.2.1.2). */\nfunction encodeCredentials(domain: string, username: string, password: string) {\n const utf16 = (text: string) => {\n const out = new Uint8Array(text.length * 2);\n const view = new DataView(out.buffer);\n for (let i = 0; i < text.length; i++) view.setUint16(i * 2, text.charCodeAt(i), true);\n return out;\n };\n\n const passwordCreds = derSequence(\n derContext(0, derOctetString(utf16(domain))),\n derContext(1, derOctetString(utf16(username))),\n derContext(2, derOctetString(utf16(password)))\n );\n\n return derSequence(\n derContext(0, derInteger(1)), // credType: password\n derContext(1, derOctetString(passwordCreds))\n );\n}\n\nexport class CredSspClient {\n private readonly username: string;\n private readonly domain: string;\n private readonly password: string;\n private readonly serverPublicKey: Uint8Array;\n private readonly send: (bytes: Uint8Array) => void;\n private readonly log: (message: string, detail?: unknown) => void;\n private inbound: Uint8Array;\n private waiters: Array<{ resolve: (bytes: Uint8Array) => void; reject: (error: Error) => void }>;\n\n constructor({ username, domain, password, serverPublicKey, send, log }) {\n this.username = username || '';\n this.domain = domain || '';\n this.password = password || '';\n this.serverPublicKey = serverPublicKey;\n this.send = send;\n this.log = log || (() => {});\n\n this.inbound = new Uint8Array(0);\n this.waiters = [];\n }\n\n /** Feed decrypted TLS application data. */\n receive(bytes: Uint8Array) {\n this.inbound = this.inbound.length === 0 ? bytes : concatBytes(this.inbound, bytes);\n\n // TSRequests are self-delimiting, so several can share one TLS record.\n for (;;) {\n const length = derElementLength(this.inbound);\n if (length === 0) return;\n\n const request = decodeTsRequest(this.inbound.subarray(0, length));\n this.inbound = this.inbound.subarray(length).slice();\n\n const waiter = this.waiters.shift();\n if (waiter) waiter.resolve(request);\n }\n }\n\n #next(timeoutMs = 15000) {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error('CredSSP: the host did not answer within 15s')),\n timeoutMs\n );\n this.waiters.push({\n resolve: (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n });\n });\n }\n\n async #bindingHash(magic, nonce) {\n const digest = await crypto.subtle.digest(\n 'SHA-256',\n concatBytes(new TextEncoder().encode(magic), nonce, this.serverPublicKey)\n );\n return new Uint8Array(digest);\n }\n\n async authenticate() {\n const negotiate = negotiateMessage();\n this.send(encodeTsRequest({ version: CREDSSP_VERSION, negoToken: negotiate }));\n this.log('CredSSP', 'sent NTLM NEGOTIATE');\n\n const challengeRequest = await this.#next();\n if (challengeRequest.errorCode) throw new Error(this.#statusMessage(challengeRequest.errorCode));\n if (!challengeRequest.negoToken) throw new Error('CredSSP: the host sent no NTLM challenge');\n\n const challengeBytes = challengeRequest.negoToken.slice();\n const challenge = parseChallengeMessage(challengeBytes);\n const targetName = new TextDecoder('utf-16le').decode(challenge.targetName);\n this.log('CredSSP', `received NTLM CHALLENGE from \"${targetName}\" (host CredSSP version ${challengeRequest.version})`);\n\n if (!this.username) {\n return {\n authenticated: false,\n reachedChallenge: true,\n hostVersion: challengeRequest.version,\n targetName,\n note: 'no credentials supplied, stopping after the challenge',\n };\n }\n\n const { message, keys } = authenticateMessage({\n username: this.username,\n domain: this.domain,\n password: this.password,\n challenge,\n negotiateBytes: negotiate,\n challengeBytes,\n });\n\n const sealer = new NtlmSealer(keys);\n const clientNonce = new Uint8Array(32);\n crypto.getRandomValues(clientNonce);\n\n // Hosts older than CredSSP 5 expect the bare public key instead of a hash.\n const legacy = challengeRequest.version < 5;\n const binding = legacy\n ? this.serverPublicKey\n : await this.#bindingHash(CLIENT_TO_SERVER_MAGIC, clientNonce);\n\n this.send(encodeTsRequest({\n version: CREDSSP_VERSION,\n negoToken: message,\n pubKeyAuth: sealer.seal(binding),\n clientNonce: legacy ? null : clientNonce,\n }));\n this.log('CredSSP', `sent NTLM AUTHENTICATE with the ${legacy ? 'legacy' : 'hashed'} public-key binding`);\n\n const response = await this.#next();\n if (response.errorCode) throw new Error(this.#statusMessage(response.errorCode));\n if (!response.pubKeyAuth) throw new Error('CredSSP: the host returned no public-key confirmation');\n\n const confirmed = sealer.unseal(response.pubKeyAuth);\n const expected = legacy\n ? this.#incrementedPublicKey()\n : await this.#bindingHash(SERVER_TO_CLIENT_MAGIC, clientNonce);\n\n if (confirmed.length !== expected.length || !expected.every((byte, i) => byte === confirmed[i])) {\n throw new Error(\n 'CredSSP: the host public-key confirmation did not match. The TLS session is not the one the host authenticated, which is what this check exists to catch.'\n );\n }\n this.log('CredSSP', 'host confirmed the public-key binding');\n\n this.send(encodeTsRequest({\n version: CREDSSP_VERSION,\n authInfo: sealer.seal(encodeCredentials(this.domain, this.username, this.password)),\n }));\n this.log('CredSSP', 'sent credentials');\n\n return { authenticated: true, hostVersion: challengeRequest.version, targetName };\n }\n\n /** Legacy confirmation is the public key with its first byte incremented. */\n #incrementedPublicKey() {\n const expected = this.serverPublicKey.slice();\n expected[0] = (expected[0] + 1) & 0xff;\n return expected;\n }\n\n #statusMessage(errorCode) {\n return (\n NT_STATUS_MESSAGES[errorCode] ||\n `CredSSP: the host reported error 0x${errorCode.toString(16).padStart(8, '0')}.`\n );\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,369 @@
1
+ const MD5_SHIFTS = [
2
+ 7,
3
+ 12,
4
+ 17,
5
+ 22,
6
+ 7,
7
+ 12,
8
+ 17,
9
+ 22,
10
+ 7,
11
+ 12,
12
+ 17,
13
+ 22,
14
+ 7,
15
+ 12,
16
+ 17,
17
+ 22,
18
+ 5,
19
+ 9,
20
+ 14,
21
+ 20,
22
+ 5,
23
+ 9,
24
+ 14,
25
+ 20,
26
+ 5,
27
+ 9,
28
+ 14,
29
+ 20,
30
+ 5,
31
+ 9,
32
+ 14,
33
+ 20,
34
+ 4,
35
+ 11,
36
+ 16,
37
+ 23,
38
+ 4,
39
+ 11,
40
+ 16,
41
+ 23,
42
+ 4,
43
+ 11,
44
+ 16,
45
+ 23,
46
+ 4,
47
+ 11,
48
+ 16,
49
+ 23,
50
+ 6,
51
+ 10,
52
+ 15,
53
+ 21,
54
+ 6,
55
+ 10,
56
+ 15,
57
+ 21,
58
+ 6,
59
+ 10,
60
+ 15,
61
+ 21,
62
+ 6,
63
+ 10,
64
+ 15,
65
+ 21
66
+ ];
67
+ const MD5_K = new Uint32Array(
68
+ Array.from({ length: 64 }, (_, i) => Math.floor(Math.abs(Math.sin(i + 1)) * 4294967296))
69
+ );
70
+ function rotl32(value, count) {
71
+ return value << count | value >>> 32 - count;
72
+ }
73
+ function md5(message) {
74
+ const bitLength = message.length * 8;
75
+ const blockCount = Math.floor((message.length + 8) / 64) + 1;
76
+ const padded = new Uint8Array(blockCount * 64);
77
+ padded.set(message);
78
+ padded[message.length] = 128;
79
+ const tail = new DataView(padded.buffer, padded.byteLength - 8, 8);
80
+ tail.setUint32(0, bitLength >>> 0, true);
81
+ tail.setUint32(4, Math.floor(bitLength / 4294967296), true);
82
+ let a0 = 1732584193, b0 = 4023233417, c0 = 2562383102, d0 = 271733878;
83
+ const words = new Uint32Array(16);
84
+ const view = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
85
+ for (let block = 0; block < blockCount; block++) {
86
+ for (let i = 0; i < 16; i++) words[i] = view.getUint32(block * 64 + i * 4, true);
87
+ let a = a0, b = b0, c = c0, d = d0;
88
+ for (let i = 0; i < 64; i++) {
89
+ let f;
90
+ let g;
91
+ if (i < 16) {
92
+ f = b & c | ~b & d;
93
+ g = i;
94
+ } else if (i < 32) {
95
+ f = d & b | ~d & c;
96
+ g = (5 * i + 1) % 16;
97
+ } else if (i < 48) {
98
+ f = b ^ c ^ d;
99
+ g = (3 * i + 5) % 16;
100
+ } else {
101
+ f = c ^ (b | ~d);
102
+ g = 7 * i % 16;
103
+ }
104
+ const temp = d;
105
+ d = c;
106
+ c = b;
107
+ const sum = a + f + MD5_K[i] + words[g] | 0;
108
+ b = b + rotl32(sum, MD5_SHIFTS[i]) | 0;
109
+ a = temp;
110
+ }
111
+ a0 = a0 + a | 0;
112
+ b0 = b0 + b | 0;
113
+ c0 = c0 + c | 0;
114
+ d0 = d0 + d | 0;
115
+ }
116
+ const digest = new Uint8Array(16);
117
+ const out = new DataView(digest.buffer);
118
+ out.setUint32(0, a0 >>> 0, true);
119
+ out.setUint32(4, b0 >>> 0, true);
120
+ out.setUint32(8, c0 >>> 0, true);
121
+ out.setUint32(12, d0 >>> 0, true);
122
+ return digest;
123
+ }
124
+ function sha1(message) {
125
+ const bitLength = message.length * 8;
126
+ const blockCount = Math.floor((message.length + 8) / 64) + 1;
127
+ const padded = new Uint8Array(blockCount * 64);
128
+ padded.set(message);
129
+ padded[message.length] = 128;
130
+ const tail = new DataView(padded.buffer, padded.byteLength - 8, 8);
131
+ tail.setUint32(0, Math.floor(bitLength / 4294967296));
132
+ tail.setUint32(4, bitLength >>> 0);
133
+ let h0 = 1732584193, h1 = 4023233417, h2 = 2562383102, h3 = 271733878, h4 = 3285377520;
134
+ const words = new Uint32Array(80);
135
+ const view = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
136
+ for (let block = 0; block < blockCount; block++) {
137
+ for (let i = 0; i < 16; i++) words[i] = view.getUint32(block * 64 + i * 4);
138
+ for (let i = 16; i < 80; i++) {
139
+ words[i] = rotl32(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], 1);
140
+ }
141
+ let a = h0, b = h1, c = h2, d = h3, e = h4;
142
+ for (let i = 0; i < 80; i++) {
143
+ let f;
144
+ let k;
145
+ if (i < 20) {
146
+ f = b & c | ~b & d;
147
+ k = 1518500249;
148
+ } else if (i < 40) {
149
+ f = b ^ c ^ d;
150
+ k = 1859775393;
151
+ } else if (i < 60) {
152
+ f = b & c | b & d | c & d;
153
+ k = 2400959708;
154
+ } else {
155
+ f = b ^ c ^ d;
156
+ k = 3395469782;
157
+ }
158
+ const temp = rotl32(a, 5) + f + e + k + words[i] | 0;
159
+ e = d;
160
+ d = c;
161
+ c = rotl32(b, 30);
162
+ b = a;
163
+ a = temp;
164
+ }
165
+ h0 = h0 + a | 0;
166
+ h1 = h1 + b | 0;
167
+ h2 = h2 + c | 0;
168
+ h3 = h3 + d | 0;
169
+ h4 = h4 + e | 0;
170
+ }
171
+ const digest = new Uint8Array(20);
172
+ const out = new DataView(digest.buffer);
173
+ [h0, h1, h2, h3, h4].forEach((word, i) => out.setUint32(i * 4, word >>> 0));
174
+ return digest;
175
+ }
176
+ function rc4Init(key) {
177
+ const s = new Uint8Array(256);
178
+ for (let i = 0; i < 256; i++) s[i] = i;
179
+ let j = 0;
180
+ for (let i = 0; i < 256; i++) {
181
+ j = j + (s[i] ?? 0) + (key[i % key.length] ?? 0) & 255;
182
+ const t = s[i] ?? 0;
183
+ s[i] = s[j] ?? 0;
184
+ s[j] = t;
185
+ }
186
+ return { s, i: 0, j: 0 };
187
+ }
188
+ function rc4Crypt(state, data) {
189
+ const out = new Uint8Array(data.length);
190
+ const { s } = state;
191
+ let { i, j } = state;
192
+ for (let n = 0; n < data.length; n++) {
193
+ i = i + 1 & 255;
194
+ j = j + s[i] & 255;
195
+ const t = s[i];
196
+ s[i] = s[j];
197
+ s[j] = t;
198
+ out[n] = data[n] ^ s[s[i] + s[j] & 255];
199
+ }
200
+ state.i = i;
201
+ state.j = j;
202
+ return out;
203
+ }
204
+ function bigIntFromLe(bytes) {
205
+ let value = 0n;
206
+ for (let i = bytes.length - 1; i >= 0; i--) value = value << 8n | BigInt(bytes[i]);
207
+ return value;
208
+ }
209
+ function bigIntToLe(value, length) {
210
+ const out = new Uint8Array(length);
211
+ let remaining = value;
212
+ for (let i = 0; i < length; i++) {
213
+ out[i] = Number(remaining & 0xffn);
214
+ remaining >>= 8n;
215
+ }
216
+ return out;
217
+ }
218
+ function modPow(base, exponent, modulus) {
219
+ let result = 1n;
220
+ let b = base % modulus;
221
+ let e = exponent;
222
+ while (e > 0n) {
223
+ if (e & 1n) result = result * b % modulus;
224
+ b = b * b % modulus;
225
+ e >>= 1n;
226
+ }
227
+ return result;
228
+ }
229
+ function rsaEncrypt(dataLe, modulusLe, exponentLe) {
230
+ const modulus = bigIntFromLe(modulusLe);
231
+ const exponent = bigIntFromLe(exponentLe);
232
+ const value = bigIntFromLe(dataLe);
233
+ if (value >= modulus) throw new Error("RDP: client random is larger than the server RSA modulus");
234
+ return bigIntToLe(modPow(value, exponent, modulus), modulusLe.length);
235
+ }
236
+ function rsaEncryptPkcs1(message, modulusBe, exponentBe) {
237
+ const bigIntFromBe = (bytes) => {
238
+ let value = 0n;
239
+ for (const byte of bytes) value = value << 8n | BigInt(byte);
240
+ return value;
241
+ };
242
+ const modulus = bigIntFromBe(modulusBe);
243
+ const exponent = bigIntFromBe(exponentBe);
244
+ const keyLength = modulusBe.length;
245
+ if (message.length > keyLength - 11) {
246
+ throw new Error("TLS: RSA message is too long for this key");
247
+ }
248
+ const block = new Uint8Array(keyLength);
249
+ block[0] = 0;
250
+ block[1] = 2;
251
+ const paddingLength = keyLength - message.length - 3;
252
+ const padding = new Uint8Array(paddingLength);
253
+ crypto.getRandomValues(padding);
254
+ for (let i = 0; i < paddingLength; i++) {
255
+ while (padding[i] === 0) padding[i] = Math.max(1, crypto.getRandomValues(new Uint8Array(1))[0]);
256
+ block[2 + i] = padding[i];
257
+ }
258
+ block[2 + paddingLength] = 0;
259
+ block.set(message, 3 + paddingLength);
260
+ const cipher = modPow(bigIntFromBe(block), exponent, modulus);
261
+ const out = new Uint8Array(keyLength);
262
+ let remaining = cipher;
263
+ for (let i = keyLength - 1; i >= 0; i--) {
264
+ out[i] = Number(remaining & 0xffn);
265
+ remaining >>= 8n;
266
+ }
267
+ return out;
268
+ }
269
+ const PAD1 = new Uint8Array(40).fill(54);
270
+ const PAD2 = new Uint8Array(48).fill(92);
271
+ const ENCRYPTION_METHOD = {
272
+ NONE: 0,
273
+ BIT_40: 1,
274
+ BIT_128: 2,
275
+ BIT_56: 8,
276
+ FIPS: 16
277
+ };
278
+ function concat(...parts) {
279
+ const total = parts.reduce((sum, part) => sum + part.length, 0);
280
+ const out = new Uint8Array(total);
281
+ let offset = 0;
282
+ for (const part of parts) {
283
+ out.set(part, offset);
284
+ offset += part.length;
285
+ }
286
+ return out;
287
+ }
288
+ function saltedHash(secret, salt, clientRandom, serverRandom) {
289
+ return md5(concat(secret, sha1(concat(salt, secret, clientRandom, serverRandom))));
290
+ }
291
+ function finalHash(key, clientRandom, serverRandom) {
292
+ return md5(concat(key, clientRandom, serverRandom));
293
+ }
294
+ const SALT_A = new Uint8Array([65]);
295
+ const SALT_BB = new Uint8Array([66, 66]);
296
+ const SALT_CCC = new Uint8Array([67, 67, 67]);
297
+ const SALT_X = new Uint8Array([88]);
298
+ const SALT_YY = new Uint8Array([89, 89]);
299
+ const SALT_ZZZ = new Uint8Array([90, 90, 90]);
300
+ function reduceKey(key, keyLength, is40Bit) {
301
+ if (keyLength !== 8) return key.slice(0, keyLength);
302
+ const reduced = key.slice(0, 8);
303
+ reduced[0] = 209;
304
+ if (is40Bit) {
305
+ reduced[1] = 38;
306
+ reduced[2] = 158;
307
+ }
308
+ return reduced;
309
+ }
310
+ function keyLengthForMethod(encryptionMethod) {
311
+ if (encryptionMethod === ENCRYPTION_METHOD.BIT_40) return 8;
312
+ if (encryptionMethod === ENCRYPTION_METHOD.BIT_56) return 8;
313
+ return 16;
314
+ }
315
+ function deriveSessionKeys(clientRandom, serverRandom, encryptionMethod) {
316
+ const preMasterSecret = concat(clientRandom.subarray(0, 24), serverRandom.subarray(0, 24));
317
+ const masterSecret = concat(
318
+ saltedHash(preMasterSecret, SALT_A, clientRandom, serverRandom),
319
+ saltedHash(preMasterSecret, SALT_BB, clientRandom, serverRandom),
320
+ saltedHash(preMasterSecret, SALT_CCC, clientRandom, serverRandom)
321
+ );
322
+ const sessionKeyBlob = concat(
323
+ saltedHash(masterSecret, SALT_X, clientRandom, serverRandom),
324
+ saltedHash(masterSecret, SALT_YY, clientRandom, serverRandom),
325
+ saltedHash(masterSecret, SALT_ZZZ, clientRandom, serverRandom)
326
+ );
327
+ const keyLength = keyLengthForMethod(encryptionMethod);
328
+ const is40Bit = encryptionMethod === ENCRYPTION_METHOD.BIT_40;
329
+ const applyReduction = (key) => reduceKey(key, keyLength, is40Bit);
330
+ const macKey = applyReduction(sessionKeyBlob.subarray(0, 16));
331
+ const decryptKey = applyReduction(finalHash(sessionKeyBlob.subarray(16, 32), clientRandom, serverRandom));
332
+ const encryptKey = applyReduction(finalHash(sessionKeyBlob.subarray(32, 48), clientRandom, serverRandom));
333
+ return {
334
+ macKey,
335
+ keyLength,
336
+ is40Bit,
337
+ // Session-key updates always restart from these initial values.
338
+ initialDecryptKey: decryptKey.slice(),
339
+ initialEncryptKey: encryptKey.slice(),
340
+ decryptKey,
341
+ encryptKey
342
+ };
343
+ }
344
+ function macSignature(macKey, data) {
345
+ const lengthField = new Uint8Array(4);
346
+ new DataView(lengthField.buffer).setUint32(0, data.length, true);
347
+ const inner = sha1(concat(macKey, PAD1, lengthField, data));
348
+ return md5(concat(macKey, PAD2, inner)).subarray(0, 8);
349
+ }
350
+ function updateSessionKey(initialKey, currentKey, keyLength, is40Bit) {
351
+ const inner = sha1(concat(initialKey, PAD1, currentKey));
352
+ const nextKey = md5(concat(initialKey, PAD2, inner)).slice(0, keyLength);
353
+ const salted = rc4Crypt(rc4Init(nextKey), nextKey);
354
+ return reduceKey(salted, keyLength, is40Bit);
355
+ }
356
+ export {
357
+ ENCRYPTION_METHOD,
358
+ deriveSessionKeys,
359
+ keyLengthForMethod,
360
+ macSignature,
361
+ md5,
362
+ rc4Crypt,
363
+ rc4Init,
364
+ rsaEncrypt,
365
+ rsaEncryptPkcs1,
366
+ sha1,
367
+ updateSessionKey
368
+ };
369
+ //# sourceMappingURL=crypto.js.map