@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.
Files changed (205) hide show
  1. package/CHANGELOG.json +23 -0
  2. package/CHANGELOG.md +16 -0
  3. package/LICENSE +21 -21
  4. package/README.md +227 -257
  5. package/dts/adb.d.ts.map +1 -1
  6. package/dts/auth.d.ts +11 -1
  7. package/dts/auth.d.ts.map +1 -1
  8. package/dts/backend.d.ts +3 -5
  9. package/dts/backend.d.ts.map +1 -1
  10. package/dts/commands/demo-mode.d.ts +3 -3
  11. package/dts/commands/demo-mode.d.ts.map +1 -1
  12. package/dts/commands/reverse.d.ts +2 -2
  13. package/dts/commands/reverse.d.ts.map +1 -1
  14. package/dts/commands/shell/index.d.ts +31 -5
  15. package/dts/commands/shell/index.d.ts.map +1 -1
  16. package/dts/commands/shell/legacy.d.ts +13 -2
  17. package/dts/commands/shell/legacy.d.ts.map +1 -1
  18. package/dts/commands/shell/protocol.d.ts +11 -3
  19. package/dts/commands/shell/protocol.d.ts.map +1 -1
  20. package/dts/commands/shell/types.d.ts +35 -3
  21. package/dts/commands/shell/types.d.ts.map +1 -1
  22. package/dts/commands/sync/request.d.ts +1 -1
  23. package/dts/commands/sync/request.d.ts.map +1 -1
  24. package/dts/commands/sync/response.d.ts +2 -2
  25. package/dts/commands/sync/response.d.ts.map +1 -1
  26. package/dts/commands/sync/sync.d.ts.map +1 -1
  27. package/dts/crypto.d.ts +7 -0
  28. package/dts/crypto.d.ts.map +1 -1
  29. package/dts/packet.d.ts.map +1 -1
  30. package/dts/socket/close-event-emitter.d.ts.map +1 -1
  31. package/dts/socket/controller.d.ts.map +1 -1
  32. package/dts/socket/data-event-emitter.d.ts.map +1 -1
  33. package/dts/socket/dispatcher.d.ts.map +1 -1
  34. package/dts/stream/buffered-stream.d.ts +2 -4
  35. package/dts/stream/buffered-stream.d.ts.map +1 -1
  36. package/dts/utils/encoding.d.ts +3 -0
  37. package/dts/utils/encoding.d.ts.map +1 -0
  38. package/dts/utils/index.d.ts +1 -0
  39. package/dts/utils/index.d.ts.map +1 -1
  40. package/esm/adb.js +3 -2
  41. package/esm/adb.js.map +1 -1
  42. package/esm/auth.js +2 -2
  43. package/esm/auth.js.map +1 -1
  44. package/esm/commands/demo-mode.js +9 -9
  45. package/esm/commands/demo-mode.js.map +1 -1
  46. package/esm/commands/reverse.js +3 -2
  47. package/esm/commands/reverse.js.map +1 -1
  48. package/esm/commands/shell/index.js +28 -18
  49. package/esm/commands/shell/index.js.map +1 -1
  50. package/esm/commands/shell/legacy.js +16 -0
  51. package/esm/commands/shell/legacy.js.map +1 -1
  52. package/esm/commands/shell/protocol.js +36 -9
  53. package/esm/commands/shell/protocol.js.map +1 -1
  54. package/esm/commands/sync/request.js +5 -4
  55. package/esm/commands/sync/request.js.map +1 -1
  56. package/esm/commands/sync/response.js +4 -3
  57. package/esm/commands/sync/response.js.map +1 -1
  58. package/esm/commands/sync/sync.js.map +1 -1
  59. package/esm/crypto.js +7 -2
  60. package/esm/crypto.js.map +1 -1
  61. package/esm/packet.js +12 -14
  62. package/esm/packet.js.map +1 -1
  63. package/esm/socket/close-event-emitter.js.map +1 -1
  64. package/esm/socket/controller.js.map +1 -1
  65. package/esm/socket/data-event-emitter.js.map +1 -1
  66. package/esm/socket/dispatcher.js +7 -7
  67. package/esm/socket/dispatcher.js.map +1 -1
  68. package/esm/stream/buffered-stream.js +0 -6
  69. package/esm/stream/buffered-stream.js.map +1 -1
  70. package/esm/utils/encoding.js +11 -0
  71. package/esm/utils/encoding.js.map +1 -0
  72. package/esm/utils/index.js +1 -0
  73. package/esm/utils/index.js.map +1 -1
  74. package/package.json +44 -51
  75. package/src/adb.ts +243 -242
  76. package/src/auth.ts +166 -156
  77. package/src/backend.ts +20 -24
  78. package/src/commands/base.ts +11 -11
  79. package/src/commands/demo-mode.ts +160 -160
  80. package/src/commands/framebuffer.ts +73 -73
  81. package/src/commands/index.ts +8 -8
  82. package/src/commands/install.ts +21 -21
  83. package/src/commands/reverse.ts +134 -133
  84. package/src/commands/shell/index.ts +87 -68
  85. package/src/commands/shell/legacy.ts +59 -42
  86. package/src/commands/shell/protocol.ts +121 -94
  87. package/src/commands/shell/types.ts +55 -21
  88. package/src/commands/shell/utils.ts +20 -20
  89. package/src/commands/sync/index.ts +7 -7
  90. package/src/commands/sync/list.ts +39 -39
  91. package/src/commands/sync/pull.ts +34 -34
  92. package/src/commands/sync/push.ts +46 -46
  93. package/src/commands/sync/request.ts +49 -48
  94. package/src/commands/sync/response.ts +58 -57
  95. package/src/commands/sync/stat.ts +121 -121
  96. package/src/commands/sync/sync.ts +113 -113
  97. package/src/commands/tcpip.ts +21 -21
  98. package/src/crypto.ts +285 -280
  99. package/src/features.ts +5 -5
  100. package/src/index.ts +10 -10
  101. package/src/packet.ts +84 -89
  102. package/src/socket/close-event-emitter.ts +28 -28
  103. package/src/socket/controller.ts +105 -105
  104. package/src/socket/data-event-emitter.ts +27 -27
  105. package/src/socket/dispatcher.ts +269 -269
  106. package/src/socket/index.ts +6 -6
  107. package/src/socket/logger.ts +12 -12
  108. package/src/socket/socket.ts +28 -28
  109. package/src/stream/buffered-stream.ts +92 -100
  110. package/src/stream/index.ts +2 -2
  111. package/src/stream/stream.ts +50 -50
  112. package/src/utils/auto-reset-event.ts +41 -41
  113. package/src/utils/base64.ts +274 -274
  114. package/src/utils/chunk.ts +70 -70
  115. package/src/utils/encoding.ts +13 -0
  116. package/src/utils/event-queue.ts +145 -145
  117. package/src/utils/index.ts +5 -4
  118. package/cjs/adb.js +0 -205
  119. package/cjs/adb.js.map +0 -1
  120. package/cjs/auth.js +0 -141
  121. package/cjs/auth.js.map +0 -1
  122. package/cjs/backend.js +0 -3
  123. package/cjs/backend.js.map +0 -1
  124. package/cjs/commands/base.js +0 -12
  125. package/cjs/commands/base.js.map +0 -1
  126. package/cjs/commands/demo-mode.js +0 -174
  127. package/cjs/commands/demo-mode.js.map +0 -1
  128. package/cjs/commands/framebuffer.js +0 -66
  129. package/cjs/commands/framebuffer.js.map +0 -1
  130. package/cjs/commands/index.js +0 -12
  131. package/cjs/commands/index.js.map +0 -1
  132. package/cjs/commands/install.js +0 -20
  133. package/cjs/commands/install.js.map +0 -1
  134. package/cjs/commands/reverse.js +0 -105
  135. package/cjs/commands/reverse.js.map +0 -1
  136. package/cjs/commands/shell/index.js +0 -56
  137. package/cjs/commands/shell/index.js.map +0 -1
  138. package/cjs/commands/shell/legacy.js +0 -37
  139. package/cjs/commands/shell/legacy.js.map +0 -1
  140. package/cjs/commands/shell/protocol.js +0 -83
  141. package/cjs/commands/shell/protocol.js.map +0 -1
  142. package/cjs/commands/shell/types.js +0 -3
  143. package/cjs/commands/shell/types.js.map +0 -1
  144. package/cjs/commands/shell/utils.js +0 -23
  145. package/cjs/commands/shell/utils.js.map +0 -1
  146. package/cjs/commands/sync/index.js +0 -11
  147. package/cjs/commands/sync/index.js.map +0 -1
  148. package/cjs/commands/sync/list.js +0 -36
  149. package/cjs/commands/sync/list.js.map +0 -1
  150. package/cjs/commands/sync/pull.js +0 -34
  151. package/cjs/commands/sync/pull.js.map +0 -1
  152. package/cjs/commands/sync/push.js +0 -49
  153. package/cjs/commands/sync/push.js.map +0 -1
  154. package/cjs/commands/sync/request.js +0 -48
  155. package/cjs/commands/sync/request.js.map +0 -1
  156. package/cjs/commands/sync/response.js +0 -53
  157. package/cjs/commands/sync/response.js.map +0 -1
  158. package/cjs/commands/sync/stat.js +0 -109
  159. package/cjs/commands/sync/stat.js.map +0 -1
  160. package/cjs/commands/sync/sync.js +0 -118
  161. package/cjs/commands/sync/sync.js.map +0 -1
  162. package/cjs/commands/tcpip.js +0 -28
  163. package/cjs/commands/tcpip.js.map +0 -1
  164. package/cjs/crypto.js +0 -231
  165. package/cjs/crypto.js.map +0 -1
  166. package/cjs/features.js +0 -10
  167. package/cjs/features.js.map +0 -1
  168. package/cjs/index.js +0 -14
  169. package/cjs/index.js.map +0 -1
  170. package/cjs/packet.js +0 -77
  171. package/cjs/packet.js.map +0 -1
  172. package/cjs/socket/close-event-emitter.js +0 -32
  173. package/cjs/socket/close-event-emitter.js.map +0 -1
  174. package/cjs/socket/controller.js +0 -84
  175. package/cjs/socket/controller.js.map +0 -1
  176. package/cjs/socket/data-event-emitter.js +0 -29
  177. package/cjs/socket/data-event-emitter.js.map +0 -1
  178. package/cjs/socket/dispatcher.js +0 -219
  179. package/cjs/socket/dispatcher.js.map +0 -1
  180. package/cjs/socket/index.js +0 -10
  181. package/cjs/socket/index.js.map +0 -1
  182. package/cjs/socket/logger.js +0 -3
  183. package/cjs/socket/logger.js.map +0 -1
  184. package/cjs/socket/socket.js +0 -24
  185. package/cjs/socket/socket.js.map +0 -1
  186. package/cjs/stream/buffered-stream.js +0 -78
  187. package/cjs/stream/buffered-stream.js.map +0 -1
  188. package/cjs/stream/index.js +0 -6
  189. package/cjs/stream/index.js.map +0 -1
  190. package/cjs/stream/stream.js +0 -45
  191. package/cjs/stream/stream.js.map +0 -1
  192. package/cjs/utils/auto-reset-event.js +0 -37
  193. package/cjs/utils/auto-reset-event.js.map +0 -1
  194. package/cjs/utils/base64.js +0 -210
  195. package/cjs/utils/base64.js.map +0 -1
  196. package/cjs/utils/chunk.js +0 -75
  197. package/cjs/utils/chunk.js.map +0 -1
  198. package/cjs/utils/event-queue.js +0 -108
  199. package/cjs/utils/event-queue.js.map +0 -1
  200. package/cjs/utils/index.js +0 -8
  201. package/cjs/utils/index.js.map +0 -1
  202. package/tsconfig.cjs.json +0 -11
  203. package/tsconfig.esm.json +0 -28
  204. package/tsconfig.esm.tsbuildinfo +0 -1305
  205. 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
