@yume-chan/adb 0.0.9 → 0.0.10
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/CHANGELOG.json +23 -0
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -21
- package/README.md +227 -257
- package/dts/adb.d.ts.map +1 -1
- package/dts/auth.d.ts +11 -1
- package/dts/auth.d.ts.map +1 -1
- package/dts/backend.d.ts +3 -5
- package/dts/backend.d.ts.map +1 -1
- package/dts/commands/demo-mode.d.ts +3 -3
- package/dts/commands/demo-mode.d.ts.map +1 -1
- package/dts/commands/reverse.d.ts +2 -2
- package/dts/commands/reverse.d.ts.map +1 -1
- package/dts/commands/shell/index.d.ts +31 -5
- package/dts/commands/shell/index.d.ts.map +1 -1
- package/dts/commands/shell/legacy.d.ts +13 -2
- package/dts/commands/shell/legacy.d.ts.map +1 -1
- package/dts/commands/shell/protocol.d.ts +11 -3
- package/dts/commands/shell/protocol.d.ts.map +1 -1
- package/dts/commands/shell/types.d.ts +35 -3
- package/dts/commands/shell/types.d.ts.map +1 -1
- package/dts/commands/sync/request.d.ts +1 -1
- package/dts/commands/sync/request.d.ts.map +1 -1
- package/dts/commands/sync/response.d.ts +2 -2
- package/dts/commands/sync/response.d.ts.map +1 -1
- package/dts/commands/sync/sync.d.ts.map +1 -1
- package/dts/crypto.d.ts +7 -0
- package/dts/crypto.d.ts.map +1 -1
- package/dts/packet.d.ts.map +1 -1
- package/dts/socket/close-event-emitter.d.ts.map +1 -1
- package/dts/socket/controller.d.ts.map +1 -1
- package/dts/socket/data-event-emitter.d.ts.map +1 -1
- package/dts/socket/dispatcher.d.ts.map +1 -1
- package/dts/stream/buffered-stream.d.ts +2 -4
- package/dts/stream/buffered-stream.d.ts.map +1 -1
- package/dts/utils/encoding.d.ts +3 -0
- package/dts/utils/encoding.d.ts.map +1 -0
- package/dts/utils/index.d.ts +1 -0
- package/dts/utils/index.d.ts.map +1 -1
- package/esm/adb.js +3 -2
- package/esm/adb.js.map +1 -1
- package/esm/auth.js +2 -2
- package/esm/auth.js.map +1 -1
- package/esm/commands/demo-mode.js +9 -9
- package/esm/commands/demo-mode.js.map +1 -1
- package/esm/commands/reverse.js +3 -2
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/shell/index.js +28 -18
- package/esm/commands/shell/index.js.map +1 -1
- package/esm/commands/shell/legacy.js +16 -0
- package/esm/commands/shell/legacy.js.map +1 -1
- package/esm/commands/shell/protocol.js +36 -9
- package/esm/commands/shell/protocol.js.map +1 -1
- package/esm/commands/sync/request.js +5 -4
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.js +4 -3
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/crypto.js +7 -2
- package/esm/crypto.js.map +1 -1
- package/esm/packet.js +12 -14
- package/esm/packet.js.map +1 -1
- package/esm/socket/close-event-emitter.js.map +1 -1
- package/esm/socket/controller.js.map +1 -1
- package/esm/socket/data-event-emitter.js.map +1 -1
- package/esm/socket/dispatcher.js +7 -7
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/stream/buffered-stream.js +0 -6
- package/esm/stream/buffered-stream.js.map +1 -1
- package/esm/utils/encoding.js +11 -0
- package/esm/utils/encoding.js.map +1 -0
- package/esm/utils/index.js +1 -0
- package/esm/utils/index.js.map +1 -1
- package/package.json +44 -51
- package/src/adb.ts +243 -242
- package/src/auth.ts +166 -156
- package/src/backend.ts +20 -24
- package/src/commands/base.ts +11 -11
- package/src/commands/demo-mode.ts +160 -160
- package/src/commands/framebuffer.ts +73 -73
- package/src/commands/index.ts +8 -8
- package/src/commands/install.ts +21 -21
- package/src/commands/reverse.ts +134 -133
- package/src/commands/shell/index.ts +87 -68
- package/src/commands/shell/legacy.ts +59 -42
- package/src/commands/shell/protocol.ts +121 -94
- package/src/commands/shell/types.ts +55 -21
- package/src/commands/shell/utils.ts +20 -20
- package/src/commands/sync/index.ts +7 -7
- package/src/commands/sync/list.ts +39 -39
- package/src/commands/sync/pull.ts +34 -34
- package/src/commands/sync/push.ts +46 -46
- package/src/commands/sync/request.ts +49 -48
- package/src/commands/sync/response.ts +58 -57
- package/src/commands/sync/stat.ts +121 -121
- package/src/commands/sync/sync.ts +113 -113
- package/src/commands/tcpip.ts +21 -21
- package/src/crypto.ts +285 -280
- package/src/features.ts +5 -5
- package/src/index.ts +10 -10
- package/src/packet.ts +84 -89
- package/src/socket/close-event-emitter.ts +28 -28
- package/src/socket/controller.ts +105 -105
- package/src/socket/data-event-emitter.ts +27 -27
- package/src/socket/dispatcher.ts +269 -269
- package/src/socket/index.ts +6 -6
- package/src/socket/logger.ts +12 -12
- package/src/socket/socket.ts +28 -28
- package/src/stream/buffered-stream.ts +92 -100
- package/src/stream/index.ts +2 -2
- package/src/stream/stream.ts +50 -50
- package/src/utils/auto-reset-event.ts +41 -41
- package/src/utils/base64.ts +274 -274
- package/src/utils/chunk.ts +70 -70
- package/src/utils/encoding.ts +13 -0
- package/src/utils/event-queue.ts +145 -145
- package/src/utils/index.ts +5 -4
- package/cjs/adb.js +0 -205
- package/cjs/adb.js.map +0 -1
- package/cjs/auth.js +0 -141
- package/cjs/auth.js.map +0 -1
- package/cjs/backend.js +0 -3
- package/cjs/backend.js.map +0 -1
- package/cjs/commands/base.js +0 -12
- package/cjs/commands/base.js.map +0 -1
- package/cjs/commands/demo-mode.js +0 -174
- package/cjs/commands/demo-mode.js.map +0 -1
- package/cjs/commands/framebuffer.js +0 -66
- package/cjs/commands/framebuffer.js.map +0 -1
- package/cjs/commands/index.js +0 -12
- package/cjs/commands/index.js.map +0 -1
- package/cjs/commands/install.js +0 -20
- package/cjs/commands/install.js.map +0 -1
- package/cjs/commands/reverse.js +0 -105
- package/cjs/commands/reverse.js.map +0 -1
- package/cjs/commands/shell/index.js +0 -56
- package/cjs/commands/shell/index.js.map +0 -1
- package/cjs/commands/shell/legacy.js +0 -37
- package/cjs/commands/shell/legacy.js.map +0 -1
- package/cjs/commands/shell/protocol.js +0 -83
- package/cjs/commands/shell/protocol.js.map +0 -1
- package/cjs/commands/shell/types.js +0 -3
- package/cjs/commands/shell/types.js.map +0 -1
- package/cjs/commands/shell/utils.js +0 -23
- package/cjs/commands/shell/utils.js.map +0 -1
- package/cjs/commands/sync/index.js +0 -11
- package/cjs/commands/sync/index.js.map +0 -1
- package/cjs/commands/sync/list.js +0 -36
- package/cjs/commands/sync/list.js.map +0 -1
- package/cjs/commands/sync/pull.js +0 -34
- package/cjs/commands/sync/pull.js.map +0 -1
- package/cjs/commands/sync/push.js +0 -49
- package/cjs/commands/sync/push.js.map +0 -1
- package/cjs/commands/sync/request.js +0 -48
- package/cjs/commands/sync/request.js.map +0 -1
- package/cjs/commands/sync/response.js +0 -53
- package/cjs/commands/sync/response.js.map +0 -1
- package/cjs/commands/sync/stat.js +0 -109
- package/cjs/commands/sync/stat.js.map +0 -1
- package/cjs/commands/sync/sync.js +0 -118
- package/cjs/commands/sync/sync.js.map +0 -1
- package/cjs/commands/tcpip.js +0 -28
- package/cjs/commands/tcpip.js.map +0 -1
- package/cjs/crypto.js +0 -231
- package/cjs/crypto.js.map +0 -1
- package/cjs/features.js +0 -10
- package/cjs/features.js.map +0 -1
- package/cjs/index.js +0 -14
- package/cjs/index.js.map +0 -1
- package/cjs/packet.js +0 -77
- package/cjs/packet.js.map +0 -1
- package/cjs/socket/close-event-emitter.js +0 -32
- package/cjs/socket/close-event-emitter.js.map +0 -1
- package/cjs/socket/controller.js +0 -84
- package/cjs/socket/controller.js.map +0 -1
- package/cjs/socket/data-event-emitter.js +0 -29
- package/cjs/socket/data-event-emitter.js.map +0 -1
- package/cjs/socket/dispatcher.js +0 -219
- package/cjs/socket/dispatcher.js.map +0 -1
- package/cjs/socket/index.js +0 -10
- package/cjs/socket/index.js.map +0 -1
- package/cjs/socket/logger.js +0 -3
- package/cjs/socket/logger.js.map +0 -1
- package/cjs/socket/socket.js +0 -24
- package/cjs/socket/socket.js.map +0 -1
- package/cjs/stream/buffered-stream.js +0 -78
- package/cjs/stream/buffered-stream.js.map +0 -1
- package/cjs/stream/index.js +0 -6
- package/cjs/stream/index.js.map +0 -1
- package/cjs/stream/stream.js +0 -45
- package/cjs/stream/stream.js.map +0 -1
- package/cjs/utils/auto-reset-event.js +0 -37
- package/cjs/utils/auto-reset-event.js.map +0 -1
- package/cjs/utils/base64.js +0 -210
- package/cjs/utils/base64.js.map +0 -1
- package/cjs/utils/chunk.js +0 -75
- package/cjs/utils/chunk.js.map +0 -1
- package/cjs/utils/event-queue.js +0 -108
- package/cjs/utils/event-queue.js.map +0 -1
- package/cjs/utils/index.js +0 -8
- package/cjs/utils/index.js.map +0 -1
- package/tsconfig.cjs.json +0 -11
- package/tsconfig.esm.json +0 -28
- package/tsconfig.esm.tsbuildinfo +0 -1305
- package/tsconfig.json +0 -18
package/src/crypto.ts
CHANGED
|
@@ -1,280 +1,285 @@
|
|
|
1
|
-
const BigInt0 = BigInt(0);
|
|
2
|
-
const BigInt1 = BigInt(1);
|
|
3
|
-
const BigInt2 = BigInt(2);
|
|
4
|
-
|
|
5
|
-
const BigInt2To64 = BigInt2 ** BigInt(64);
|
|
6
|
-
|
|
7
|
-
export function getBig(
|
|
8
|
-
buffer: ArrayBuffer,
|
|
9
|
-
offset = 0,
|
|
10
|
-
length = buffer.byteLength - offset
|
|
11
|
-
): bigint {
|
|
12
|
-
const view = new DataView(buffer);
|
|
13
|
-
|
|
14
|
-
let result = BigInt0;
|
|
15
|
-
|
|
16
|
-
// Now `length` must be a multiplication of 8
|
|
17
|
-
// Support for arbitrary length can be easily added
|
|
18
|
-
|
|
19
|
-
for (let i = offset; i < offset + length; i += 8) {
|
|
20
|
-
result *= BigInt2To64;
|
|
21
|
-
const value = view.getBigUint64(i, false);
|
|
22
|
-
result += value;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return result;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function setBig(buffer: ArrayBuffer, value: bigint, offset: number = 0) {
|
|
29
|
-
const uint64Array: bigint[] = [];
|
|
30
|
-
while (value > BigInt0) {
|
|
31
|
-
uint64Array.push(BigInt.asUintN(64, value));
|
|
32
|
-
value /= BigInt2To64;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const view = new DataView(buffer);
|
|
36
|
-
for (let i = uint64Array.length - 1; i >= 0; i -= 1) {
|
|
37
|
-
view.setBigUint64(offset, uint64Array[i], false);
|
|
38
|
-
offset += 8;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function setBigLE(buffer: ArrayBuffer, value: bigint, offset = 0) {
|
|
43
|
-
const view = new DataView(buffer);
|
|
44
|
-
while (value > BigInt0) {
|
|
45
|
-
view.setBigUint64(offset, value, true);
|
|
46
|
-
offset += 8;
|
|
47
|
-
value /= BigInt2To64;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// These values are correct only if
|
|
52
|
-
// modulus length is 2048 and
|
|
53
|
-
// public exponent (e) is 65537
|
|
54
|
-
// Anyway, that's how this library generates keys
|
|
55
|
-
|
|
56
|
-
// To support other parameters,
|
|
57
|
-
// a proper ASN.1 parser can be used
|
|
58
|
-
|
|
59
|
-
// References:
|
|
60
|
-
//
|
|
61
|
-
// https://tools.ietf.org/html/rfc8017#appendix-A.1.2
|
|
62
|
-
// PKCS #1: RSA Cryptography Specifications Version 2.2
|
|
63
|
-
// A.1.2. RSA Private Key Syntax
|
|
64
|
-
//
|
|
65
|
-
// https://lapo.it/asn1js/
|
|
66
|
-
// https://github.com/lapo-luchini/asn1js
|
|
67
|
-
// ASN.1 JavaScript decoder
|
|
68
|
-
//
|
|
69
|
-
// https://www.itu.int/rec/T-REC-X.690-201508-I/en
|
|
70
|
-
// X.690: Specification of Distinguished Encoding Rules (DER)
|
|
71
|
-
|
|
72
|
-
const RsaPrivateKeyNOffset = 38;
|
|
73
|
-
const RsaPrivateKeyNLength = 2048 / 8;
|
|
74
|
-
const RsaPrivateKeyDOffset = 303;
|
|
75
|
-
const RsaPrivateKeyDLength = 2048 / 8;
|
|
76
|
-
|
|
77
|
-
export function parsePrivateKey(key: ArrayBuffer): [n: bigint, d: bigint] {
|
|
78
|
-
let n = getBig(key, RsaPrivateKeyNOffset, RsaPrivateKeyNLength);
|
|
79
|
-
let d = getBig(key, RsaPrivateKeyDOffset, RsaPrivateKeyDLength);
|
|
80
|
-
|
|
81
|
-
return [n, d];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Taken from https://stackoverflow.com/a/51562038
|
|
85
|
-
// I can't understand, but it does work
|
|
86
|
-
// Only used with numbers less than 2^32 so doesn't need BigInt
|
|
87
|
-
export function modInverse(a: number, m: number) {
|
|
88
|
-
// validate inputs
|
|
89
|
-
[a, m] = [Number(a), Number(m)];
|
|
90
|
-
if (Number.isNaN(a) || Number.isNaN(m)) {
|
|
91
|
-
return NaN; // invalid input
|
|
92
|
-
}
|
|
93
|
-
a = (a % m + m) % m;
|
|
94
|
-
if (!a || m < 2) {
|
|
95
|
-
return NaN; // invalid input
|
|
96
|
-
}
|
|
97
|
-
// find the gcd
|
|
98
|
-
const s = [];
|
|
99
|
-
let b = m;
|
|
100
|
-
while (b) {
|
|
101
|
-
[a, b] = [b, a % b];
|
|
102
|
-
s.push({ a, b });
|
|
103
|
-
}
|
|
104
|
-
if (a !== 1) {
|
|
105
|
-
return NaN; // inverse does not exists
|
|
106
|
-
}
|
|
107
|
-
// find the inverse
|
|
108
|
-
let x = 1;
|
|
109
|
-
let y = 0;
|
|
110
|
-
for (let i = s.length - 2; i >= 0; --i) {
|
|
111
|
-
[x, y] = [y, x - y * Math.floor(s[i].a / s[i].b)];
|
|
112
|
-
}
|
|
113
|
-
return (y % m + m) % m;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function calculatePublicKeyLength() {
|
|
117
|
-
return 4 + 4 + 2048 / 8 + 2048 / 8 + 4;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function calculatePublicKey(
|
|
121
|
-
privateKey: ArrayBuffer
|
|
122
|
-
): ArrayBuffer;
|
|
123
|
-
export function calculatePublicKey(
|
|
124
|
-
privateKey: ArrayBuffer,
|
|
125
|
-
output: ArrayBuffer,
|
|
126
|
-
outputOffset?: number
|
|
127
|
-
): number;
|
|
128
|
-
export function calculatePublicKey(
|
|
129
|
-
privateKey: ArrayBuffer,
|
|
130
|
-
output?: ArrayBuffer,
|
|
131
|
-
outputOffset: number = 0
|
|
132
|
-
): ArrayBuffer | number {
|
|
133
|
-
// Android has its own public key generation algorithm
|
|
134
|
-
// See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#111
|
|
135
|
-
|
|
136
|
-
// The public key is an array of
|
|
137
|
-
//
|
|
138
|
-
// [
|
|
139
|
-
// modulusLengthInWords, // 32-bit integer, a "word" is 32-bit so it must be 2048 / 8 / 4
|
|
140
|
-
// // Actually the comment in Android source code was wrong
|
|
141
|
-
// n0inv, // 32-bit integer, the modular inverse of (lower 32 bits of) n
|
|
142
|
-
// modulus, // n
|
|
143
|
-
// rr, // Montgomery parameter R^2
|
|
144
|
-
// exponent, // 32-bit integer, must be 65537
|
|
145
|
-
// ]
|
|
146
|
-
//
|
|
147
|
-
// (All in little endian)
|
|
148
|
-
// See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#38
|
|
149
|
-
|
|
150
|
-
// extract `n` from private key
|
|
151
|
-
const [n] = parsePrivateKey(privateKey);
|
|
152
|
-
|
|
153
|
-
let outputType: 'ArrayBuffer' | 'number';
|
|
154
|
-
const outputLength = calculatePublicKeyLength();
|
|
155
|
-
if (!output) {
|
|
156
|
-
output = new ArrayBuffer(outputLength);
|
|
157
|
-
outputType = 'ArrayBuffer';
|
|
158
|
-
} else {
|
|
159
|
-
if (output.byteLength - outputOffset < outputLength) {
|
|
160
|
-
throw new Error('output buffer is too small');
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
outputType = 'number';
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const outputView = new DataView(output);
|
|
167
|
-
|
|
168
|
-
// modulusLengthInWords
|
|
169
|
-
outputView.setUint32(outputOffset, 2048 / 8 / 4, true);
|
|
170
|
-
outputOffset += 4;
|
|
171
|
-
|
|
172
|
-
// Calculate `n0inv`
|
|
173
|
-
// Don't know why need to multiple -1
|
|
174
|
-
// Didn't exist in Android codebase
|
|
175
|
-
const n0inv = modInverse(Number(BigInt.asUintN(32, n) * BigInt(-1)), 2 ** 32);
|
|
176
|
-
outputView.setUint32(outputOffset, n0inv, true);
|
|
177
|
-
outputOffset += 4;
|
|
178
|
-
|
|
179
|
-
// Write n
|
|
180
|
-
setBigLE(output, n, outputOffset);
|
|
181
|
-
outputOffset += 256;
|
|
182
|
-
|
|
183
|
-
// Calculate rr = (2^(rsa_size)) ^ 2 mod n
|
|
184
|
-
let rr = BigInt(2) ** BigInt(4096) % n;
|
|
185
|
-
setBigLE(output, rr, outputOffset);
|
|
186
|
-
outputOffset += 256;
|
|
187
|
-
|
|
188
|
-
// exponent
|
|
189
|
-
outputView.setUint32(outputOffset, 65537, true);
|
|
190
|
-
outputOffset += 4;
|
|
191
|
-
|
|
192
|
-
if (outputType === 'ArrayBuffer') {
|
|
193
|
-
return output;
|
|
194
|
-
} else {
|
|
195
|
-
return outputLength;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
export const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
export const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
1
|
+
const BigInt0 = BigInt(0);
|
|
2
|
+
const BigInt1 = BigInt(1);
|
|
3
|
+
const BigInt2 = BigInt(2);
|
|
4
|
+
|
|
5
|
+
const BigInt2To64 = BigInt2 ** BigInt(64);
|
|
6
|
+
|
|
7
|
+
export function getBig(
|
|
8
|
+
buffer: ArrayBuffer,
|
|
9
|
+
offset = 0,
|
|
10
|
+
length = buffer.byteLength - offset
|
|
11
|
+
): bigint {
|
|
12
|
+
const view = new DataView(buffer);
|
|
13
|
+
|
|
14
|
+
let result = BigInt0;
|
|
15
|
+
|
|
16
|
+
// Now `length` must be a multiplication of 8
|
|
17
|
+
// Support for arbitrary length can be easily added
|
|
18
|
+
|
|
19
|
+
for (let i = offset; i < offset + length; i += 8) {
|
|
20
|
+
result *= BigInt2To64;
|
|
21
|
+
const value = view.getBigUint64(i, false);
|
|
22
|
+
result += value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function setBig(buffer: ArrayBuffer, value: bigint, offset: number = 0) {
|
|
29
|
+
const uint64Array: bigint[] = [];
|
|
30
|
+
while (value > BigInt0) {
|
|
31
|
+
uint64Array.push(BigInt.asUintN(64, value));
|
|
32
|
+
value /= BigInt2To64;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const view = new DataView(buffer);
|
|
36
|
+
for (let i = uint64Array.length - 1; i >= 0; i -= 1) {
|
|
37
|
+
view.setBigUint64(offset, uint64Array[i], false);
|
|
38
|
+
offset += 8;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function setBigLE(buffer: ArrayBuffer, value: bigint, offset = 0) {
|
|
43
|
+
const view = new DataView(buffer);
|
|
44
|
+
while (value > BigInt0) {
|
|
45
|
+
view.setBigUint64(offset, value, true);
|
|
46
|
+
offset += 8;
|
|
47
|
+
value /= BigInt2To64;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// These values are correct only if
|
|
52
|
+
// modulus length is 2048 and
|
|
53
|
+
// public exponent (e) is 65537
|
|
54
|
+
// Anyway, that's how this library generates keys
|
|
55
|
+
|
|
56
|
+
// To support other parameters,
|
|
57
|
+
// a proper ASN.1 parser can be used
|
|
58
|
+
|
|
59
|
+
// References:
|
|
60
|
+
//
|
|
61
|
+
// https://tools.ietf.org/html/rfc8017#appendix-A.1.2
|
|
62
|
+
// PKCS #1: RSA Cryptography Specifications Version 2.2
|
|
63
|
+
// A.1.2. RSA Private Key Syntax
|
|
64
|
+
//
|
|
65
|
+
// https://lapo.it/asn1js/
|
|
66
|
+
// https://github.com/lapo-luchini/asn1js
|
|
67
|
+
// ASN.1 JavaScript decoder
|
|
68
|
+
//
|
|
69
|
+
// https://www.itu.int/rec/T-REC-X.690-201508-I/en
|
|
70
|
+
// X.690: Specification of Distinguished Encoding Rules (DER)
|
|
71
|
+
|
|
72
|
+
const RsaPrivateKeyNOffset = 38;
|
|
73
|
+
const RsaPrivateKeyNLength = 2048 / 8;
|
|
74
|
+
const RsaPrivateKeyDOffset = 303;
|
|
75
|
+
const RsaPrivateKeyDLength = 2048 / 8;
|
|
76
|
+
|
|
77
|
+
export function parsePrivateKey(key: ArrayBuffer): [n: bigint, d: bigint] {
|
|
78
|
+
let n = getBig(key, RsaPrivateKeyNOffset, RsaPrivateKeyNLength);
|
|
79
|
+
let d = getBig(key, RsaPrivateKeyDOffset, RsaPrivateKeyDLength);
|
|
80
|
+
|
|
81
|
+
return [n, d];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Taken from https://stackoverflow.com/a/51562038
|
|
85
|
+
// I can't understand, but it does work
|
|
86
|
+
// Only used with numbers less than 2^32 so doesn't need BigInt
|
|
87
|
+
export function modInverse(a: number, m: number) {
|
|
88
|
+
// validate inputs
|
|
89
|
+
[a, m] = [Number(a), Number(m)];
|
|
90
|
+
if (Number.isNaN(a) || Number.isNaN(m)) {
|
|
91
|
+
return NaN; // invalid input
|
|
92
|
+
}
|
|
93
|
+
a = (a % m + m) % m;
|
|
94
|
+
if (!a || m < 2) {
|
|
95
|
+
return NaN; // invalid input
|
|
96
|
+
}
|
|
97
|
+
// find the gcd
|
|
98
|
+
const s = [];
|
|
99
|
+
let b = m;
|
|
100
|
+
while (b) {
|
|
101
|
+
[a, b] = [b, a % b];
|
|
102
|
+
s.push({ a, b });
|
|
103
|
+
}
|
|
104
|
+
if (a !== 1) {
|
|
105
|
+
return NaN; // inverse does not exists
|
|
106
|
+
}
|
|
107
|
+
// find the inverse
|
|
108
|
+
let x = 1;
|
|
109
|
+
let y = 0;
|
|
110
|
+
for (let i = s.length - 2; i >= 0; --i) {
|
|
111
|
+
[x, y] = [y, x - y * Math.floor(s[i].a / s[i].b)];
|
|
112
|
+
}
|
|
113
|
+
return (y % m + m) % m;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function calculatePublicKeyLength() {
|
|
117
|
+
return 4 + 4 + 2048 / 8 + 2048 / 8 + 4;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function calculatePublicKey(
|
|
121
|
+
privateKey: ArrayBuffer
|
|
122
|
+
): ArrayBuffer;
|
|
123
|
+
export function calculatePublicKey(
|
|
124
|
+
privateKey: ArrayBuffer,
|
|
125
|
+
output: ArrayBuffer,
|
|
126
|
+
outputOffset?: number
|
|
127
|
+
): number;
|
|
128
|
+
export function calculatePublicKey(
|
|
129
|
+
privateKey: ArrayBuffer,
|
|
130
|
+
output?: ArrayBuffer,
|
|
131
|
+
outputOffset: number = 0
|
|
132
|
+
): ArrayBuffer | number {
|
|
133
|
+
// Android has its own public key generation algorithm
|
|
134
|
+
// See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#111
|
|
135
|
+
|
|
136
|
+
// The public key is an array of
|
|
137
|
+
//
|
|
138
|
+
// [
|
|
139
|
+
// modulusLengthInWords, // 32-bit integer, a "word" is 32-bit so it must be 2048 / 8 / 4
|
|
140
|
+
// // Actually the comment in Android source code was wrong
|
|
141
|
+
// n0inv, // 32-bit integer, the modular inverse of (lower 32 bits of) n
|
|
142
|
+
// modulus, // n
|
|
143
|
+
// rr, // Montgomery parameter R^2
|
|
144
|
+
// exponent, // 32-bit integer, must be 65537
|
|
145
|
+
// ]
|
|
146
|
+
//
|
|
147
|
+
// (All in little endian)
|
|
148
|
+
// See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#38
|
|
149
|
+
|
|
150
|
+
// extract `n` from private key
|
|
151
|
+
const [n] = parsePrivateKey(privateKey);
|
|
152
|
+
|
|
153
|
+
let outputType: 'ArrayBuffer' | 'number';
|
|
154
|
+
const outputLength = calculatePublicKeyLength();
|
|
155
|
+
if (!output) {
|
|
156
|
+
output = new ArrayBuffer(outputLength);
|
|
157
|
+
outputType = 'ArrayBuffer';
|
|
158
|
+
} else {
|
|
159
|
+
if (output.byteLength - outputOffset < outputLength) {
|
|
160
|
+
throw new Error('output buffer is too small');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
outputType = 'number';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const outputView = new DataView(output);
|
|
167
|
+
|
|
168
|
+
// modulusLengthInWords
|
|
169
|
+
outputView.setUint32(outputOffset, 2048 / 8 / 4, true);
|
|
170
|
+
outputOffset += 4;
|
|
171
|
+
|
|
172
|
+
// Calculate `n0inv`
|
|
173
|
+
// Don't know why need to multiple -1
|
|
174
|
+
// Didn't exist in Android codebase
|
|
175
|
+
const n0inv = modInverse(Number(BigInt.asUintN(32, n) * BigInt(-1)), 2 ** 32);
|
|
176
|
+
outputView.setUint32(outputOffset, n0inv, true);
|
|
177
|
+
outputOffset += 4;
|
|
178
|
+
|
|
179
|
+
// Write n
|
|
180
|
+
setBigLE(output, n, outputOffset);
|
|
181
|
+
outputOffset += 256;
|
|
182
|
+
|
|
183
|
+
// Calculate rr = (2^(rsa_size)) ^ 2 mod n
|
|
184
|
+
let rr = BigInt(2) ** BigInt(4096) % n;
|
|
185
|
+
setBigLE(output, rr, outputOffset);
|
|
186
|
+
outputOffset += 256;
|
|
187
|
+
|
|
188
|
+
// exponent
|
|
189
|
+
outputView.setUint32(outputOffset, 65537, true);
|
|
190
|
+
outputOffset += 4;
|
|
191
|
+
|
|
192
|
+
if (outputType === 'ArrayBuffer') {
|
|
193
|
+
return output;
|
|
194
|
+
} else {
|
|
195
|
+
return outputLength;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Modular exponentiation.
|
|
201
|
+
*
|
|
202
|
+
* Calculate `(base ** exponent) % modulus` without actually calculating `(base ** exponent)`.
|
|
203
|
+
*
|
|
204
|
+
* See https://en.wikipedia.org/wiki/Modular_exponentiation#Implementation_in_Lua
|
|
205
|
+
*/
|
|
206
|
+
export function powMod(base: bigint, exponent: bigint, modulus: bigint): bigint {
|
|
207
|
+
if (modulus === BigInt1) {
|
|
208
|
+
return BigInt0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let r = BigInt1;
|
|
212
|
+
base = base % modulus;
|
|
213
|
+
|
|
214
|
+
while (exponent > BigInt0) {
|
|
215
|
+
if (BigInt.asUintN(1, exponent) === BigInt1) {
|
|
216
|
+
r = r * base % modulus;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
exponent >>= BigInt1;
|
|
220
|
+
base = base ** BigInt2 % modulus;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return r;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export const Sha1DigestLength = 20;
|
|
227
|
+
|
|
228
|
+
export const Asn1Sequence = 0x30;
|
|
229
|
+
export const Asn1OctetString = 0x04;
|
|
230
|
+
export const Asn1Null = 0x05;
|
|
231
|
+
export const Asn1Oid = 0x06;
|
|
232
|
+
|
|
233
|
+
// PKCS#1 SHA-1 hash digest info
|
|
234
|
+
export const Sha1DigestInfo = [
|
|
235
|
+
Asn1Sequence, 0x0d + Sha1DigestLength,
|
|
236
|
+
Asn1Sequence, 0x09,
|
|
237
|
+
// SHA-1 (1 3 14 3 2 26)
|
|
238
|
+
Asn1Oid, 0x05, 1 * 40 + 3, 14, 3, 2, 26,
|
|
239
|
+
Asn1Null, 0x00,
|
|
240
|
+
Asn1OctetString, Sha1DigestLength
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
// SubtleCrypto.sign() will hash the given data and sign the hash
|
|
244
|
+
// But we don't need the hashing step
|
|
245
|
+
// (In another word, ADB just requires the client to
|
|
246
|
+
// encrypt the given data with its private key)
|
|
247
|
+
// However SubtileCrypto.encrypt() doesn't accept 'RSASSA-PKCS1-v1_5' algorithm
|
|
248
|
+
// So we need to implement the encryption by ourself
|
|
249
|
+
export function sign(privateKey: ArrayBuffer, data: ArrayBuffer): ArrayBuffer {
|
|
250
|
+
const [n, d] = parsePrivateKey(privateKey);
|
|
251
|
+
|
|
252
|
+
// PKCS#1 padding
|
|
253
|
+
const padded = new Uint8Array(256);
|
|
254
|
+
let index = 0;
|
|
255
|
+
|
|
256
|
+
padded[index] = 0;
|
|
257
|
+
index += 1;
|
|
258
|
+
|
|
259
|
+
padded[index] = 1;
|
|
260
|
+
index += 1;
|
|
261
|
+
|
|
262
|
+
const fillLength = padded.length - Sha1DigestInfo.length - data.byteLength - 1;
|
|
263
|
+
while (index < fillLength) {
|
|
264
|
+
padded[index] = 0xff;
|
|
265
|
+
index += 1;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
padded[index] = 0;
|
|
269
|
+
index += 1;
|
|
270
|
+
|
|
271
|
+
padded.set(new Uint8Array(Sha1DigestInfo), index);
|
|
272
|
+
index += Sha1DigestInfo.length;
|
|
273
|
+
|
|
274
|
+
padded.set(new Uint8Array(data), index);
|
|
275
|
+
|
|
276
|
+
// Encryption
|
|
277
|
+
// signature = padded ** d % n
|
|
278
|
+
let signature = powMod(getBig(padded.buffer), d, n);
|
|
279
|
+
|
|
280
|
+
// Put into an ArrayBuffer
|
|
281
|
+
const result = new ArrayBuffer(256);
|
|
282
|
+
setBig(result, signature);
|
|
283
|
+
|
|
284
|
+
return result;
|
|
285
|
+
}
|
package/src/features.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export enum AdbFeatures {
|
|
2
|
-
StatV2 = 'stat_v2',
|
|
3
|
-
Cmd = 'cmd',
|
|
4
|
-
ShellV2 = "shell_v2"
|
|
5
|
-
}
|
|
1
|
+
export enum AdbFeatures {
|
|
2
|
+
StatV2 = 'stat_v2',
|
|
3
|
+
Cmd = 'cmd',
|
|
4
|
+
ShellV2 = "shell_v2"
|
|
5
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export * from './adb';
|
|
2
|
-
export * from './auth';
|
|
3
|
-
export * from './backend';
|
|
4
|
-
export * from './commands';
|
|
5
|
-
export * from './crypto';
|
|
6
|
-
export * from './features';
|
|
7
|
-
export * from './packet';
|
|
8
|
-
export * from './socket';
|
|
9
|
-
export * from './stream';
|
|
10
|
-
export * from './utils';
|
|
1
|
+
export * from './adb';
|
|
2
|
+
export * from './auth';
|
|
3
|
+
export * from './backend';
|
|
4
|
+
export * from './commands';
|
|
5
|
+
export * from './crypto';
|
|
6
|
+
export * from './features';
|
|
7
|
+
export * from './packet';
|
|
8
|
+
export * from './socket';
|
|
9
|
+
export * from './stream';
|
|
10
|
+
export * from './utils';
|