Loading .vscode/settings.json +1 −1 Original line number Diff line number Diff line Loading @@ -116,6 +116,6 @@ "prettier.prettierPath": "./common/temp/node_modules/prettier/index.cjs", "cSpell.numSuggestions": 4, "cSpell.ignoreRegExpList": [ "0x[0-9a-f]+" "0x[0-9a-f_]+" ] } libraries/adb/src/daemon/auth.spec.ts +38 −77 Original line number Diff line number Diff line import { describe, expect, it } from "@jest/globals"; import { EMPTY_UINT8_ARRAY, encodeUtf8 } from "@yume-chan/struct"; import { decodeBase64 } from "../utils/base64.js"; import type { AdbCredentialStore } from "./auth.js"; import { AdbAuthType, AdbPublicKeyAuthenticator } from "./auth.js"; import type { AdbPacketData } from "./packet.js"; Loading Loading @@ -30,84 +31,44 @@ class MockCredentialStore implements AdbCredentialStore { } } const PRIVATE_KEY = [ 48, 130, 4, 189, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 167, 48, 130, 4, 163, 2, 1, 0, 2, 130, 1, 1, 0, 217, 179, 48, 37, 252, 254, 42, 107, 119, 116, 188, 159, 90, 212, 219, 207, 43, 31, 205, 216, 235, 91, 195, 185, 129, 2, 135, 239, 24, 99, 228, 231, 26, 86, 204, 63, 23, 228, 185, 227, 61, 156, 146, 229, 174, 162, 128, 247, 186, 142, 34, 234, 132, 123, 233, 239, 185, 68, 174, 155, 157, 184, 234, 95, 198, 134, 159, 28, 82, 43, 62, 4, 252, 78, 8, 158, 94, 246, 140, 207, 163, 87, 192, 250, 89, 19, 231, 241, 148, 93, 114, 9, 141, 127, 160, 89, 140, 96, 47, 38, 107, 81, 18, 96, 210, 123, 83, 88, 81, 10, 118, 156, 10, 153, 188, 37, 70, 37, 163, 237, 66, 161, 121, 252, 247, 47, 193, 36, 107, 193, 46, 130, 127, 191, 34, 129, 69, 172, 73, 196, 216, 157, 141, 78, 71, 85, 15, 101, 175, 196, 223, 64, 246, 119, 81, 63, 141, 107, 236, 193, 208, 72, 47, 213, 105, 42, 231, 22, 158, 150, 253, 43, 112, 149, 11, 121, 218, 90, 203, 89, 126, 145, 134, 68, 161, 19, 82, 119, 46, 253, 171, 5, 232, 127, 118, 27, 165, 209, 159, 145, 28, 99, 12, 200, 170, 251, 78, 94, 93, 113, 73, 129, 74, 171, 192, 102, 120, 18, 223, 135, 193, 16, 225, 184, 148, 153, 77, 167, 203, 159, 94, 193, 180, 153, 239, 31, 137, 103, 222, 20, 245, 253, 64, 138, 103, 132, 109, 39, 66, 138, 224, 3, 44, 247, 184, 25, 2, 3, 1, 0, 1, 2, 130, 1, 0, 18, 96, 73, 196, 43, 34, 217, 57, 209, 15, 141, 140, 118, 2, 89, 187, 151, 12, 76, 55, 239, 70, 3, 179, 120, 236, 89, 197, 24, 237, 245, 184, 124, 68, 175, 96, 244, 7, 94, 153, 139, 237, 215, 136, 131, 193, 59, 217, 173, 105, 170, 16, 217, 182, 11, 253, 44, 74, 91, 226, 206, 225, 121, 7, 52, 158, 208, 119, 119, 136, 38, 232, 12, 212, 25, 110, 36, 221, 242, 236, 228, 0, 216, 77, 73, 143, 160, 152, 135, 201, 139, 130, 186, 234, 247, 2, 24, 19, 86, 103, 139, 207, 128, 25, 164, 42, 188, 210, 75, 164, 242, 118, 33, 126, 240, 158, 196, 217, 16, 137, 74, 130, 142, 229, 135, 136, 4, 105, 130, 180, 130, 72, 128, 50, 23, 70, 161, 214, 94, 67, 43, 185, 30, 111, 254, 156, 213, 4, 17, 51, 121, 92, 84, 52, 166, 16, 184, 56, 133, 217, 227, 163, 27, 190, 31, 71, 79, 61, 126, 250, 58, 81, 64, 174, 129, 21, 239, 160, 153, 88, 206, 89, 147, 219, 106, 130, 36, 240, 177, 202, 190, 56, 209, 89, 49, 242, 103, 250, 237, 167, 12, 240, 140, 121, 38, 20, 212, 36, 244, 68, 151, 25, 28, 255, 101, 79, 217, 12, 82, 121, 254, 154, 174, 7, 88, 56, 49, 0, 217, 223, 32, 193, 203, 12, 236, 33, 203, 216, 40, 240, 230, 36, 112, 162, 129, 216, 166, 177, 107, 252, 39, 216, 24, 166, 181, 241, 2, 129, 129, 0, 249, 131, 185, 184, 67, 21, 70, 238, 177, 150, 21, 62, 29, 192, 126, 78, 115, 79, 140, 4, 242, 156, 90, 104, 211, 143, 183, 63, 12, 111, 143, 143, 16, 84, 209, 3, 214, 123, 103, 142, 255, 7, 148, 198, 43, 49, 65, 223, 247, 61, 91, 243, 59, 23, 190, 234, 181, 222, 30, 213, 188, 52, 116, 113, 152, 248, 193, 20, 115, 11, 116, 113, 103, 154, 79, 214, 95, 201, 78, 44, 41, 194, 32, 36, 120, 254, 25, 65, 10, 65, 200, 137, 213, 103, 88, 59, 224, 168, 141, 111, 78, 93, 215, 35, 21, 94, 4, 235, 5, 150, 206, 9, 85, 25, 207, 248, 169, 174, 237, 239, 177, 186, 67, 67, 193, 151, 61, 107, 2, 129, 129, 0, 223, 91, 196, 134, 0, 240, 151, 155, 10, 177, 81, 132, 59, 80, 24, 4, 151, 163, 156, 35, 236, 2, 210, 247, 183, 127, 167, 20, 194, 116, 150, 25, 82, 82, 139, 0, 115, 38, 198, 51, 218, 111, 177, 232, 0, 91, 96, 65, 143, 37, 42, 26, 240, 159, 159, 129, 250, 33, 12, 255, 90, 238, 249, 84, 120, 39, 247, 80, 105, 34, 23, 10, 123, 249, 185, 184, 155, 159, 217, 156, 158, 59, 175, 124, 24, 235, 142, 96, 141, 165, 156, 183, 41, 21, 250, 173, 119, 110, 192, 44, 35, 170, 140, 52, 97, 119, 237, 57, 226, 80, 144, 70, 41, 253, 57, 211, 181, 139, 15, 81, 91, 63, 32, 183, 64, 124, 221, 139, 2, 129, 128, 123, 118, 247, 246, 58, 147, 147, 182, 214, 255, 9, 225, 227, 188, 245, 131, 2, 66, 17, 105, 253, 86, 234, 209, 198, 37, 238, 41, 239, 144, 96, 124, 13, 59, 186, 245, 104, 51, 70, 42, 22, 253, 252, 91, 22, 210, 87, 227, 104, 38, 223, 145, 250, 226, 164, 32, 229, 255, 84, 72, 180, 201, 75, 249, 78, 21, 129, 13, 10, 100, 87, 169, 41, 247, 204, 155, 170, 104, 37, 27, 107, 74, 88, 183, 83, 123, 128, 169, 147, 86, 187, 209, 160, 92, 115, 231, 165, 34, 34, 98, 58, 103, 234, 229, 188, 83, 250, 161, 4, 241, 251, 95, 216, 209, 93, 252, 144, 146, 51, 192, 144, 180, 55, 70, 150, 203, 172, 163, 2, 129, 129, 0, 152, 92, 63, 237, 108, 252, 177, 94, 8, 104, 54, 131, 237, 245, 207, 188, 106, 56, 39, 205, 117, 51, 227, 247, 40, 140, 2, 76, 45, 237, 91, 106, 64, 118, 159, 237, 25, 159, 172, 122, 56, 154, 18, 144, 128, 149, 212, 78, 68, 56, 4, 197, 197, 184, 13, 21, 155, 171, 41, 243, 146, 115, 11, 79, 44, 123, 142, 191, 162, 71, 167, 209, 246, 9, 190, 63, 136, 160, 252, 207, 82, 60, 194, 146, 243, 104, 211, 129, 87, 126, 78, 45, 190, 240, 8, 68, 134, 0, 221, 67, 254, 188, 90, 209, 108, 95, 99, 74, 37, 239, 240, 202, 123, 224, 9, 175, 57, 218, 119, 3, 119, 43, 211, 196, 77, 80, 31, 203, 2, 129, 128, 44, 54, 34, 176, 67, 152, 179, 82, 5, 122, 133, 123, 5, 194, 237, 113, 52, 54, 94, 154, 121, 79, 197, 194, 67, 209, 188, 218, 239, 74, 128, 137, 21, 86, 240, 0, 111, 163, 37, 19, 208, 79, 27, 185, 110, 132, 219, 176, 97, 208, 113, 252, 13, 154, 168, 87, 33, 213, 244, 242, 163, 59, 114, 172, 217, 88, 122, 142, 7, 12, 198, 88, 163, 210, 192, 232, 139, 5, 98, 13, 228, 111, 249, 73, 95, 220, 30, 166, 59, 141, 27, 36, 0, 82, 99, 135, 150, 5, 217, 13, 87, 120, 14, 67, 187, 124, 57, 196, 224, 94, 201, 125, 227, 168, 224, 26, 195, 181, 73, 173, 52, 72, 232, 1, 67, 233, 249, 133, ]; // From `adbkey` generated by Google ADB const PRIVATE_KEY = decodeBase64( `-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPlpZTBGI2GL42 XMtFF0jkgVUVQeBcLBzdvKoHhiSbXmbWsxylnWIJHNo94PxNHeic5KQTWImcZQ9L b9RWshagmqee8Ab6a/6KyP+a5voSHMWiDZmSR3AHV/PsJIUGzE+TlQgxbjq6IRHi rwGkFo2NmAmUajtI3+eSuq2AZdKj7CVe4BfrcFmMv4//92whEybk0f4Genp0N4qi EfRCkK96h3Nij3ZvqgvscCV9edFF8j7R4UMIGzNF59aGL0wWIfZiyf/W2frv2H12 lXEc3fsZq9TkU9cIwuXW/yy80XJUJVo2ZPg5z6c9SzLXSy5CCfLA9StnLjtPfuI7 CNm/jpODAgMBAAECggEACNZaU/Jt0+u9vUa6CJjzK3cuDhed246tM+tiOavGRy7/ pcg+QfavQ8AMsnGvjADn9DXvnjs4sIXE3utF2OL//5pV5HhHc8XBMltYNln672Z2 K230ybts04M1CSqM1zs/cAL6NFCDA4WA42ub4EZthEeisMTM/U865o438K1lCEFj s0+pHWYL6HSirQUYkArIGgwP+PasY8zxkGBl4D3005ZZTjVu4e/c4QCwNn2Vi40T k/7DmrXm4yQeTrctWVIMxhjWeK2EAkgc9wWRFlpOnCDulP+lnM6wshD8x18muc1j rLfRbDvDxhVv1BygqJmbj0zOxAmW8mzCsa8gVvhB4QKBgQD1ZRFVpnRnu5ixHwVx l9NI9n0G9trKQee/OpC5d1bdgYdkOXrBV85STJctvJaitpD5i4H0nLITT5fhIZLL jfcBJVkXSdwuvqaOBXWRcNmNFDqQtpazXSx1pUuCsW2l9V/gLARJe98uDRVBCVM+ 8VvC7hamUNK10GEqg76I+oGlKwKBgQDYjz7Yj5E0M9Trkps3LKLEWMENWvz40vJC 7vDIOSpOnpqtqgW+JKLC53UGgoMEnXQRnAqPbmRj8xmwf9GIAqA2vZGFf5iehCGr /RiF8RLWxFZohUDYY3B/LDm7/urax7rhiCFbmyWCAsWkllKE8uGOP9eKVOcVjXT3 iZy14FbPCQKBgBrUEuIXUbCpnNb4ekLiA3J9qEujn2XvcKPChmIQfwm2iJPXiOks bV0oDHsunBVr+kueCfYxT3K3B/bQEdl5SuDwMV5Pb+gYZeMvC5x8BvzaklCR9cXk UOEH0kqWlVNIkVPT3CAgj9TcD0/N8jD2eD7Ggulp+q9v+b+JKcKWCKiDAoGBAL0N yKKMKwo0mZOSKDixmeLpTJeZMDEVDvOJ3uAcr6d05LnpLRxCpWibYVluhGx5/IMH A10V1URATNP9sfEXwcAoHCs8KgNwfGjGCiucOoMNYhXbBrIhlWsgM8LAF00pgicz jVOIjOUEAIDfzmhMFMb3SvZzik0RceRL2WgZ0g7pAoGAauflDCIaUwJJHEz6u5/w 5XiiqZFzcgzGJAo/ZHQqPbCms/lYGvKFTurg4RSrtpqKB2kVHe1gd65EW9W/JcBQ U1Q0nKXFxhKY+bz1IqiculhINnAxyBV91s6tdhoazkdSj6XCgtSK9SP/DfiAUWm0 ytnwjm/+s2vme5fFtK9hBKo= -----END PRIVATE KEY-----` .split("\n") .slice(1, -1) .join(""), ); // From `adbkey.pub` generated by Google ADB const PUBLIC_KEY = "QAAAANfbD8gZuPcsA+CKQidthGeKQP31FN5niR/vmbTBXp/Lp02ZlLjhEMGH3xJ4ZsCrSoFJcV1eTvuqyAxjHJGf0aUbdn/oBav9LndSE6FEhpF+Wcta2nkLlXAr/ZaeFucqadUvSNDB7GuNP1F39kDfxK9lD1VHTo2d2MRJrEWBIr9/gi7BayTBL/f8eaFC7aMlRiW8mQqcdgpRWFN70mASUWsmL2CMWaB/jQlyXZTx5xNZ+sBXo8+M9l6eCE78BD4rUhyfhsZf6ridm65Eue/pe4TqIo6694CiruWSnD3jueQXP8xWGufkYxjvhwKBucNb69jNHyvP29Ran7x0d2sq/vwlMLPZX7azjy0vpJEONdrhwsbYPQZp7Uj34JBDxB22/oh8NMuN9PwRUj+M9S+A3yRIS6zuvjk9nGUrgCH26js3LfkBywhYSERFHPc7h/yRWzMYL8udOGa5NByfVzSE4DtOj3cF/huVGV0Stedt7UnXSDrsAiasSo990IID7wHjpPX4tUM4AJZO8lYsP6kdCYOATZeR1geNwAJtR9UAnJythYEQMbEQzO15tuPpdq5h50DpZKwynW+ATMSdVOreAoWxy9Qs3zPLstBifMwT3/tuEgB/Q86wprfDhcIkAH9ahsQfZ+WCcqTqd4imP7+RrTKVsUvEIjyw+LlUIcFw1foRztbnpAEAAQA="; "QAAAANVsDNqDk46/2Qg74n5POy5nK/XA8glCLkvXMks9p885+GQ2WiVUctG8LP/W5cII11Pk1KsZ+90ccZV2fdjv+tnW/8li9iEWTC+G1udFMxsIQ+HRPvJF0Xl9JXDsC6pvdo9ic4d6r5BC9BGiijd0enoG/tHkJhMhbPf/j7+MWXDrF+BeJeyj0mWArbqS599IO2qUCZiNjRakAa/iESG6Om4xCJWTT8wGhSTs81cHcEeSmQ2ixRwS+uaa/8iK/mv6BvCep5qgFrJW1G9LD2WciVgTpOSc6B1N/OA92hwJYp2lHLPWZl6bJIYHqrzdHCxc4EEVVYHkSBdFy1w2vhg2YgRTlpbP00NVrZb6Car8BTqPnwTRIkHBC6nnrg6cWMQ0xusMtxChKBoYGhCLHY4iKK6ra3P1Ou1UXu0WySau3s+Av9FFXxtAuMAJUA+5GSMQGGECRhwLX910OfnHHN+VxqJkHQye4vNhIH5C1dJ39HJoxAdwH2tF7v7GF2fwsy2lUa3Vj6bBssWivCB9cKyJR0GVPZJZ1uah24ecvspwtAqbtxvj7ZD9l7AD92geEJdLrsbfhNaDyAioQ2grI32gdp80su/7BrdAsPaSomxCYBB8opmS+oJq6qTYxNZ0doT9EEyT5D9rl9UXXxq+rQbDpKV1rOQo5zJJ2GkELhUrslFm6n4+JQEAAQA="; describe("auth", () => { describe("PublicKeyAuthenticator", () => { Loading libraries/adb/src/daemon/auth.ts +1 −1 Original line number Diff line number Diff line Loading @@ -83,7 +83,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* ( command: AdbCommand.Auth, arg0: AdbAuthType.Signature, arg1: 0, payload: new Uint8Array(signature), payload: signature, }; } }; Loading libraries/adb/src/daemon/crypto.spec.ts 0 → 100644 +95 −0 Original line number Diff line number Diff line import { describe, expect, it } from "@jest/globals"; import { decodeBase64 } from "../utils/base64.js"; import { adbGeneratePublicKey, modInverse } from "./crypto.js"; describe("modInverse", () => { it("should return correct value", () => { // https://github.com/openssl/openssl/blob/98161274636dca12e3bfafab7d2d2ac28f4d7c30/test/bntest.c#L3176 expect(modInverse(5193817943, 3259122431)).toBe(2609653924); // https://cs.android.com/android/platform/superproject/main/+/main:external/cronet/third_party/boringssl/src/crypto/fipsmodule/bn/test/mod_inv_tests.txt expect(modInverse(0, 1)).toBe(NaN); expect(modInverse(1, 1)).toBe(NaN); expect(modInverse(2, 1)).toBe(NaN); expect(modInverse(3, 1)).toBe(NaN); expect(modInverse(0x54, 0xe3)).toBe(0x64); expect(modInverse(0x2b, 0x30)).toBe(0x13); expect(modInverse(0x30, 0x37)).toBe(0x2f); expect(modInverse(0x13, 0x4b)).toBe(0x4); expect(modInverse(0xcd4, 0x6a21)).toBe(0x1c47); expect(modInverse(0x8e7, 0x49c0)).toBe(0x2b97); expect(modInverse(0xfcb, 0x3092)).toBe(0x29b9); expect(modInverse(0x14bf, 0x41ae)).toBe(0xa83); expect(modInverse(0x11b5d53e, 0x322e92a1)).toBe(0x18f15fe1); expect(modInverse(0x8af6df6, 0x33d45eb7)).toBe(0x32f9453b); expect(modInverse(0xc5f89dd5, 0xfc09c17c)).toBe(0xd696369); expect(modInverse(0x60c2526, 0x74200493)).toBe(0x622839d8); }); }); // From `adbkey` generated by Google ADB const PRIVATE_KEY = decodeBase64( `-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPlpZTBGI2GL42 XMtFF0jkgVUVQeBcLBzdvKoHhiSbXmbWsxylnWIJHNo94PxNHeic5KQTWImcZQ9L b9RWshagmqee8Ab6a/6KyP+a5voSHMWiDZmSR3AHV/PsJIUGzE+TlQgxbjq6IRHi rwGkFo2NmAmUajtI3+eSuq2AZdKj7CVe4BfrcFmMv4//92whEybk0f4Genp0N4qi EfRCkK96h3Nij3ZvqgvscCV9edFF8j7R4UMIGzNF59aGL0wWIfZiyf/W2frv2H12 lXEc3fsZq9TkU9cIwuXW/yy80XJUJVo2ZPg5z6c9SzLXSy5CCfLA9StnLjtPfuI7 CNm/jpODAgMBAAECggEACNZaU/Jt0+u9vUa6CJjzK3cuDhed246tM+tiOavGRy7/ pcg+QfavQ8AMsnGvjADn9DXvnjs4sIXE3utF2OL//5pV5HhHc8XBMltYNln672Z2 K230ybts04M1CSqM1zs/cAL6NFCDA4WA42ub4EZthEeisMTM/U865o438K1lCEFj s0+pHWYL6HSirQUYkArIGgwP+PasY8zxkGBl4D3005ZZTjVu4e/c4QCwNn2Vi40T k/7DmrXm4yQeTrctWVIMxhjWeK2EAkgc9wWRFlpOnCDulP+lnM6wshD8x18muc1j rLfRbDvDxhVv1BygqJmbj0zOxAmW8mzCsa8gVvhB4QKBgQD1ZRFVpnRnu5ixHwVx l9NI9n0G9trKQee/OpC5d1bdgYdkOXrBV85STJctvJaitpD5i4H0nLITT5fhIZLL jfcBJVkXSdwuvqaOBXWRcNmNFDqQtpazXSx1pUuCsW2l9V/gLARJe98uDRVBCVM+ 8VvC7hamUNK10GEqg76I+oGlKwKBgQDYjz7Yj5E0M9Trkps3LKLEWMENWvz40vJC 7vDIOSpOnpqtqgW+JKLC53UGgoMEnXQRnAqPbmRj8xmwf9GIAqA2vZGFf5iehCGr /RiF8RLWxFZohUDYY3B/LDm7/urax7rhiCFbmyWCAsWkllKE8uGOP9eKVOcVjXT3 iZy14FbPCQKBgBrUEuIXUbCpnNb4ekLiA3J9qEujn2XvcKPChmIQfwm2iJPXiOks bV0oDHsunBVr+kueCfYxT3K3B/bQEdl5SuDwMV5Pb+gYZeMvC5x8BvzaklCR9cXk UOEH0kqWlVNIkVPT3CAgj9TcD0/N8jD2eD7Ggulp+q9v+b+JKcKWCKiDAoGBAL0N yKKMKwo0mZOSKDixmeLpTJeZMDEVDvOJ3uAcr6d05LnpLRxCpWibYVluhGx5/IMH A10V1URATNP9sfEXwcAoHCs8KgNwfGjGCiucOoMNYhXbBrIhlWsgM8LAF00pgicz jVOIjOUEAIDfzmhMFMb3SvZzik0RceRL2WgZ0g7pAoGAauflDCIaUwJJHEz6u5/w 5XiiqZFzcgzGJAo/ZHQqPbCms/lYGvKFTurg4RSrtpqKB2kVHe1gd65EW9W/JcBQ U1Q0nKXFxhKY+bz1IqiculhINnAxyBV91s6tdhoazkdSj6XCgtSK9SP/DfiAUWm0 ytnwjm/+s2vme5fFtK9hBKo= -----END PRIVATE KEY-----` .split("\n") .slice(1, -1) .join(""), ); // From `adbkey.pub` generated by Google ADB const PUBLIC_KEY = decodeBase64( "QAAAANVsDNqDk46/2Qg74n5POy5nK/XA8glCLkvXMks9p885+GQ2WiVUctG8LP/W5cII11Pk1KsZ+90ccZV2fdjv+tnW/8li9iEWTC+G1udFMxsIQ+HRPvJF0Xl9JXDsC6pvdo9ic4d6r5BC9BGiijd0enoG/tHkJhMhbPf/j7+MWXDrF+BeJeyj0mWArbqS599IO2qUCZiNjRakAa/iESG6Om4xCJWTT8wGhSTs81cHcEeSmQ2ixRwS+uaa/8iK/mv6BvCep5qgFrJW1G9LD2WciVgTpOSc6B1N/OA92hwJYp2lHLPWZl6bJIYHqrzdHCxc4EEVVYHkSBdFy1w2vhg2YgRTlpbP00NVrZb6Car8BTqPnwTRIkHBC6nnrg6cWMQ0xusMtxChKBoYGhCLHY4iKK6ra3P1Ou1UXu0WySau3s+Av9FFXxtAuMAJUA+5GSMQGGECRhwLX910OfnHHN+VxqJkHQye4vNhIH5C1dJ39HJoxAdwH2tF7v7GF2fwsy2lUa3Vj6bBssWivCB9cKyJR0GVPZJZ1uah24ecvspwtAqbtxvj7ZD9l7AD92geEJdLrsbfhNaDyAioQ2grI32gdp80su/7BrdAsPaSomxCYBB8opmS+oJq6qTYxNZ0doT9EEyT5D9rl9UXXxq+rQbDpKV1rOQo5zJJ2GkELhUrslFm6n4+JQEAAQA=", ); describe("adbGeneratePublicKey", () => { it("should return correct value", () => { const generated = adbGeneratePublicKey(PRIVATE_KEY); expect(generated.subarray(0, 4)).toStrictEqual( PUBLIC_KEY.subarray(0, 4), ); expect(generated.subarray(4, 8)).toStrictEqual( PUBLIC_KEY.subarray(4, 8), ); expect(generated.subarray(8, 264)).toStrictEqual( PUBLIC_KEY.subarray(8, 264), ); expect(generated.subarray(265, 520)).toStrictEqual( PUBLIC_KEY.subarray(265, 520), ); expect(generated.subarray(520, 524)).toStrictEqual( PUBLIC_KEY.subarray(520, 524), ); }); it("should throw if output is too small", () => { expect(() => adbGeneratePublicKey(PRIVATE_KEY, new Uint8Array(1)), ).toThrow("output buffer is too small"); }); }); libraries/adb/src/daemon/crypto.ts +49 −39 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ export function getBigUint( /** * Stores an arbitrary-precision positive `BigInt` value at the specified byte offset from the start of the view. * @param byteOffset The place in the buffer at which the value should be set. * @param length The number of bytes to set. * @param value The value to set. * @param littleEndian If `false` or `undefined`, a big-endian value should be written, * otherwise a little-endian value should be written. Loading @@ -40,11 +41,10 @@ export function getBigUint( export function setBigUint( array: Uint8Array, byteOffset: number, length: number, value: bigint, littleEndian?: boolean, ) { const start = byteOffset; if (littleEndian) { while (value > 0n) { setInt64LittleEndian(array, byteOffset, value); Loading @@ -52,23 +52,15 @@ export function setBigUint( value >>= 64n; } } else { // Because we don't know how long (in bits) the `value` is, // Convert it to an array of `uint64` first. const uint64Array: bigint[] = []; let position = byteOffset + length - 8; while (value > 0n) { uint64Array.push(BigInt.asUintN(64, value)); setInt64BigEndian(array, position, value); position -= 8; value >>= 64n; } for (let i = uint64Array.length - 1; i >= 0; i -= 1) { setInt64BigEndian(array, byteOffset, uint64Array[i]!); byteOffset += 8; } } return byteOffset - start; } // These values are correct only if // modulus length is 2048 and // public exponent (e) is 65537 Loading Loading @@ -101,11 +93,21 @@ export function rsaParsePrivateKey(key: Uint8Array): [n: bigint, d: bigint] { return [n, d]; } function nonNegativeMod(m: number, d: number) { const r = m % d; if (r > 0) { return r; } return r + (d > 0 ? d : -d); } // https://en.wikipedia.org/wiki/Modular_multiplicative_inverse // Solve for the smallest positive `x` in the equation `a * x ≡ 1 (mod m)`, // or in other words, `a * x % m = 1` // Taken from https://stackoverflow.com/a/51562038 // I can't understand, but it does work // Only used with numbers smaller than 2^32 so doesn't need BigInt export function modInverse(a: number, m: number) { a = ((a % m) + m) % m; a = nonNegativeMod(a, m); if (!a || m < 2) { return NaN; // invalid input } Loading @@ -116,6 +118,7 @@ export function modInverse(a: number, m: number) { [a, b] = [b, a % b]; s.push({ a, b }); } /* istanbul ignore next */ if (a !== 1) { return NaN; // inverse does not exists } Loading @@ -125,11 +128,14 @@ export function modInverse(a: number, m: number) { for (let i = s.length - 2; i >= 0; i -= 1) { [x, y] = [y, x - y * Math.floor(s[i]!.a / s[i]!.b)]; } return ((y % m) + m) % m; return nonNegativeMod(y, m); } const ModulusLengthInBytes = 2048 / 8; const ModulusLengthInWords = ModulusLengthInBytes / 4; export function adbGetPublicKeySize() { return 4 + 4 + 2048 / 8 + 2048 / 8 + 4; return 4 + 4 + ModulusLengthInBytes + ModulusLengthInBytes + 4; } export function adbGeneratePublicKey(privateKey: Uint8Array): Uint8Array; Loading @@ -141,22 +147,27 @@ export function adbGeneratePublicKey( privateKey: Uint8Array, output?: Uint8Array, ): Uint8Array | number { // Android has its own public key generation algorithm // See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#111 // The public key is an array of // cspell: ignore: mincrypt // Android 6 and earlier has its own encryption library called mincrypt // This is the RSA public key format used by mincrypt: // https://android.googlesource.com/platform/system/core/+/bb0c180e62703c2068a1b2c9f8ba6d634bf1553c/include/mincrypt/rsa.h#46 // `n0inv` and `rr` are pre-calculated to speed up RSA operations // Android 7 switched its encryption library to BoringSSL, but still keeps the key format: // https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#38 // Except when reading a key, `n0inv` and `rr` are ignored (they are still populated when generating a key): // https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#55 // The public key is a struct (in little endian) of: // // [ // modulusLengthInWords, // 32-bit integer, a "word" is 32-bit so it must be 2048 / 8 / 4 // // Actually the comment in Android source code was wrong // n0inv, // 32-bit integer, the modular inverse of (low 32 bits of n) // modulus, // n // // (the comment in Android source code is incorrect saying "This must be ANDROID_PUBKEY_MODULUS_SIZE") // n0inv, // 32-bit integer, the modular inverse of (lower 32 bits of `n`) // modulus, // `n` // rr, // Montgomery parameter R^2 // exponent, // 32-bit integer, must be 65537 // exponent, // 32-bit integer, must be 3 or 65537 // ] // // (All in little endian) // See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#38 let outputType: "Uint8Array" | "number"; const outputLength = adbGetPublicKeySize(); Loading @@ -179,26 +190,25 @@ export function adbGeneratePublicKey( let outputOffset = 0; // modulusLengthInWords outputView.setUint32(outputOffset, 2048 / 8 / 4, true); outputView.setUint32(outputOffset, ModulusLengthInWords, true); outputOffset += 4; // extract `n` from private key const [n] = rsaParsePrivateKey(privateKey); // Calculate `n0inv` // Don't know why need to multiply by -1 // Didn't exist in Android codebase const n0inv = modInverse(-Number(BigInt.asUintN(32, n)), 2 ** 32); outputView.setUint32(outputOffset, n0inv, true); const n0inv = -modInverse(Number(n % 2n ** 32n), 2 ** 32); outputView.setInt32(outputOffset, n0inv, true); outputOffset += 4; // Write n setBigUint(output, outputOffset, n, true); outputOffset += 256; // Write `n` (a.k.a. `modulus`) setBigUint(output, outputOffset, ModulusLengthInBytes, n, true); outputOffset += ModulusLengthInBytes; // Calculate rr = (2^(rsa_size)) ^ 2 mod n // Calculate rr = (2 ** (rsa_size)) ** 2 % n const rr = 2n ** 4096n % n; outputOffset += setBigUint(output, outputOffset, rr, true); setBigUint(output, outputOffset, ModulusLengthInBytes, rr, true); outputOffset += ModulusLengthInBytes; // exponent outputView.setUint32(outputOffset, 65537, true); Loading Loading @@ -309,7 +319,7 @@ export function rsaSign(privateKey: Uint8Array, data: Uint8Array): Uint8Array { // `padded` is not used anymore, // re-use the buffer to store the result setBigUint(padded, 0, signature, false); setBigUint(padded, 0, padded.length, signature, false); return padded; } Loading
.vscode/settings.json +1 −1 Original line number Diff line number Diff line Loading @@ -116,6 +116,6 @@ "prettier.prettierPath": "./common/temp/node_modules/prettier/index.cjs", "cSpell.numSuggestions": 4, "cSpell.ignoreRegExpList": [ "0x[0-9a-f]+" "0x[0-9a-f_]+" ] }
libraries/adb/src/daemon/auth.spec.ts +38 −77 Original line number Diff line number Diff line import { describe, expect, it } from "@jest/globals"; import { EMPTY_UINT8_ARRAY, encodeUtf8 } from "@yume-chan/struct"; import { decodeBase64 } from "../utils/base64.js"; import type { AdbCredentialStore } from "./auth.js"; import { AdbAuthType, AdbPublicKeyAuthenticator } from "./auth.js"; import type { AdbPacketData } from "./packet.js"; Loading Loading @@ -30,84 +31,44 @@ class MockCredentialStore implements AdbCredentialStore { } } const PRIVATE_KEY = [ 48, 130, 4, 189, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 167, 48, 130, 4, 163, 2, 1, 0, 2, 130, 1, 1, 0, 217, 179, 48, 37, 252, 254, 42, 107, 119, 116, 188, 159, 90, 212, 219, 207, 43, 31, 205, 216, 235, 91, 195, 185, 129, 2, 135, 239, 24, 99, 228, 231, 26, 86, 204, 63, 23, 228, 185, 227, 61, 156, 146, 229, 174, 162, 128, 247, 186, 142, 34, 234, 132, 123, 233, 239, 185, 68, 174, 155, 157, 184, 234, 95, 198, 134, 159, 28, 82, 43, 62, 4, 252, 78, 8, 158, 94, 246, 140, 207, 163, 87, 192, 250, 89, 19, 231, 241, 148, 93, 114, 9, 141, 127, 160, 89, 140, 96, 47, 38, 107, 81, 18, 96, 210, 123, 83, 88, 81, 10, 118, 156, 10, 153, 188, 37, 70, 37, 163, 237, 66, 161, 121, 252, 247, 47, 193, 36, 107, 193, 46, 130, 127, 191, 34, 129, 69, 172, 73, 196, 216, 157, 141, 78, 71, 85, 15, 101, 175, 196, 223, 64, 246, 119, 81, 63, 141, 107, 236, 193, 208, 72, 47, 213, 105, 42, 231, 22, 158, 150, 253, 43, 112, 149, 11, 121, 218, 90, 203, 89, 126, 145, 134, 68, 161, 19, 82, 119, 46, 253, 171, 5, 232, 127, 118, 27, 165, 209, 159, 145, 28, 99, 12, 200, 170, 251, 78, 94, 93, 113, 73, 129, 74, 171, 192, 102, 120, 18, 223, 135, 193, 16, 225, 184, 148, 153, 77, 167, 203, 159, 94, 193, 180, 153, 239, 31, 137, 103, 222, 20, 245, 253, 64, 138, 103, 132, 109, 39, 66, 138, 224, 3, 44, 247, 184, 25, 2, 3, 1, 0, 1, 2, 130, 1, 0, 18, 96, 73, 196, 43, 34, 217, 57, 209, 15, 141, 140, 118, 2, 89, 187, 151, 12, 76, 55, 239, 70, 3, 179, 120, 236, 89, 197, 24, 237, 245, 184, 124, 68, 175, 96, 244, 7, 94, 153, 139, 237, 215, 136, 131, 193, 59, 217, 173, 105, 170, 16, 217, 182, 11, 253, 44, 74, 91, 226, 206, 225, 121, 7, 52, 158, 208, 119, 119, 136, 38, 232, 12, 212, 25, 110, 36, 221, 242, 236, 228, 0, 216, 77, 73, 143, 160, 152, 135, 201, 139, 130, 186, 234, 247, 2, 24, 19, 86, 103, 139, 207, 128, 25, 164, 42, 188, 210, 75, 164, 242, 118, 33, 126, 240, 158, 196, 217, 16, 137, 74, 130, 142, 229, 135, 136, 4, 105, 130, 180, 130, 72, 128, 50, 23, 70, 161, 214, 94, 67, 43, 185, 30, 111, 254, 156, 213, 4, 17, 51, 121, 92, 84, 52, 166, 16, 184, 56, 133, 217, 227, 163, 27, 190, 31, 71, 79, 61, 126, 250, 58, 81, 64, 174, 129, 21, 239, 160, 153, 88, 206, 89, 147, 219, 106, 130, 36, 240, 177, 202, 190, 56, 209, 89, 49, 242, 103, 250, 237, 167, 12, 240, 140, 121, 38, 20, 212, 36, 244, 68, 151, 25, 28, 255, 101, 79, 217, 12, 82, 121, 254, 154, 174, 7, 88, 56, 49, 0, 217, 223, 32, 193, 203, 12, 236, 33, 203, 216, 40, 240, 230, 36, 112, 162, 129, 216, 166, 177, 107, 252, 39, 216, 24, 166, 181, 241, 2, 129, 129, 0, 249, 131, 185, 184, 67, 21, 70, 238, 177, 150, 21, 62, 29, 192, 126, 78, 115, 79, 140, 4, 242, 156, 90, 104, 211, 143, 183, 63, 12, 111, 143, 143, 16, 84, 209, 3, 214, 123, 103, 142, 255, 7, 148, 198, 43, 49, 65, 223, 247, 61, 91, 243, 59, 23, 190, 234, 181, 222, 30, 213, 188, 52, 116, 113, 152, 248, 193, 20, 115, 11, 116, 113, 103, 154, 79, 214, 95, 201, 78, 44, 41, 194, 32, 36, 120, 254, 25, 65, 10, 65, 200, 137, 213, 103, 88, 59, 224, 168, 141, 111, 78, 93, 215, 35, 21, 94, 4, 235, 5, 150, 206, 9, 85, 25, 207, 248, 169, 174, 237, 239, 177, 186, 67, 67, 193, 151, 61, 107, 2, 129, 129, 0, 223, 91, 196, 134, 0, 240, 151, 155, 10, 177, 81, 132, 59, 80, 24, 4, 151, 163, 156, 35, 236, 2, 210, 247, 183, 127, 167, 20, 194, 116, 150, 25, 82, 82, 139, 0, 115, 38, 198, 51, 218, 111, 177, 232, 0, 91, 96, 65, 143, 37, 42, 26, 240, 159, 159, 129, 250, 33, 12, 255, 90, 238, 249, 84, 120, 39, 247, 80, 105, 34, 23, 10, 123, 249, 185, 184, 155, 159, 217, 156, 158, 59, 175, 124, 24, 235, 142, 96, 141, 165, 156, 183, 41, 21, 250, 173, 119, 110, 192, 44, 35, 170, 140, 52, 97, 119, 237, 57, 226, 80, 144, 70, 41, 253, 57, 211, 181, 139, 15, 81, 91, 63, 32, 183, 64, 124, 221, 139, 2, 129, 128, 123, 118, 247, 246, 58, 147, 147, 182, 214, 255, 9, 225, 227, 188, 245, 131, 2, 66, 17, 105, 253, 86, 234, 209, 198, 37, 238, 41, 239, 144, 96, 124, 13, 59, 186, 245, 104, 51, 70, 42, 22, 253, 252, 91, 22, 210, 87, 227, 104, 38, 223, 145, 250, 226, 164, 32, 229, 255, 84, 72, 180, 201, 75, 249, 78, 21, 129, 13, 10, 100, 87, 169, 41, 247, 204, 155, 170, 104, 37, 27, 107, 74, 88, 183, 83, 123, 128, 169, 147, 86, 187, 209, 160, 92, 115, 231, 165, 34, 34, 98, 58, 103, 234, 229, 188, 83, 250, 161, 4, 241, 251, 95, 216, 209, 93, 252, 144, 146, 51, 192, 144, 180, 55, 70, 150, 203, 172, 163, 2, 129, 129, 0, 152, 92, 63, 237, 108, 252, 177, 94, 8, 104, 54, 131, 237, 245, 207, 188, 106, 56, 39, 205, 117, 51, 227, 247, 40, 140, 2, 76, 45, 237, 91, 106, 64, 118, 159, 237, 25, 159, 172, 122, 56, 154, 18, 144, 128, 149, 212, 78, 68, 56, 4, 197, 197, 184, 13, 21, 155, 171, 41, 243, 146, 115, 11, 79, 44, 123, 142, 191, 162, 71, 167, 209, 246, 9, 190, 63, 136, 160, 252, 207, 82, 60, 194, 146, 243, 104, 211, 129, 87, 126, 78, 45, 190, 240, 8, 68, 134, 0, 221, 67, 254, 188, 90, 209, 108, 95, 99, 74, 37, 239, 240, 202, 123, 224, 9, 175, 57, 218, 119, 3, 119, 43, 211, 196, 77, 80, 31, 203, 2, 129, 128, 44, 54, 34, 176, 67, 152, 179, 82, 5, 122, 133, 123, 5, 194, 237, 113, 52, 54, 94, 154, 121, 79, 197, 194, 67, 209, 188, 218, 239, 74, 128, 137, 21, 86, 240, 0, 111, 163, 37, 19, 208, 79, 27, 185, 110, 132, 219, 176, 97, 208, 113, 252, 13, 154, 168, 87, 33, 213, 244, 242, 163, 59, 114, 172, 217, 88, 122, 142, 7, 12, 198, 88, 163, 210, 192, 232, 139, 5, 98, 13, 228, 111, 249, 73, 95, 220, 30, 166, 59, 141, 27, 36, 0, 82, 99, 135, 150, 5, 217, 13, 87, 120, 14, 67, 187, 124, 57, 196, 224, 94, 201, 125, 227, 168, 224, 26, 195, 181, 73, 173, 52, 72, 232, 1, 67, 233, 249, 133, ]; // From `adbkey` generated by Google ADB const PRIVATE_KEY = decodeBase64( `-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPlpZTBGI2GL42 XMtFF0jkgVUVQeBcLBzdvKoHhiSbXmbWsxylnWIJHNo94PxNHeic5KQTWImcZQ9L b9RWshagmqee8Ab6a/6KyP+a5voSHMWiDZmSR3AHV/PsJIUGzE+TlQgxbjq6IRHi rwGkFo2NmAmUajtI3+eSuq2AZdKj7CVe4BfrcFmMv4//92whEybk0f4Genp0N4qi EfRCkK96h3Nij3ZvqgvscCV9edFF8j7R4UMIGzNF59aGL0wWIfZiyf/W2frv2H12 lXEc3fsZq9TkU9cIwuXW/yy80XJUJVo2ZPg5z6c9SzLXSy5CCfLA9StnLjtPfuI7 CNm/jpODAgMBAAECggEACNZaU/Jt0+u9vUa6CJjzK3cuDhed246tM+tiOavGRy7/ pcg+QfavQ8AMsnGvjADn9DXvnjs4sIXE3utF2OL//5pV5HhHc8XBMltYNln672Z2 K230ybts04M1CSqM1zs/cAL6NFCDA4WA42ub4EZthEeisMTM/U865o438K1lCEFj s0+pHWYL6HSirQUYkArIGgwP+PasY8zxkGBl4D3005ZZTjVu4e/c4QCwNn2Vi40T k/7DmrXm4yQeTrctWVIMxhjWeK2EAkgc9wWRFlpOnCDulP+lnM6wshD8x18muc1j rLfRbDvDxhVv1BygqJmbj0zOxAmW8mzCsa8gVvhB4QKBgQD1ZRFVpnRnu5ixHwVx l9NI9n0G9trKQee/OpC5d1bdgYdkOXrBV85STJctvJaitpD5i4H0nLITT5fhIZLL jfcBJVkXSdwuvqaOBXWRcNmNFDqQtpazXSx1pUuCsW2l9V/gLARJe98uDRVBCVM+ 8VvC7hamUNK10GEqg76I+oGlKwKBgQDYjz7Yj5E0M9Trkps3LKLEWMENWvz40vJC 7vDIOSpOnpqtqgW+JKLC53UGgoMEnXQRnAqPbmRj8xmwf9GIAqA2vZGFf5iehCGr /RiF8RLWxFZohUDYY3B/LDm7/urax7rhiCFbmyWCAsWkllKE8uGOP9eKVOcVjXT3 iZy14FbPCQKBgBrUEuIXUbCpnNb4ekLiA3J9qEujn2XvcKPChmIQfwm2iJPXiOks bV0oDHsunBVr+kueCfYxT3K3B/bQEdl5SuDwMV5Pb+gYZeMvC5x8BvzaklCR9cXk UOEH0kqWlVNIkVPT3CAgj9TcD0/N8jD2eD7Ggulp+q9v+b+JKcKWCKiDAoGBAL0N yKKMKwo0mZOSKDixmeLpTJeZMDEVDvOJ3uAcr6d05LnpLRxCpWibYVluhGx5/IMH A10V1URATNP9sfEXwcAoHCs8KgNwfGjGCiucOoMNYhXbBrIhlWsgM8LAF00pgicz jVOIjOUEAIDfzmhMFMb3SvZzik0RceRL2WgZ0g7pAoGAauflDCIaUwJJHEz6u5/w 5XiiqZFzcgzGJAo/ZHQqPbCms/lYGvKFTurg4RSrtpqKB2kVHe1gd65EW9W/JcBQ U1Q0nKXFxhKY+bz1IqiculhINnAxyBV91s6tdhoazkdSj6XCgtSK9SP/DfiAUWm0 ytnwjm/+s2vme5fFtK9hBKo= -----END PRIVATE KEY-----` .split("\n") .slice(1, -1) .join(""), ); // From `adbkey.pub` generated by Google ADB const PUBLIC_KEY = "QAAAANfbD8gZuPcsA+CKQidthGeKQP31FN5niR/vmbTBXp/Lp02ZlLjhEMGH3xJ4ZsCrSoFJcV1eTvuqyAxjHJGf0aUbdn/oBav9LndSE6FEhpF+Wcta2nkLlXAr/ZaeFucqadUvSNDB7GuNP1F39kDfxK9lD1VHTo2d2MRJrEWBIr9/gi7BayTBL/f8eaFC7aMlRiW8mQqcdgpRWFN70mASUWsmL2CMWaB/jQlyXZTx5xNZ+sBXo8+M9l6eCE78BD4rUhyfhsZf6ridm65Eue/pe4TqIo6694CiruWSnD3jueQXP8xWGufkYxjvhwKBucNb69jNHyvP29Ran7x0d2sq/vwlMLPZX7azjy0vpJEONdrhwsbYPQZp7Uj34JBDxB22/oh8NMuN9PwRUj+M9S+A3yRIS6zuvjk9nGUrgCH26js3LfkBywhYSERFHPc7h/yRWzMYL8udOGa5NByfVzSE4DtOj3cF/huVGV0Stedt7UnXSDrsAiasSo990IID7wHjpPX4tUM4AJZO8lYsP6kdCYOATZeR1geNwAJtR9UAnJythYEQMbEQzO15tuPpdq5h50DpZKwynW+ATMSdVOreAoWxy9Qs3zPLstBifMwT3/tuEgB/Q86wprfDhcIkAH9ahsQfZ+WCcqTqd4imP7+RrTKVsUvEIjyw+LlUIcFw1foRztbnpAEAAQA="; "QAAAANVsDNqDk46/2Qg74n5POy5nK/XA8glCLkvXMks9p885+GQ2WiVUctG8LP/W5cII11Pk1KsZ+90ccZV2fdjv+tnW/8li9iEWTC+G1udFMxsIQ+HRPvJF0Xl9JXDsC6pvdo9ic4d6r5BC9BGiijd0enoG/tHkJhMhbPf/j7+MWXDrF+BeJeyj0mWArbqS599IO2qUCZiNjRakAa/iESG6Om4xCJWTT8wGhSTs81cHcEeSmQ2ixRwS+uaa/8iK/mv6BvCep5qgFrJW1G9LD2WciVgTpOSc6B1N/OA92hwJYp2lHLPWZl6bJIYHqrzdHCxc4EEVVYHkSBdFy1w2vhg2YgRTlpbP00NVrZb6Car8BTqPnwTRIkHBC6nnrg6cWMQ0xusMtxChKBoYGhCLHY4iKK6ra3P1Ou1UXu0WySau3s+Av9FFXxtAuMAJUA+5GSMQGGECRhwLX910OfnHHN+VxqJkHQye4vNhIH5C1dJ39HJoxAdwH2tF7v7GF2fwsy2lUa3Vj6bBssWivCB9cKyJR0GVPZJZ1uah24ecvspwtAqbtxvj7ZD9l7AD92geEJdLrsbfhNaDyAioQ2grI32gdp80su/7BrdAsPaSomxCYBB8opmS+oJq6qTYxNZ0doT9EEyT5D9rl9UXXxq+rQbDpKV1rOQo5zJJ2GkELhUrslFm6n4+JQEAAQA="; describe("auth", () => { describe("PublicKeyAuthenticator", () => { Loading
libraries/adb/src/daemon/auth.ts +1 −1 Original line number Diff line number Diff line Loading @@ -83,7 +83,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* ( command: AdbCommand.Auth, arg0: AdbAuthType.Signature, arg1: 0, payload: new Uint8Array(signature), payload: signature, }; } }; Loading
libraries/adb/src/daemon/crypto.spec.ts 0 → 100644 +95 −0 Original line number Diff line number Diff line import { describe, expect, it } from "@jest/globals"; import { decodeBase64 } from "../utils/base64.js"; import { adbGeneratePublicKey, modInverse } from "./crypto.js"; describe("modInverse", () => { it("should return correct value", () => { // https://github.com/openssl/openssl/blob/98161274636dca12e3bfafab7d2d2ac28f4d7c30/test/bntest.c#L3176 expect(modInverse(5193817943, 3259122431)).toBe(2609653924); // https://cs.android.com/android/platform/superproject/main/+/main:external/cronet/third_party/boringssl/src/crypto/fipsmodule/bn/test/mod_inv_tests.txt expect(modInverse(0, 1)).toBe(NaN); expect(modInverse(1, 1)).toBe(NaN); expect(modInverse(2, 1)).toBe(NaN); expect(modInverse(3, 1)).toBe(NaN); expect(modInverse(0x54, 0xe3)).toBe(0x64); expect(modInverse(0x2b, 0x30)).toBe(0x13); expect(modInverse(0x30, 0x37)).toBe(0x2f); expect(modInverse(0x13, 0x4b)).toBe(0x4); expect(modInverse(0xcd4, 0x6a21)).toBe(0x1c47); expect(modInverse(0x8e7, 0x49c0)).toBe(0x2b97); expect(modInverse(0xfcb, 0x3092)).toBe(0x29b9); expect(modInverse(0x14bf, 0x41ae)).toBe(0xa83); expect(modInverse(0x11b5d53e, 0x322e92a1)).toBe(0x18f15fe1); expect(modInverse(0x8af6df6, 0x33d45eb7)).toBe(0x32f9453b); expect(modInverse(0xc5f89dd5, 0xfc09c17c)).toBe(0xd696369); expect(modInverse(0x60c2526, 0x74200493)).toBe(0x622839d8); }); }); // From `adbkey` generated by Google ADB const PRIVATE_KEY = decodeBase64( `-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPlpZTBGI2GL42 XMtFF0jkgVUVQeBcLBzdvKoHhiSbXmbWsxylnWIJHNo94PxNHeic5KQTWImcZQ9L b9RWshagmqee8Ab6a/6KyP+a5voSHMWiDZmSR3AHV/PsJIUGzE+TlQgxbjq6IRHi rwGkFo2NmAmUajtI3+eSuq2AZdKj7CVe4BfrcFmMv4//92whEybk0f4Genp0N4qi EfRCkK96h3Nij3ZvqgvscCV9edFF8j7R4UMIGzNF59aGL0wWIfZiyf/W2frv2H12 lXEc3fsZq9TkU9cIwuXW/yy80XJUJVo2ZPg5z6c9SzLXSy5CCfLA9StnLjtPfuI7 CNm/jpODAgMBAAECggEACNZaU/Jt0+u9vUa6CJjzK3cuDhed246tM+tiOavGRy7/ pcg+QfavQ8AMsnGvjADn9DXvnjs4sIXE3utF2OL//5pV5HhHc8XBMltYNln672Z2 K230ybts04M1CSqM1zs/cAL6NFCDA4WA42ub4EZthEeisMTM/U865o438K1lCEFj s0+pHWYL6HSirQUYkArIGgwP+PasY8zxkGBl4D3005ZZTjVu4e/c4QCwNn2Vi40T k/7DmrXm4yQeTrctWVIMxhjWeK2EAkgc9wWRFlpOnCDulP+lnM6wshD8x18muc1j rLfRbDvDxhVv1BygqJmbj0zOxAmW8mzCsa8gVvhB4QKBgQD1ZRFVpnRnu5ixHwVx l9NI9n0G9trKQee/OpC5d1bdgYdkOXrBV85STJctvJaitpD5i4H0nLITT5fhIZLL jfcBJVkXSdwuvqaOBXWRcNmNFDqQtpazXSx1pUuCsW2l9V/gLARJe98uDRVBCVM+ 8VvC7hamUNK10GEqg76I+oGlKwKBgQDYjz7Yj5E0M9Trkps3LKLEWMENWvz40vJC 7vDIOSpOnpqtqgW+JKLC53UGgoMEnXQRnAqPbmRj8xmwf9GIAqA2vZGFf5iehCGr /RiF8RLWxFZohUDYY3B/LDm7/urax7rhiCFbmyWCAsWkllKE8uGOP9eKVOcVjXT3 iZy14FbPCQKBgBrUEuIXUbCpnNb4ekLiA3J9qEujn2XvcKPChmIQfwm2iJPXiOks bV0oDHsunBVr+kueCfYxT3K3B/bQEdl5SuDwMV5Pb+gYZeMvC5x8BvzaklCR9cXk UOEH0kqWlVNIkVPT3CAgj9TcD0/N8jD2eD7Ggulp+q9v+b+JKcKWCKiDAoGBAL0N yKKMKwo0mZOSKDixmeLpTJeZMDEVDvOJ3uAcr6d05LnpLRxCpWibYVluhGx5/IMH A10V1URATNP9sfEXwcAoHCs8KgNwfGjGCiucOoMNYhXbBrIhlWsgM8LAF00pgicz jVOIjOUEAIDfzmhMFMb3SvZzik0RceRL2WgZ0g7pAoGAauflDCIaUwJJHEz6u5/w 5XiiqZFzcgzGJAo/ZHQqPbCms/lYGvKFTurg4RSrtpqKB2kVHe1gd65EW9W/JcBQ U1Q0nKXFxhKY+bz1IqiculhINnAxyBV91s6tdhoazkdSj6XCgtSK9SP/DfiAUWm0 ytnwjm/+s2vme5fFtK9hBKo= -----END PRIVATE KEY-----` .split("\n") .slice(1, -1) .join(""), ); // From `adbkey.pub` generated by Google ADB const PUBLIC_KEY = decodeBase64( "QAAAANVsDNqDk46/2Qg74n5POy5nK/XA8glCLkvXMks9p885+GQ2WiVUctG8LP/W5cII11Pk1KsZ+90ccZV2fdjv+tnW/8li9iEWTC+G1udFMxsIQ+HRPvJF0Xl9JXDsC6pvdo9ic4d6r5BC9BGiijd0enoG/tHkJhMhbPf/j7+MWXDrF+BeJeyj0mWArbqS599IO2qUCZiNjRakAa/iESG6Om4xCJWTT8wGhSTs81cHcEeSmQ2ixRwS+uaa/8iK/mv6BvCep5qgFrJW1G9LD2WciVgTpOSc6B1N/OA92hwJYp2lHLPWZl6bJIYHqrzdHCxc4EEVVYHkSBdFy1w2vhg2YgRTlpbP00NVrZb6Car8BTqPnwTRIkHBC6nnrg6cWMQ0xusMtxChKBoYGhCLHY4iKK6ra3P1Ou1UXu0WySau3s+Av9FFXxtAuMAJUA+5GSMQGGECRhwLX910OfnHHN+VxqJkHQye4vNhIH5C1dJ39HJoxAdwH2tF7v7GF2fwsy2lUa3Vj6bBssWivCB9cKyJR0GVPZJZ1uah24ecvspwtAqbtxvj7ZD9l7AD92geEJdLrsbfhNaDyAioQ2grI32gdp80su/7BrdAsPaSomxCYBB8opmS+oJq6qTYxNZ0doT9EEyT5D9rl9UXXxq+rQbDpKV1rOQo5zJJ2GkELhUrslFm6n4+JQEAAQA=", ); describe("adbGeneratePublicKey", () => { it("should return correct value", () => { const generated = adbGeneratePublicKey(PRIVATE_KEY); expect(generated.subarray(0, 4)).toStrictEqual( PUBLIC_KEY.subarray(0, 4), ); expect(generated.subarray(4, 8)).toStrictEqual( PUBLIC_KEY.subarray(4, 8), ); expect(generated.subarray(8, 264)).toStrictEqual( PUBLIC_KEY.subarray(8, 264), ); expect(generated.subarray(265, 520)).toStrictEqual( PUBLIC_KEY.subarray(265, 520), ); expect(generated.subarray(520, 524)).toStrictEqual( PUBLIC_KEY.subarray(520, 524), ); }); it("should throw if output is too small", () => { expect(() => adbGeneratePublicKey(PRIVATE_KEY, new Uint8Array(1)), ).toThrow("output buffer is too small"); }); });
libraries/adb/src/daemon/crypto.ts +49 −39 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ export function getBigUint( /** * Stores an arbitrary-precision positive `BigInt` value at the specified byte offset from the start of the view. * @param byteOffset The place in the buffer at which the value should be set. * @param length The number of bytes to set. * @param value The value to set. * @param littleEndian If `false` or `undefined`, a big-endian value should be written, * otherwise a little-endian value should be written. Loading @@ -40,11 +41,10 @@ export function getBigUint( export function setBigUint( array: Uint8Array, byteOffset: number, length: number, value: bigint, littleEndian?: boolean, ) { const start = byteOffset; if (littleEndian) { while (value > 0n) { setInt64LittleEndian(array, byteOffset, value); Loading @@ -52,23 +52,15 @@ export function setBigUint( value >>= 64n; } } else { // Because we don't know how long (in bits) the `value` is, // Convert it to an array of `uint64` first. const uint64Array: bigint[] = []; let position = byteOffset + length - 8; while (value > 0n) { uint64Array.push(BigInt.asUintN(64, value)); setInt64BigEndian(array, position, value); position -= 8; value >>= 64n; } for (let i = uint64Array.length - 1; i >= 0; i -= 1) { setInt64BigEndian(array, byteOffset, uint64Array[i]!); byteOffset += 8; } } return byteOffset - start; } // These values are correct only if // modulus length is 2048 and // public exponent (e) is 65537 Loading Loading @@ -101,11 +93,21 @@ export function rsaParsePrivateKey(key: Uint8Array): [n: bigint, d: bigint] { return [n, d]; } function nonNegativeMod(m: number, d: number) { const r = m % d; if (r > 0) { return r; } return r + (d > 0 ? d : -d); } // https://en.wikipedia.org/wiki/Modular_multiplicative_inverse // Solve for the smallest positive `x` in the equation `a * x ≡ 1 (mod m)`, // or in other words, `a * x % m = 1` // Taken from https://stackoverflow.com/a/51562038 // I can't understand, but it does work // Only used with numbers smaller than 2^32 so doesn't need BigInt export function modInverse(a: number, m: number) { a = ((a % m) + m) % m; a = nonNegativeMod(a, m); if (!a || m < 2) { return NaN; // invalid input } Loading @@ -116,6 +118,7 @@ export function modInverse(a: number, m: number) { [a, b] = [b, a % b]; s.push({ a, b }); } /* istanbul ignore next */ if (a !== 1) { return NaN; // inverse does not exists } Loading @@ -125,11 +128,14 @@ export function modInverse(a: number, m: number) { for (let i = s.length - 2; i >= 0; i -= 1) { [x, y] = [y, x - y * Math.floor(s[i]!.a / s[i]!.b)]; } return ((y % m) + m) % m; return nonNegativeMod(y, m); } const ModulusLengthInBytes = 2048 / 8; const ModulusLengthInWords = ModulusLengthInBytes / 4; export function adbGetPublicKeySize() { return 4 + 4 + 2048 / 8 + 2048 / 8 + 4; return 4 + 4 + ModulusLengthInBytes + ModulusLengthInBytes + 4; } export function adbGeneratePublicKey(privateKey: Uint8Array): Uint8Array; Loading @@ -141,22 +147,27 @@ export function adbGeneratePublicKey( privateKey: Uint8Array, output?: Uint8Array, ): Uint8Array | number { // Android has its own public key generation algorithm // See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#111 // The public key is an array of // cspell: ignore: mincrypt // Android 6 and earlier has its own encryption library called mincrypt // This is the RSA public key format used by mincrypt: // https://android.googlesource.com/platform/system/core/+/bb0c180e62703c2068a1b2c9f8ba6d634bf1553c/include/mincrypt/rsa.h#46 // `n0inv` and `rr` are pre-calculated to speed up RSA operations // Android 7 switched its encryption library to BoringSSL, but still keeps the key format: // https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#38 // Except when reading a key, `n0inv` and `rr` are ignored (they are still populated when generating a key): // https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#55 // The public key is a struct (in little endian) of: // // [ // modulusLengthInWords, // 32-bit integer, a "word" is 32-bit so it must be 2048 / 8 / 4 // // Actually the comment in Android source code was wrong // n0inv, // 32-bit integer, the modular inverse of (low 32 bits of n) // modulus, // n // // (the comment in Android source code is incorrect saying "This must be ANDROID_PUBKEY_MODULUS_SIZE") // n0inv, // 32-bit integer, the modular inverse of (lower 32 bits of `n`) // modulus, // `n` // rr, // Montgomery parameter R^2 // exponent, // 32-bit integer, must be 65537 // exponent, // 32-bit integer, must be 3 or 65537 // ] // // (All in little endian) // See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#38 let outputType: "Uint8Array" | "number"; const outputLength = adbGetPublicKeySize(); Loading @@ -179,26 +190,25 @@ export function adbGeneratePublicKey( let outputOffset = 0; // modulusLengthInWords outputView.setUint32(outputOffset, 2048 / 8 / 4, true); outputView.setUint32(outputOffset, ModulusLengthInWords, true); outputOffset += 4; // extract `n` from private key const [n] = rsaParsePrivateKey(privateKey); // Calculate `n0inv` // Don't know why need to multiply by -1 // Didn't exist in Android codebase const n0inv = modInverse(-Number(BigInt.asUintN(32, n)), 2 ** 32); outputView.setUint32(outputOffset, n0inv, true); const n0inv = -modInverse(Number(n % 2n ** 32n), 2 ** 32); outputView.setInt32(outputOffset, n0inv, true); outputOffset += 4; // Write n setBigUint(output, outputOffset, n, true); outputOffset += 256; // Write `n` (a.k.a. `modulus`) setBigUint(output, outputOffset, ModulusLengthInBytes, n, true); outputOffset += ModulusLengthInBytes; // Calculate rr = (2^(rsa_size)) ^ 2 mod n // Calculate rr = (2 ** (rsa_size)) ** 2 % n const rr = 2n ** 4096n % n; outputOffset += setBigUint(output, outputOffset, rr, true); setBigUint(output, outputOffset, ModulusLengthInBytes, rr, true); outputOffset += ModulusLengthInBytes; // exponent outputView.setUint32(outputOffset, 65537, true); Loading Loading @@ -309,7 +319,7 @@ export function rsaSign(privateKey: Uint8Array, data: Uint8Array): Uint8Array { // `padded` is not used anymore, // re-use the buffer to store the result setBigUint(padded, 0, signature, false); setBigUint(padded, 0, padded.length, signature, false); return padded; }