- // Modular exponentiation
200
- // See https://en.wikipedia.org/wiki/Modular_exponentiation#Implementation_in_Lua
201
- export function powMod(base: bigint, exponent: bigint, modulus: bigint): bigint {
202
- if (modulus === BigInt1) {
203
- return BigInt0;
204
- }
205
-
206
- let r = BigInt1;
207
- base = base % modulus;
208
-
209
- while (exponent > BigInt0) {
210
- if (BigInt.asUintN(1, exponent) === BigInt1) {
211
- r = r * base % modulus;
212
- }
213
-
214
- exponent >>= BigInt1;
215
- base = base ** BigInt2 % modulus;
216
- }
217
-
218
- return r;
219
- }
220
-
221
- export const Sha1DigestLength = 20;
222
-
223
- export const Asn1Sequence = 0x30;
224
- export const Asn1OctetString = 0x04;
225
- export const Asn1Null = 0x05;
226
- export const Asn1Oid = 0x06;
227
-
228
- // PKCS#1 SHA-1 hash digest info
229
- export const Sha1DigestInfo = [
230
- Asn1Sequence, 0x0d + Sha1DigestLength,
231
- Asn1Sequence, 0x09,
232
- // SHA-1 (1 3 14 3 2 26)
233
- Asn1Oid, 0x05, 1 * 40 + 3, 14, 3, 2, 26,
234
- Asn1Null, 0x00,
235
- Asn1OctetString, Sha1DigestLength
236
- ];
237
-
238
- // SubtleCrypto.sign() will hash the given data and sign the hash
239
- // But we don't need the hashing step
240
- // (In another word, ADB just requires the client to
241
- // encrypt the given data with its private key)
242
- // However SubtileCrypto.encrypt() doesn't accept 'RSASSA-PKCS1-v1_5' algorithm
243
- // So we need to implement the encryption by ourself
244
- export function sign(privateKey: ArrayBuffer, data: ArrayBuffer): ArrayBuffer {
245
- const [n, d] = parsePrivateKey(privateKey);
246
-
247
- // PKCS#1 padding
248
- const padded = new Uint8Array(256);
249
- let index = 0;
250
-
251
- padded[index] = 0;
252
- index += 1;
253
-
254
- padded[index] = 1;
255
- index += 1;
256
-
257
- const fillLength = padded.length - Sha1DigestInfo.length - data.byteLength - 1;
258
- while (index < fillLength) {
259
- padded[index] = 0xff;
260
- index += 1;
261
- }
262
-
263
- padded[index] = 0;
264
- index += 1;
265
-
266
- padded.set(new Uint8Array(Sha1DigestInfo), index);
267
- index += Sha1DigestInfo.length;
268
-
269
- padded.set(new Uint8Array(data), index);
270
-
271
- // Encryption
272
- // signature = padded ** d % n
273
- let signature = powMod(getBig(padded.buffer), d, n);
274
-
275
- // Put into an ArrayBuffer
276
- const result = new ArrayBuffer(256);
277
- setBig(result, signature);
278
-
279
- return result;
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';