@ledgerhq/revault-sdk 0.28.11 → 0.28.14
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/lib/bake.cjs +3 -3
- package/lib/bake.cjs.map +1 -1
- package/lib/bake.d.cts +2 -2
- package/lib/bake.d.ts +2 -2
- package/lib/bake.js +3 -3
- package/lib/bake.js.map +1 -1
- package/lib/{crypto-BTN8FS8v.cjs → crypto-CKLQSwr3.cjs} +48 -12
- package/lib/crypto-CKLQSwr3.cjs.map +1 -0
- package/lib/{crypto-BcqzGi2f.js → crypto-hrnmToQa.js} +48 -11
- package/lib/crypto-hrnmToQa.js.map +1 -0
- package/lib/crypto.cjs +1 -1
- package/lib/crypto.js +1 -1
- package/lib/{device-DQyYUWPl.js → device-BnO26Hlr.js} +90 -34
- package/lib/device-BnO26Hlr.js.map +1 -0
- package/lib/{device-DQ32fSI-.cjs → device-CvgFoib2.cjs} +113 -33
- package/lib/device-CvgFoib2.cjs.map +1 -0
- package/lib/device.cjs +3 -1
- package/lib/device.d.cts +2 -2
- package/lib/device.d.ts +2 -2
- package/lib/device.js +2 -2
- package/lib/engine.cjs +93 -53
- package/lib/engine.cjs.map +1 -1
- package/lib/engine.d.cts +2 -2
- package/lib/engine.d.ts +2 -2
- package/lib/engine.js +94 -54
- package/lib/engine.js.map +1 -1
- package/lib/{index-xlQiIxlX.d.ts → index-16zV3onR.d.ts} +1 -1
- package/lib/{index-B3IUJM2r.d.cts → index-BAb2WCcL.d.cts} +25 -14
- package/lib/{index-Doiqe3tk.d.cts → index-CliA8Mh-.d.cts} +1 -1
- package/lib/{index-B1WQdM71.d.ts → index-DQgupTPR.d.ts} +25 -14
- package/lib/index.cjs +1 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/onboarding.cjs +6 -2
- package/lib/onboarding.cjs.map +1 -1
- package/lib/onboarding.d.cts +2 -2
- package/lib/onboarding.d.ts +2 -2
- package/lib/onboarding.js +6 -2
- package/lib/onboarding.js.map +1 -1
- package/lib/{types-DzZQZPXO.d.cts → types-bfqkmpgo.d.cts} +2 -1
- package/lib/{types-DqjcDy4H.d.ts → types-tRODcWIL.d.ts} +2 -1
- package/package.json +4 -5
- package/lib/crypto-BTN8FS8v.cjs.map +0 -1
- package/lib/crypto-BcqzGi2f.js.map +0 -1
- package/lib/device-DQ32fSI-.cjs.map +0 -1
- package/lib/device-DQyYUWPl.js.map +0 -1
|
@@ -3,10 +3,13 @@ let _noble_hashes_sha2_js = require("@noble/hashes/sha2.js");
|
|
|
3
3
|
let _scure_bip32 = require("@scure/bip32");
|
|
4
4
|
let _scure_bip39 = require("@scure/bip39");
|
|
5
5
|
let _scure_bip39_wordlists_english_js = require("@scure/bip39/wordlists/english.js");
|
|
6
|
-
let
|
|
7
|
-
|
|
6
|
+
let _noble_curves_nist_js = require("@noble/curves/nist.js");
|
|
7
|
+
let _noble_curves_utils_js = require("@noble/curves/utils.js");
|
|
8
8
|
let jose = require("jose");
|
|
9
9
|
jose = require_rolldown_runtime.__toESM(jose, 1);
|
|
10
|
+
let _noble_hashes_hmac_js = require("@noble/hashes/hmac.js");
|
|
11
|
+
let _noble_hashes_utils_js = require("@noble/hashes/utils.js");
|
|
12
|
+
let _noble_curves_secp256k1_js = require("@noble/curves/secp256k1.js");
|
|
10
13
|
let asn1_js = require("asn1.js");
|
|
11
14
|
asn1_js = require_rolldown_runtime.__toESM(asn1_js, 1);
|
|
12
15
|
let bn_js = require("bn.js");
|
|
@@ -45,6 +48,40 @@ const getMasterSeed = async (salt) => {
|
|
|
45
48
|
return masterSeed;
|
|
46
49
|
};
|
|
47
50
|
//#endregion
|
|
51
|
+
//#region src/crypto/deterministic-key.ts
|
|
52
|
+
const CURVE_ORDER = _noble_curves_nist_js.p256.Point.Fn.ORDER;
|
|
53
|
+
const hmacSha256 = (key, ...messages) => (0, _noble_hashes_hmac_js.hmac)(_noble_hashes_sha2_js.sha256, key, (0, _noble_curves_utils_js.concatBytes)(...messages));
|
|
54
|
+
const drbg = (0, _noble_curves_utils_js.createHmacDrbg)(32, 32, hmacSha256);
|
|
55
|
+
/**
|
|
56
|
+
* Derive a secp256r1 secret key from `entropy`, as a hex string.
|
|
57
|
+
*
|
|
58
|
+
* This reproduces byte-for-byte what `elliptic`'s `ec.genKeyPair({ entropy })` used to return,
|
|
59
|
+
* down to the unpadded hex encoding of `BN.toString(16, 2)`. The derivation is load-bearing:
|
|
60
|
+
* API users already provisioned in HSMs and baked workspaces are identified by keys derived
|
|
61
|
+
* from it, so any change here would orphan them. Pinned by golden vectors in
|
|
62
|
+
* `__tests__/crypto/utils.test.ts`.
|
|
63
|
+
*/
|
|
64
|
+
const deriveDeterministicSecretHex = (entropy) => {
|
|
65
|
+
const seed = (0, _noble_curves_utils_js.concatBytes)((0, _noble_hashes_sha2_js.sha256)((0, _noble_hashes_utils_js.utf8ToBytes)(entropy)), (0, _noble_curves_utils_js.numberToBytesBE)(CURVE_ORDER, 32));
|
|
66
|
+
const hex = drbg(seed, (bytes) => {
|
|
67
|
+
const candidate = (0, _noble_curves_utils_js.bytesToNumberBE)(bytes);
|
|
68
|
+
/* v8 ignore next -- @preserve: rejection sampling, unreachable in practice */
|
|
69
|
+
if (candidate > CURVE_ORDER - 2n) return void 0;
|
|
70
|
+
return candidate + 1n;
|
|
71
|
+
}).toString(16);
|
|
72
|
+
return hex.length % 2 === 0 ? hex : `0${hex}`;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Pad a secret key hex to the 32 bytes the curve API requires.
|
|
76
|
+
*
|
|
77
|
+
* Rejects anything that is not hex. `elliptic` used to accept such input and silently derive a
|
|
78
|
+
* public key from garbage.
|
|
79
|
+
*/
|
|
80
|
+
const secretHexToBytes = (hex) => {
|
|
81
|
+
if (!/^[0-9a-fA-F]{1,64}$/.test(hex)) throw new Error("private key must be a hex string of at most 32 bytes");
|
|
82
|
+
return (0, _noble_curves_utils_js.numberToBytesBE)(BigInt(`0x${hex}`), 32);
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
48
85
|
//#region src/crypto/key-encoder.ts
|
|
49
86
|
const ECPrivateKeyASN = asn1_js.default.define("ECPrivateKey", function() {
|
|
50
87
|
const self = this;
|
|
@@ -73,7 +110,7 @@ const curves = {
|
|
|
73
110
|
],
|
|
74
111
|
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
75
112
|
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
76
|
-
curve:
|
|
113
|
+
curve: _noble_curves_secp256k1_js.secp256k1
|
|
77
114
|
},
|
|
78
115
|
p256: {
|
|
79
116
|
curveParameters: [
|
|
@@ -87,7 +124,7 @@ const curves = {
|
|
|
87
124
|
],
|
|
88
125
|
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
89
126
|
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
90
|
-
curve:
|
|
127
|
+
curve: _noble_curves_nist_js.p256
|
|
91
128
|
}
|
|
92
129
|
};
|
|
93
130
|
var KeyEncoder = class {
|
|
@@ -151,7 +188,7 @@ var KeyEncoder = class {
|
|
|
151
188
|
switch (originalFormat) {
|
|
152
189
|
case "raw": {
|
|
153
190
|
if (typeof privateKey !== "string") throw new Error("private key must be a string");
|
|
154
|
-
const rawPublicKey = this.options.curve.
|
|
191
|
+
const rawPublicKey = (0, _noble_curves_utils_js.bytesToHex)(this.options.curve.getPublicKey(secretHexToBytes(privateKey), false));
|
|
155
192
|
privateKeyObject = this.privateKeyObject(privateKey, rawPublicKey);
|
|
156
193
|
break;
|
|
157
194
|
}
|
|
@@ -235,13 +272,12 @@ function hexToPem(hexString, { isPrivate = true } = {}) {
|
|
|
235
272
|
*/
|
|
236
273
|
function genKeys(entropy) {
|
|
237
274
|
if (entropy) {
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
const keyPair = ec.genKeyPair({ entropy: Buffer.from(hashedEntropy, "hex") });
|
|
275
|
+
const secretHex = deriveDeterministicSecretHex(entropy);
|
|
276
|
+
const publicHex = (0, _noble_curves_utils_js.bytesToHex)(_noble_curves_nist_js.p256.getPublicKey(secretHexToBytes(secretHex), false));
|
|
241
277
|
return {
|
|
242
|
-
privateKey: String(hexToPem(
|
|
243
|
-
publicKey: String(hexToPem(
|
|
244
|
-
hexPubKey: extractPublicKey(String(hexToPem(
|
|
278
|
+
privateKey: String(hexToPem(secretHex)),
|
|
279
|
+
publicKey: String(hexToPem(publicHex, { isPrivate: false })),
|
|
280
|
+
hexPubKey: extractPublicKey(String(hexToPem(publicHex, { isPrivate: false })))
|
|
245
281
|
};
|
|
246
282
|
}
|
|
247
283
|
const { publicKey, privateKey } = node_crypto.default.generateKeyPairSync("ec", {
|
|
@@ -295,4 +331,4 @@ Object.defineProperty(exports, "sign", {
|
|
|
295
331
|
}
|
|
296
332
|
});
|
|
297
333
|
|
|
298
|
-
//# sourceMappingURL=crypto-
|
|
334
|
+
//# sourceMappingURL=crypto-CKLQSwr3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-CKLQSwr3.cjs","names":["sha256","entropyToMnemonic","wordlist","mnemonicToSeed","HDKey","p256","hmac","sha256","concatBytes","createHmacDrbg","utf8ToBytes","numberToBytesBE","bytesToNumberBE","asn1","secp256k1","p256","BN","bytesToHex","bytesToHex","p256","crypto"],"sources":["../src/crypto/gen-seed.ts","../src/crypto/deterministic-key.ts","../src/crypto/key-encoder.ts","../src/crypto/utils.ts"],"sourcesContent":["import { sha256 } from \"@noble/hashes/sha2.js\";\nimport { HDKey } from \"@scure/bip32\";\nimport { entropyToMnemonic, mnemonicToSeed } from \"@scure/bip39\";\nimport { wordlist } from \"@scure/bip39/wordlists/english.js\";\n\n/**\n * Generate a deterministic BIP39 mnemonic from a salt and device index.\n *\n * Produces `entropyToMnemonic(SHA256(salt + \"_\" + index))`, matching\n * the behavior of `@ledgerhq/vault-common`'s `genSeed`.\n *\n * @param salt The workspace salt\n * @param index The device index (1-based)\n * @returns A 24-word BIP39 mnemonic string\n */\nexport function genSeed(salt: string, index: number): string {\n const input = new TextEncoder().encode(`${salt}_${index}`);\n const entropy = sha256(input);\n return entropyToMnemonic(entropy, wordlist);\n}\n\nconst getSeedFragment = async (salt: string, index: number): Promise<Uint8Array> => {\n const seed = await mnemonicToSeed(genSeed(salt, index));\n const secpKey = HDKey.fromMasterSeed(seed);\n const fragment = secpKey.derive(\"m/5655636'/4932953'\");\n return Buffer.concat([fragment.privateKey!, fragment.chainCode!]);\n};\n\nexport const getMasterSeed = async (salt: string): Promise<Uint8Array> => {\n const fragments = await Promise.all([\n getSeedFragment(salt, 7),\n getSeedFragment(salt, 8),\n getSeedFragment(salt, 9),\n ]);\n\n const masterSeed = new Uint8Array(fragments[0].length);\n for (let i = 0; i < fragments[0].length; i++) {\n masterSeed[i] = fragments[0][i]! ^ fragments[1][i]! ^ fragments[2][i]!;\n }\n\n return masterSeed;\n};\n","import { p256 } from \"@noble/curves/nist.js\";\nimport {\n bytesToNumberBE,\n concatBytes,\n createHmacDrbg,\n numberToBytesBE,\n} from \"@noble/curves/utils.js\";\nimport { hmac } from \"@noble/hashes/hmac.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { utf8ToBytes } from \"@noble/hashes/utils.js\";\n\nconst CURVE_ORDER = p256.Point.Fn.ORDER;\n\nconst hmacSha256 = (key: Uint8Array, ...messages: Uint8Array[]): Uint8Array =>\n hmac(sha256, key, concatBytes(...messages));\n\nconst drbg = createHmacDrbg<bigint>(32, 32, hmacSha256);\n\n/**\n * Derive a secp256r1 secret key from `entropy`, as a hex string.\n *\n * This reproduces byte-for-byte what `elliptic`'s `ec.genKeyPair({ entropy })` used to return,\n * down to the unpadded hex encoding of `BN.toString(16, 2)`. The derivation is load-bearing:\n * API users already provisioned in HSMs and baked workspaces are identified by keys derived\n * from it, so any change here would orphan them. Pinned by golden vectors in\n * `__tests__/crypto/utils.test.ts`.\n */\nexport const deriveDeterministicSecretHex = (entropy: string): string => {\n const seed = concatBytes(sha256(utf8ToBytes(entropy)), numberToBytesBE(CURVE_ORDER, 32));\n const secret = drbg(seed, (bytes) => {\n const candidate = bytesToNumberBE(bytes);\n /* v8 ignore next -- @preserve: rejection sampling, unreachable in practice */\n if (candidate > CURVE_ORDER - 2n) return undefined;\n return candidate + 1n;\n });\n const hex = secret.toString(16);\n return hex.length % 2 === 0 ? hex : `0${hex}`;\n};\n\n/**\n * Pad a secret key hex to the 32 bytes the curve API requires.\n *\n * Rejects anything that is not hex. `elliptic` used to accept such input and silently derive a\n * public key from garbage.\n */\nexport const secretHexToBytes = (hex: string): Uint8Array => {\n if (!/^[0-9a-fA-F]{1,64}$/.test(hex)) {\n throw new Error(\"private key must be a hex string of at most 32 bytes\");\n }\n return numberToBytesBE(BigInt(`0x${hex}`), 32);\n};\n","// ========================================================================== //\n// //\n// DISCLAIMER //\n// //\n// This code has been blindly copy-pasted from: //\n// https://github.com/LedgerHQ/pkey-ts //\n// //\n// ========================================================================== //\nimport { p256 } from \"@noble/curves/nist.js\";\nimport { secp256k1 } from \"@noble/curves/secp256k1.js\";\nimport { bytesToHex } from \"@noble/curves/utils.js\";\n// @ts-expect-error this library does not ship types\nimport asn1 from \"asn1.js\";\nimport BN from \"bn.js\";\n\nimport { secretHexToBytes } from \"./deterministic-key\";\n\n/* cspell:disable */\nconst ECPrivateKeyASN = asn1.define(\"ECPrivateKey\", function () {\n // @ts-expect-error pure black box\n // biome-ignore lint/suspicious/noExplicitAny: black box\n const self = this as any;\n self\n .seq()\n .obj(\n self.key(\"version\").int(),\n self.key(\"privateKey\").octstr(),\n self.key(\"parameters\").explicit(0).objid().optional(),\n self.key(\"publicKey\").explicit(1).bitstr().optional(),\n );\n});\n\nconst ECPrivateKey8ASN = asn1.define(\n \"ECPrivateKey\",\n /* v8 ignore next -- @preserve */\n function () {\n // @ts-expect-error pure black box\n // biome-ignore lint/suspicious/noExplicitAny: black box\n const self = this as any;\n self\n .seq()\n .obj(\n self.key(\"version\").int(),\n self\n .key(\"privateKeyAlgorithm\")\n .seq()\n .obj(self.key(\"ecPublicKey\").objid(), self.key(\"curve\").objid()),\n self.key(\"privateKey\").octstr().contains(ECPrivateKeyASN),\n self.key(\"attributes\").explicit(0).bitstr().optional(),\n );\n },\n);\n\nconst SubjectPublicKeyInfoASN = asn1.define(\"SubjectPublicKeyInfo\", function () {\n // @ts-expect-error pure black box\n // biome-ignore lint/suspicious/noExplicitAny: black box\n const self = this as any;\n self\n .seq()\n .obj(\n self.key(\"algorithm\").seq().obj(self.key(\"id\").objid(), self.key(\"curve\").objid()),\n self.key(\"pub\").bitstr(),\n );\n});\n\ntype CurveOptions = {\n curveParameters: number[];\n privatePEMOptions: { label: string };\n publicPEMOptions: { label: string };\n curve: { getPublicKey: (secretKey: Uint8Array, isCompressed?: boolean) => Uint8Array };\n};\n\nconst curves: Record<string, CurveOptions> = {\n secp256k1: {\n curveParameters: [1, 3, 132, 0, 10],\n privatePEMOptions: { label: \"EC PRIVATE KEY\" },\n publicPEMOptions: { label: \"PUBLIC KEY\" },\n curve: secp256k1,\n },\n p256: {\n curveParameters: [1, 2, 840, 10045, 3, 1, 7], // OID for p256 curve\n privatePEMOptions: { label: \"EC PRIVATE KEY\" },\n publicPEMOptions: { label: \"PUBLIC KEY\" },\n curve: p256,\n },\n};\n\ntype PrivateKeyPKCS1 = {\n version: BN;\n privateKey: Buffer;\n parameters: number[];\n publicKey?: {\n unused: number;\n data: Buffer;\n };\n};\n\ntype PrivateKeyPKCS8 = {\n version: BN;\n privateKey: PrivateKeyPKCS1;\n privateKeyAlgorithm: { ecPublicKey: number[]; curve: number[] };\n};\n\nexport type KeyFormat = \"raw\" | \"pem\" | \"der\";\n\nexport class KeyEncoder {\n algorithmID: number[];\n options: CurveOptions;\n\n constructor(options: string | CurveOptions) {\n /* v8 ignore else -- @preserve */\n if (typeof options === \"string\") {\n /* v8 ignore if -- @preserve */\n if (options !== \"secp256k1\" && options !== \"p256\") {\n throw new Error(`Unknown curve ${options}`);\n }\n options = curves[options]!;\n }\n this.options = options;\n this.algorithmID = [1, 2, 840, 10045, 2, 1];\n }\n\n /* v8 ignore next -- @preserve */\n private PKCS1toPKCS8(privateKey: PrivateKeyPKCS1): PrivateKeyPKCS8 {\n return {\n version: new BN(0),\n privateKey,\n privateKeyAlgorithm: {\n ecPublicKey: this.algorithmID,\n curve: privateKey.parameters,\n },\n };\n }\n\n privateKeyObject(rawPrivateKey: string, rawPublicKey: string): PrivateKeyPKCS1 {\n const privateKeyObject: PrivateKeyPKCS1 = {\n version: new BN(1),\n privateKey: Buffer.from(rawPrivateKey, \"hex\"),\n parameters: this.options.curveParameters,\n };\n\n /* v8 ignore else -- @preserve */\n if (rawPublicKey) {\n privateKeyObject.publicKey = {\n unused: 0,\n data: Buffer.from(rawPublicKey, \"hex\"),\n };\n }\n\n return privateKeyObject;\n }\n\n publicKeyObject(rawPublicKey: string): {\n algorithm: { id: number[]; curve: number[] };\n pub: { unused: number; data: Buffer };\n } {\n return {\n algorithm: {\n id: this.algorithmID,\n curve: this.options.curveParameters,\n },\n pub: {\n unused: 0,\n data: Buffer.from(rawPublicKey, \"hex\"),\n },\n };\n }\n\n encodePrivate(\n privateKey: string | Buffer,\n originalFormat: KeyFormat,\n destinationFormat: KeyFormat,\n destinationFormatType: \"pkcs8\" | \"pkcs1\" = \"pkcs1\",\n ): string {\n let privateKeyObject: PrivateKeyPKCS1;\n\n /* Parse the incoming private key and convert it to a private key object */\n switch (originalFormat) {\n case \"raw\": {\n if (typeof privateKey !== \"string\") {\n throw new Error(\"private key must be a string\");\n }\n const rawPublicKey = bytesToHex(\n this.options.curve.getPublicKey(secretHexToBytes(privateKey), false),\n );\n privateKeyObject = this.privateKeyObject(privateKey, rawPublicKey);\n break;\n }\n /* v8 ignore next -- @preserve */\n case \"der\":\n if (typeof privateKey === \"string\") {\n privateKey = Buffer.from(privateKey, \"hex\");\n }\n privateKeyObject = ECPrivateKeyASN.decode(privateKey, \"der\");\n break;\n case \"pem\":\n if (typeof privateKey !== \"string\") {\n throw new Error(\"private key must be a string\");\n }\n privateKeyObject = ECPrivateKeyASN.decode(\n privateKey,\n \"pem\",\n this.options.privatePEMOptions,\n );\n break;\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid private key format\");\n }\n\n /* Export the private key object to the desired format */\n switch (destinationFormat) {\n case \"raw\":\n if (destinationFormatType === \"pkcs1\") {\n return privateKeyObject.privateKey.toString(\"hex\");\n } else if (destinationFormatType === \"pkcs8\") {\n return this.PKCS1toPKCS8(privateKeyObject).privateKey.privateKey.toString(\"hex\");\n }\n break;\n case \"der\":\n if (destinationFormatType === \"pkcs1\") {\n return ECPrivateKeyASN.encode(privateKeyObject, \"der\").toString(\"hex\");\n } else if (destinationFormatType === \"pkcs8\") {\n return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), \"der\").toString(\n \"hex\",\n );\n }\n break;\n case \"pem\":\n if (destinationFormatType === \"pkcs1\") {\n return ECPrivateKeyASN.encode(privateKeyObject, \"pem\", this.options.privatePEMOptions);\n } else if (destinationFormatType === \"pkcs8\") {\n return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), \"pem\", {\n ...this.options.privatePEMOptions,\n label: \"PRIVATE KEY\",\n });\n }\n break;\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid destination format for private key\");\n }\n\n throw new Error(\"unsupported destination format or type\");\n }\n\n encodePublic(\n publicKey: string | Buffer,\n originalFormat: KeyFormat,\n destinationFormat: KeyFormat,\n ): string {\n // biome-ignore lint/suspicious/noImplicitAnyLet: melting pot object\n let publicKeyObject;\n\n switch (originalFormat) {\n case \"raw\":\n if (typeof publicKey !== \"string\") {\n throw new Error(\"public key must be a string\");\n }\n publicKeyObject = this.publicKeyObject(publicKey);\n break;\n /* v8 ignore next -- @preserve */\n case \"der\":\n if (typeof publicKey === \"string\") {\n publicKey = Buffer.from(publicKey, \"hex\");\n }\n publicKeyObject = SubjectPublicKeyInfoASN.decode(publicKey, \"der\");\n break;\n case \"pem\":\n if (typeof publicKey !== \"string\") {\n throw new Error(\"public key must be a string\");\n }\n publicKeyObject = SubjectPublicKeyInfoASN.decode(\n publicKey,\n \"pem\",\n this.options.publicPEMOptions,\n );\n break;\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid public key format\");\n }\n\n /* Export the private key object to the desired format */\n switch (destinationFormat) {\n case \"raw\":\n return publicKeyObject.pub.data.toString(\"hex\");\n case \"der\":\n return SubjectPublicKeyInfoASN.encode(publicKeyObject, \"der\").toString(\"hex\");\n case \"pem\":\n return SubjectPublicKeyInfoASN.encode(\n publicKeyObject,\n \"pem\",\n this.options.publicPEMOptions,\n );\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid destination format for public key\");\n }\n }\n}\n/* cspell:enable */\n","import { p256 } from \"@noble/curves/nist.js\";\nimport { bytesToHex } from \"@noble/curves/utils.js\";\nimport * as jose from \"jose\";\n\nimport { deriveDeterministicSecretHex, secretHexToBytes } from \"./deterministic-key\";\nimport { KeyEncoder } from \"./key-encoder\";\nimport type { GeneratedKeys } from \"./types\";\nimport crypto from \"node:crypto\";\n\nfunction extractPublicKey(pemKey: string): string {\n // convert the PEM formatted public key to raw public key in X9.62 uncompressed format\n // this is an oversimplified method and may not work with different curves or PEM formats\n const pem = pemKey.split(\"\\n\");\n pem.shift(); // remove the first line (BEGIN PUBLIC KEY)\n pem.pop(); // remove the last line (END PUBLIC KEY)\n // convert base64 to buffer\n const keyBuffer = Buffer.from(pem.join(\"\"), \"base64\");\n // assuming the first 26 bytes are the header for the SPKI formatted key.\n // the actual key should begin after this header.\n const actualKeyBuffer = keyBuffer.slice(26);\n return actualKeyBuffer.toString(\"hex\").toUpperCase();\n}\n\nfunction hexToPem(hexString: string, { isPrivate = true } = {}): string {\n const keyEncoder = new KeyEncoder(\"p256\");\n if (isPrivate) {\n return keyEncoder.encodePrivate(hexString, \"raw\", \"pem\");\n }\n return keyEncoder.encodePublic(hexString, \"raw\", \"pem\");\n}\n\n/**\n * If `entropy` is passed, will generate keys pair deterministically\n * else, random keys pair generated\n */\nexport function genKeys(entropy?: string): GeneratedKeys {\n if (entropy) {\n const secretHex = deriveDeterministicSecretHex(entropy);\n const publicHex = bytesToHex(p256.getPublicKey(secretHexToBytes(secretHex), false));\n return {\n privateKey: String(hexToPem(secretHex)),\n publicKey: String(hexToPem(publicHex, { isPrivate: false })),\n hexPubKey: extractPublicKey(String(hexToPem(publicHex, { isPrivate: false }))),\n };\n }\n const { publicKey, privateKey } = crypto.generateKeyPairSync(\"ec\", {\n namedCurve: \"P-256\",\n publicKeyEncoding: { type: \"spki\", format: \"pem\" },\n privateKeyEncoding: { type: \"sec1\", format: \"pem\" },\n });\n const hexPubKey = extractPublicKey(publicKey);\n return {\n privateKey,\n publicKey,\n hexPubKey,\n };\n}\n\nexport const sign = async (privateKeyPem: string, base64Challenge: string): Promise<string> => {\n // Decode base64url challenge to bytes\n const challengeDataBytes = jose.base64url.decode(base64Challenge);\n\n // For EC private key format, we need to use a different import method\n // Since jose doesn't support SEC1 format directly, let's use Node.js crypto\n // Create a KeyObject from the EC private key\n const privateKey = crypto.createPrivateKey(privateKeyPem);\n\n // Use jose with the KeyObject\n return new jose.CompactSign(challengeDataBytes)\n .setProtectedHeader({ alg: \"ES256\", typ: \"JWT\" })\n .sign(privateKey);\n};\n"],"mappings":"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"}
|
|
@@ -2,8 +2,12 @@ import { sha256 } from "@noble/hashes/sha2.js";
|
|
|
2
2
|
import { HDKey } from "@scure/bip32";
|
|
3
3
|
import { entropyToMnemonic, mnemonicToSeed } from "@scure/bip39";
|
|
4
4
|
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
5
|
-
import
|
|
5
|
+
import { p256 } from "@noble/curves/nist.js";
|
|
6
|
+
import { bytesToHex, bytesToNumberBE, concatBytes, createHmacDrbg, numberToBytesBE } from "@noble/curves/utils.js";
|
|
6
7
|
import * as jose from "jose";
|
|
8
|
+
import { hmac } from "@noble/hashes/hmac.js";
|
|
9
|
+
import { utf8ToBytes } from "@noble/hashes/utils.js";
|
|
10
|
+
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
7
11
|
import asn1 from "asn1.js";
|
|
8
12
|
import BN from "bn.js";
|
|
9
13
|
import crypto from "node:crypto";
|
|
@@ -39,6 +43,40 @@ const getMasterSeed = async (salt) => {
|
|
|
39
43
|
return masterSeed;
|
|
40
44
|
};
|
|
41
45
|
//#endregion
|
|
46
|
+
//#region src/crypto/deterministic-key.ts
|
|
47
|
+
const CURVE_ORDER = p256.Point.Fn.ORDER;
|
|
48
|
+
const hmacSha256 = (key, ...messages) => hmac(sha256, key, concatBytes(...messages));
|
|
49
|
+
const drbg = createHmacDrbg(32, 32, hmacSha256);
|
|
50
|
+
/**
|
|
51
|
+
* Derive a secp256r1 secret key from `entropy`, as a hex string.
|
|
52
|
+
*
|
|
53
|
+
* This reproduces byte-for-byte what `elliptic`'s `ec.genKeyPair({ entropy })` used to return,
|
|
54
|
+
* down to the unpadded hex encoding of `BN.toString(16, 2)`. The derivation is load-bearing:
|
|
55
|
+
* API users already provisioned in HSMs and baked workspaces are identified by keys derived
|
|
56
|
+
* from it, so any change here would orphan them. Pinned by golden vectors in
|
|
57
|
+
* `__tests__/crypto/utils.test.ts`.
|
|
58
|
+
*/
|
|
59
|
+
const deriveDeterministicSecretHex = (entropy) => {
|
|
60
|
+
const seed = concatBytes(sha256(utf8ToBytes(entropy)), numberToBytesBE(CURVE_ORDER, 32));
|
|
61
|
+
const hex = drbg(seed, (bytes) => {
|
|
62
|
+
const candidate = bytesToNumberBE(bytes);
|
|
63
|
+
/* v8 ignore next -- @preserve: rejection sampling, unreachable in practice */
|
|
64
|
+
if (candidate > CURVE_ORDER - 2n) return void 0;
|
|
65
|
+
return candidate + 1n;
|
|
66
|
+
}).toString(16);
|
|
67
|
+
return hex.length % 2 === 0 ? hex : `0${hex}`;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Pad a secret key hex to the 32 bytes the curve API requires.
|
|
71
|
+
*
|
|
72
|
+
* Rejects anything that is not hex. `elliptic` used to accept such input and silently derive a
|
|
73
|
+
* public key from garbage.
|
|
74
|
+
*/
|
|
75
|
+
const secretHexToBytes = (hex) => {
|
|
76
|
+
if (!/^[0-9a-fA-F]{1,64}$/.test(hex)) throw new Error("private key must be a hex string of at most 32 bytes");
|
|
77
|
+
return numberToBytesBE(BigInt(`0x${hex}`), 32);
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
42
80
|
//#region src/crypto/key-encoder.ts
|
|
43
81
|
const ECPrivateKeyASN = asn1.define("ECPrivateKey", function() {
|
|
44
82
|
const self = this;
|
|
@@ -67,7 +105,7 @@ const curves = {
|
|
|
67
105
|
],
|
|
68
106
|
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
69
107
|
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
70
|
-
curve:
|
|
108
|
+
curve: secp256k1
|
|
71
109
|
},
|
|
72
110
|
p256: {
|
|
73
111
|
curveParameters: [
|
|
@@ -81,7 +119,7 @@ const curves = {
|
|
|
81
119
|
],
|
|
82
120
|
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
83
121
|
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
84
|
-
curve:
|
|
122
|
+
curve: p256
|
|
85
123
|
}
|
|
86
124
|
};
|
|
87
125
|
var KeyEncoder = class {
|
|
@@ -145,7 +183,7 @@ var KeyEncoder = class {
|
|
|
145
183
|
switch (originalFormat) {
|
|
146
184
|
case "raw": {
|
|
147
185
|
if (typeof privateKey !== "string") throw new Error("private key must be a string");
|
|
148
|
-
const rawPublicKey = this.options.curve.
|
|
186
|
+
const rawPublicKey = bytesToHex(this.options.curve.getPublicKey(secretHexToBytes(privateKey), false));
|
|
149
187
|
privateKeyObject = this.privateKeyObject(privateKey, rawPublicKey);
|
|
150
188
|
break;
|
|
151
189
|
}
|
|
@@ -229,13 +267,12 @@ function hexToPem(hexString, { isPrivate = true } = {}) {
|
|
|
229
267
|
*/
|
|
230
268
|
function genKeys(entropy) {
|
|
231
269
|
if (entropy) {
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
const keyPair = ec.genKeyPair({ entropy: Buffer.from(hashedEntropy, "hex") });
|
|
270
|
+
const secretHex = deriveDeterministicSecretHex(entropy);
|
|
271
|
+
const publicHex = bytesToHex(p256.getPublicKey(secretHexToBytes(secretHex), false));
|
|
235
272
|
return {
|
|
236
|
-
privateKey: String(hexToPem(
|
|
237
|
-
publicKey: String(hexToPem(
|
|
238
|
-
hexPubKey: extractPublicKey(String(hexToPem(
|
|
273
|
+
privateKey: String(hexToPem(secretHex)),
|
|
274
|
+
publicKey: String(hexToPem(publicHex, { isPrivate: false })),
|
|
275
|
+
hexPubKey: extractPublicKey(String(hexToPem(publicHex, { isPrivate: false })))
|
|
239
276
|
};
|
|
240
277
|
}
|
|
241
278
|
const { publicKey, privateKey } = crypto.generateKeyPairSync("ec", {
|
|
@@ -266,4 +303,4 @@ const sign = async (privateKeyPem, base64Challenge) => {
|
|
|
266
303
|
//#endregion
|
|
267
304
|
export { getMasterSeed as i, sign as n, genSeed as r, genKeys as t };
|
|
268
305
|
|
|
269
|
-
//# sourceMappingURL=crypto-
|
|
306
|
+
//# sourceMappingURL=crypto-hrnmToQa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-hrnmToQa.js","names":[],"sources":["../src/crypto/gen-seed.ts","../src/crypto/deterministic-key.ts","../src/crypto/key-encoder.ts","../src/crypto/utils.ts"],"sourcesContent":["import { sha256 } from \"@noble/hashes/sha2.js\";\nimport { HDKey } from \"@scure/bip32\";\nimport { entropyToMnemonic, mnemonicToSeed } from \"@scure/bip39\";\nimport { wordlist } from \"@scure/bip39/wordlists/english.js\";\n\n/**\n * Generate a deterministic BIP39 mnemonic from a salt and device index.\n *\n * Produces `entropyToMnemonic(SHA256(salt + \"_\" + index))`, matching\n * the behavior of `@ledgerhq/vault-common`'s `genSeed`.\n *\n * @param salt The workspace salt\n * @param index The device index (1-based)\n * @returns A 24-word BIP39 mnemonic string\n */\nexport function genSeed(salt: string, index: number): string {\n const input = new TextEncoder().encode(`${salt}_${index}`);\n const entropy = sha256(input);\n return entropyToMnemonic(entropy, wordlist);\n}\n\nconst getSeedFragment = async (salt: string, index: number): Promise<Uint8Array> => {\n const seed = await mnemonicToSeed(genSeed(salt, index));\n const secpKey = HDKey.fromMasterSeed(seed);\n const fragment = secpKey.derive(\"m/5655636'/4932953'\");\n return Buffer.concat([fragment.privateKey!, fragment.chainCode!]);\n};\n\nexport const getMasterSeed = async (salt: string): Promise<Uint8Array> => {\n const fragments = await Promise.all([\n getSeedFragment(salt, 7),\n getSeedFragment(salt, 8),\n getSeedFragment(salt, 9),\n ]);\n\n const masterSeed = new Uint8Array(fragments[0].length);\n for (let i = 0; i < fragments[0].length; i++) {\n masterSeed[i] = fragments[0][i]! ^ fragments[1][i]! ^ fragments[2][i]!;\n }\n\n return masterSeed;\n};\n","import { p256 } from \"@noble/curves/nist.js\";\nimport {\n bytesToNumberBE,\n concatBytes,\n createHmacDrbg,\n numberToBytesBE,\n} from \"@noble/curves/utils.js\";\nimport { hmac } from \"@noble/hashes/hmac.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { utf8ToBytes } from \"@noble/hashes/utils.js\";\n\nconst CURVE_ORDER = p256.Point.Fn.ORDER;\n\nconst hmacSha256 = (key: Uint8Array, ...messages: Uint8Array[]): Uint8Array =>\n hmac(sha256, key, concatBytes(...messages));\n\nconst drbg = createHmacDrbg<bigint>(32, 32, hmacSha256);\n\n/**\n * Derive a secp256r1 secret key from `entropy`, as a hex string.\n *\n * This reproduces byte-for-byte what `elliptic`'s `ec.genKeyPair({ entropy })` used to return,\n * down to the unpadded hex encoding of `BN.toString(16, 2)`. The derivation is load-bearing:\n * API users already provisioned in HSMs and baked workspaces are identified by keys derived\n * from it, so any change here would orphan them. Pinned by golden vectors in\n * `__tests__/crypto/utils.test.ts`.\n */\nexport const deriveDeterministicSecretHex = (entropy: string): string => {\n const seed = concatBytes(sha256(utf8ToBytes(entropy)), numberToBytesBE(CURVE_ORDER, 32));\n const secret = drbg(seed, (bytes) => {\n const candidate = bytesToNumberBE(bytes);\n /* v8 ignore next -- @preserve: rejection sampling, unreachable in practice */\n if (candidate > CURVE_ORDER - 2n) return undefined;\n return candidate + 1n;\n });\n const hex = secret.toString(16);\n return hex.length % 2 === 0 ? hex : `0${hex}`;\n};\n\n/**\n * Pad a secret key hex to the 32 bytes the curve API requires.\n *\n * Rejects anything that is not hex. `elliptic` used to accept such input and silently derive a\n * public key from garbage.\n */\nexport const secretHexToBytes = (hex: string): Uint8Array => {\n if (!/^[0-9a-fA-F]{1,64}$/.test(hex)) {\n throw new Error(\"private key must be a hex string of at most 32 bytes\");\n }\n return numberToBytesBE(BigInt(`0x${hex}`), 32);\n};\n","// ========================================================================== //\n// //\n// DISCLAIMER //\n// //\n// This code has been blindly copy-pasted from: //\n// https://github.com/LedgerHQ/pkey-ts //\n// //\n// ========================================================================== //\nimport { p256 } from \"@noble/curves/nist.js\";\nimport { secp256k1 } from \"@noble/curves/secp256k1.js\";\nimport { bytesToHex } from \"@noble/curves/utils.js\";\n// @ts-expect-error this library does not ship types\nimport asn1 from \"asn1.js\";\nimport BN from \"bn.js\";\n\nimport { secretHexToBytes } from \"./deterministic-key\";\n\n/* cspell:disable */\nconst ECPrivateKeyASN = asn1.define(\"ECPrivateKey\", function () {\n // @ts-expect-error pure black box\n // biome-ignore lint/suspicious/noExplicitAny: black box\n const self = this as any;\n self\n .seq()\n .obj(\n self.key(\"version\").int(),\n self.key(\"privateKey\").octstr(),\n self.key(\"parameters\").explicit(0).objid().optional(),\n self.key(\"publicKey\").explicit(1).bitstr().optional(),\n );\n});\n\nconst ECPrivateKey8ASN = asn1.define(\n \"ECPrivateKey\",\n /* v8 ignore next -- @preserve */\n function () {\n // @ts-expect-error pure black box\n // biome-ignore lint/suspicious/noExplicitAny: black box\n const self = this as any;\n self\n .seq()\n .obj(\n self.key(\"version\").int(),\n self\n .key(\"privateKeyAlgorithm\")\n .seq()\n .obj(self.key(\"ecPublicKey\").objid(), self.key(\"curve\").objid()),\n self.key(\"privateKey\").octstr().contains(ECPrivateKeyASN),\n self.key(\"attributes\").explicit(0).bitstr().optional(),\n );\n },\n);\n\nconst SubjectPublicKeyInfoASN = asn1.define(\"SubjectPublicKeyInfo\", function () {\n // @ts-expect-error pure black box\n // biome-ignore lint/suspicious/noExplicitAny: black box\n const self = this as any;\n self\n .seq()\n .obj(\n self.key(\"algorithm\").seq().obj(self.key(\"id\").objid(), self.key(\"curve\").objid()),\n self.key(\"pub\").bitstr(),\n );\n});\n\ntype CurveOptions = {\n curveParameters: number[];\n privatePEMOptions: { label: string };\n publicPEMOptions: { label: string };\n curve: { getPublicKey: (secretKey: Uint8Array, isCompressed?: boolean) => Uint8Array };\n};\n\nconst curves: Record<string, CurveOptions> = {\n secp256k1: {\n curveParameters: [1, 3, 132, 0, 10],\n privatePEMOptions: { label: \"EC PRIVATE KEY\" },\n publicPEMOptions: { label: \"PUBLIC KEY\" },\n curve: secp256k1,\n },\n p256: {\n curveParameters: [1, 2, 840, 10045, 3, 1, 7], // OID for p256 curve\n privatePEMOptions: { label: \"EC PRIVATE KEY\" },\n publicPEMOptions: { label: \"PUBLIC KEY\" },\n curve: p256,\n },\n};\n\ntype PrivateKeyPKCS1 = {\n version: BN;\n privateKey: Buffer;\n parameters: number[];\n publicKey?: {\n unused: number;\n data: Buffer;\n };\n};\n\ntype PrivateKeyPKCS8 = {\n version: BN;\n privateKey: PrivateKeyPKCS1;\n privateKeyAlgorithm: { ecPublicKey: number[]; curve: number[] };\n};\n\nexport type KeyFormat = \"raw\" | \"pem\" | \"der\";\n\nexport class KeyEncoder {\n algorithmID: number[];\n options: CurveOptions;\n\n constructor(options: string | CurveOptions) {\n /* v8 ignore else -- @preserve */\n if (typeof options === \"string\") {\n /* v8 ignore if -- @preserve */\n if (options !== \"secp256k1\" && options !== \"p256\") {\n throw new Error(`Unknown curve ${options}`);\n }\n options = curves[options]!;\n }\n this.options = options;\n this.algorithmID = [1, 2, 840, 10045, 2, 1];\n }\n\n /* v8 ignore next -- @preserve */\n private PKCS1toPKCS8(privateKey: PrivateKeyPKCS1): PrivateKeyPKCS8 {\n return {\n version: new BN(0),\n privateKey,\n privateKeyAlgorithm: {\n ecPublicKey: this.algorithmID,\n curve: privateKey.parameters,\n },\n };\n }\n\n privateKeyObject(rawPrivateKey: string, rawPublicKey: string): PrivateKeyPKCS1 {\n const privateKeyObject: PrivateKeyPKCS1 = {\n version: new BN(1),\n privateKey: Buffer.from(rawPrivateKey, \"hex\"),\n parameters: this.options.curveParameters,\n };\n\n /* v8 ignore else -- @preserve */\n if (rawPublicKey) {\n privateKeyObject.publicKey = {\n unused: 0,\n data: Buffer.from(rawPublicKey, \"hex\"),\n };\n }\n\n return privateKeyObject;\n }\n\n publicKeyObject(rawPublicKey: string): {\n algorithm: { id: number[]; curve: number[] };\n pub: { unused: number; data: Buffer };\n } {\n return {\n algorithm: {\n id: this.algorithmID,\n curve: this.options.curveParameters,\n },\n pub: {\n unused: 0,\n data: Buffer.from(rawPublicKey, \"hex\"),\n },\n };\n }\n\n encodePrivate(\n privateKey: string | Buffer,\n originalFormat: KeyFormat,\n destinationFormat: KeyFormat,\n destinationFormatType: \"pkcs8\" | \"pkcs1\" = \"pkcs1\",\n ): string {\n let privateKeyObject: PrivateKeyPKCS1;\n\n /* Parse the incoming private key and convert it to a private key object */\n switch (originalFormat) {\n case \"raw\": {\n if (typeof privateKey !== \"string\") {\n throw new Error(\"private key must be a string\");\n }\n const rawPublicKey = bytesToHex(\n this.options.curve.getPublicKey(secretHexToBytes(privateKey), false),\n );\n privateKeyObject = this.privateKeyObject(privateKey, rawPublicKey);\n break;\n }\n /* v8 ignore next -- @preserve */\n case \"der\":\n if (typeof privateKey === \"string\") {\n privateKey = Buffer.from(privateKey, \"hex\");\n }\n privateKeyObject = ECPrivateKeyASN.decode(privateKey, \"der\");\n break;\n case \"pem\":\n if (typeof privateKey !== \"string\") {\n throw new Error(\"private key must be a string\");\n }\n privateKeyObject = ECPrivateKeyASN.decode(\n privateKey,\n \"pem\",\n this.options.privatePEMOptions,\n );\n break;\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid private key format\");\n }\n\n /* Export the private key object to the desired format */\n switch (destinationFormat) {\n case \"raw\":\n if (destinationFormatType === \"pkcs1\") {\n return privateKeyObject.privateKey.toString(\"hex\");\n } else if (destinationFormatType === \"pkcs8\") {\n return this.PKCS1toPKCS8(privateKeyObject).privateKey.privateKey.toString(\"hex\");\n }\n break;\n case \"der\":\n if (destinationFormatType === \"pkcs1\") {\n return ECPrivateKeyASN.encode(privateKeyObject, \"der\").toString(\"hex\");\n } else if (destinationFormatType === \"pkcs8\") {\n return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), \"der\").toString(\n \"hex\",\n );\n }\n break;\n case \"pem\":\n if (destinationFormatType === \"pkcs1\") {\n return ECPrivateKeyASN.encode(privateKeyObject, \"pem\", this.options.privatePEMOptions);\n } else if (destinationFormatType === \"pkcs8\") {\n return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), \"pem\", {\n ...this.options.privatePEMOptions,\n label: \"PRIVATE KEY\",\n });\n }\n break;\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid destination format for private key\");\n }\n\n throw new Error(\"unsupported destination format or type\");\n }\n\n encodePublic(\n publicKey: string | Buffer,\n originalFormat: KeyFormat,\n destinationFormat: KeyFormat,\n ): string {\n // biome-ignore lint/suspicious/noImplicitAnyLet: melting pot object\n let publicKeyObject;\n\n switch (originalFormat) {\n case \"raw\":\n if (typeof publicKey !== \"string\") {\n throw new Error(\"public key must be a string\");\n }\n publicKeyObject = this.publicKeyObject(publicKey);\n break;\n /* v8 ignore next -- @preserve */\n case \"der\":\n if (typeof publicKey === \"string\") {\n publicKey = Buffer.from(publicKey, \"hex\");\n }\n publicKeyObject = SubjectPublicKeyInfoASN.decode(publicKey, \"der\");\n break;\n case \"pem\":\n if (typeof publicKey !== \"string\") {\n throw new Error(\"public key must be a string\");\n }\n publicKeyObject = SubjectPublicKeyInfoASN.decode(\n publicKey,\n \"pem\",\n this.options.publicPEMOptions,\n );\n break;\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid public key format\");\n }\n\n /* Export the private key object to the desired format */\n switch (destinationFormat) {\n case \"raw\":\n return publicKeyObject.pub.data.toString(\"hex\");\n case \"der\":\n return SubjectPublicKeyInfoASN.encode(publicKeyObject, \"der\").toString(\"hex\");\n case \"pem\":\n return SubjectPublicKeyInfoASN.encode(\n publicKeyObject,\n \"pem\",\n this.options.publicPEMOptions,\n );\n /* v8 ignore next -- @preserve */\n default:\n throw new Error(\"invalid destination format for public key\");\n }\n }\n}\n/* cspell:enable */\n","import { p256 } from \"@noble/curves/nist.js\";\nimport { bytesToHex } from \"@noble/curves/utils.js\";\nimport * as jose from \"jose\";\n\nimport { deriveDeterministicSecretHex, secretHexToBytes } from \"./deterministic-key\";\nimport { KeyEncoder } from \"./key-encoder\";\nimport type { GeneratedKeys } from \"./types\";\nimport crypto from \"node:crypto\";\n\nfunction extractPublicKey(pemKey: string): string {\n // convert the PEM formatted public key to raw public key in X9.62 uncompressed format\n // this is an oversimplified method and may not work with different curves or PEM formats\n const pem = pemKey.split(\"\\n\");\n pem.shift(); // remove the first line (BEGIN PUBLIC KEY)\n pem.pop(); // remove the last line (END PUBLIC KEY)\n // convert base64 to buffer\n const keyBuffer = Buffer.from(pem.join(\"\"), \"base64\");\n // assuming the first 26 bytes are the header for the SPKI formatted key.\n // the actual key should begin after this header.\n const actualKeyBuffer = keyBuffer.slice(26);\n return actualKeyBuffer.toString(\"hex\").toUpperCase();\n}\n\nfunction hexToPem(hexString: string, { isPrivate = true } = {}): string {\n const keyEncoder = new KeyEncoder(\"p256\");\n if (isPrivate) {\n return keyEncoder.encodePrivate(hexString, \"raw\", \"pem\");\n }\n return keyEncoder.encodePublic(hexString, \"raw\", \"pem\");\n}\n\n/**\n * If `entropy` is passed, will generate keys pair deterministically\n * else, random keys pair generated\n */\nexport function genKeys(entropy?: string): GeneratedKeys {\n if (entropy) {\n const secretHex = deriveDeterministicSecretHex(entropy);\n const publicHex = bytesToHex(p256.getPublicKey(secretHexToBytes(secretHex), false));\n return {\n privateKey: String(hexToPem(secretHex)),\n publicKey: String(hexToPem(publicHex, { isPrivate: false })),\n hexPubKey: extractPublicKey(String(hexToPem(publicHex, { isPrivate: false }))),\n };\n }\n const { publicKey, privateKey } = crypto.generateKeyPairSync(\"ec\", {\n namedCurve: \"P-256\",\n publicKeyEncoding: { type: \"spki\", format: \"pem\" },\n privateKeyEncoding: { type: \"sec1\", format: \"pem\" },\n });\n const hexPubKey = extractPublicKey(publicKey);\n return {\n privateKey,\n publicKey,\n hexPubKey,\n };\n}\n\nexport const sign = async (privateKeyPem: string, base64Challenge: string): Promise<string> => {\n // Decode base64url challenge to bytes\n const challengeDataBytes = jose.base64url.decode(base64Challenge);\n\n // For EC private key format, we need to use a different import method\n // Since jose doesn't support SEC1 format directly, let's use Node.js crypto\n // Create a KeyObject from the EC private key\n const privateKey = crypto.createPrivateKey(privateKeyPem);\n\n // Use jose with the KeyObject\n return new jose.CompactSign(challengeDataBytes)\n .setProtectedHeader({ alg: \"ES256\", typ: \"JWT\" })\n .sign(privateKey);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAeA,SAAgB,QAAQ,MAAc,OAAuB;CAC3D,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,GAAG,KAAK,GAAG,OAAO;CACzD,MAAM,UAAU,OAAO,KAAK;CAC5B,OAAO,kBAAkB,SAAS,QAAQ;AAC5C;AAEA,MAAM,kBAAkB,OAAO,MAAc,UAAuC;CAClF,MAAM,OAAO,MAAM,eAAe,QAAQ,MAAM,KAAK,CAAC;CAEtD,MAAM,WADU,MAAM,eAAe,IACd,CAAC,CAAC,OAAO,qBAAqB;CACrD,OAAO,OAAO,OAAO,CAAC,SAAS,YAAa,SAAS,SAAU,CAAC;AAClE;AAEA,MAAa,gBAAgB,OAAO,SAAsC;CACxE,MAAM,YAAY,MAAM,QAAQ,IAAI;EAClC,gBAAgB,MAAM,CAAC;EACvB,gBAAgB,MAAM,CAAC;EACvB,gBAAgB,MAAM,CAAC;CACzB,CAAC;CAED,MAAM,aAAa,IAAI,WAAW,UAAU,EAAE,CAAC,MAAM;CACrD,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC,QAAQ,KACvC,WAAW,KAAK,UAAU,EAAE,CAAC,KAAM,UAAU,EAAE,CAAC,KAAM,UAAU,EAAE,CAAC;CAGrE,OAAO;AACT;;;AC9BA,MAAM,cAAc,KAAK,MAAM,GAAG;AAElC,MAAM,cAAc,KAAiB,GAAG,aACtC,KAAK,QAAQ,KAAK,YAAY,GAAG,QAAQ,CAAC;AAE5C,MAAM,OAAO,eAAuB,IAAI,IAAI,UAAU;;;;;;;;;;AAWtD,MAAa,gCAAgC,YAA4B;CACvE,MAAM,OAAO,YAAY,OAAO,YAAY,OAAO,CAAC,GAAG,gBAAgB,aAAa,EAAE,CAAC;CAOvF,MAAM,MANS,KAAK,OAAO,UAAU;EACnC,MAAM,YAAY,gBAAgB,KAAK;;EAEvC,IAAI,YAAY,cAAc,IAAI,OAAO,KAAA;EACzC,OAAO,YAAY;CACrB,CACiB,CAAC,CAAC,SAAS,EAAE;CAC9B,OAAO,IAAI,SAAS,MAAM,IAAI,MAAM,IAAI;AAC1C;;;;;;;AAQA,MAAa,oBAAoB,QAA4B;CAC3D,IAAI,CAAC,sBAAsB,KAAK,GAAG,GACjC,MAAM,IAAI,MAAM,sDAAsD;CAExE,OAAO,gBAAgB,OAAO,KAAK,KAAK,GAAG,EAAE;AAC/C;;;AChCA,MAAM,kBAAkB,KAAK,OAAO,gBAAgB,WAAY;CAG9D,MAAM,OAAO;CACb,KACG,IAAI,CAAC,CACL,IACC,KAAK,IAAI,SAAS,CAAC,CAAC,IAAI,GACxB,KAAK,IAAI,YAAY,CAAC,CAAC,OAAO,GAC9B,KAAK,IAAI,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,GACpD,KAAK,IAAI,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CACtD;AACJ,CAAC;AAED,MAAM,mBAAmB,KAAK;CAC5B;;CAEA,WAAY;EAGV,MAAM,OAAO;EACb,KACG,IAAI,CAAC,CACL,IACC,KAAK,IAAI,SAAS,CAAC,CAAC,IAAI,GACxB,KACG,IAAI,qBAAqB,CAAC,CAC1B,IAAI,CAAC,CACL,IAAI,KAAK,IAAI,aAAa,CAAC,CAAC,MAAM,GAAG,KAAK,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,GACjE,KAAK,IAAI,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,eAAe,GACxD,KAAK,IAAI,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CACvD;CACJ;AACF;AAEA,MAAM,0BAA0B,KAAK,OAAO,wBAAwB,WAAY;CAG9E,MAAM,OAAO;CACb,KACG,IAAI,CAAC,CACL,IACC,KAAK,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,KAAK,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,GACjF,KAAK,IAAI,KAAK,CAAC,CAAC,OAAO,CACzB;AACJ,CAAC;AASD,MAAM,SAAuC;CAC3C,WAAW;EACT,iBAAiB;GAAC;GAAG;GAAG;GAAK;GAAG;EAAE;EAClC,mBAAmB,EAAE,OAAO,iBAAiB;EAC7C,kBAAkB,EAAE,OAAO,aAAa;EACxC,OAAO;CACT;CACA,MAAM;EACJ,iBAAiB;GAAC;GAAG;GAAG;GAAK;GAAO;GAAG;GAAG;EAAC;EAC3C,mBAAmB,EAAE,OAAO,iBAAiB;EAC7C,kBAAkB,EAAE,OAAO,aAAa;EACxC,OAAO;CACT;AACF;AAoBA,IAAa,aAAb,MAAwB;CACtB;CACA;CAEA,YAAY,SAAgC;;EAE1C,IAAI,OAAO,YAAY,UAAU;;GAE/B,IAAI,YAAY,eAAe,YAAY,QACzC,MAAM,IAAI,MAAM,iBAAiB,SAAS;GAE5C,UAAU,OAAO;EACnB;EACA,KAAK,UAAU;EACf,KAAK,cAAc;GAAC;GAAG;GAAG;GAAK;GAAO;GAAG;EAAC;CAC5C;;CAGA,aAAqB,YAA8C;EACjE,OAAO;GACL,SAAS,IAAI,GAAG,CAAC;GACjB;GACA,qBAAqB;IACnB,aAAa,KAAK;IAClB,OAAO,WAAW;GACpB;EACF;CACF;CAEA,iBAAiB,eAAuB,cAAuC;EAC7E,MAAM,mBAAoC;GACxC,SAAS,IAAI,GAAG,CAAC;GACjB,YAAY,OAAO,KAAK,eAAe,KAAK;GAC5C,YAAY,KAAK,QAAQ;EAC3B;;EAGA,IAAI,cACF,iBAAiB,YAAY;GAC3B,QAAQ;GACR,MAAM,OAAO,KAAK,cAAc,KAAK;EACvC;EAGF,OAAO;CACT;CAEA,gBAAgB,cAGd;EACA,OAAO;GACL,WAAW;IACT,IAAI,KAAK;IACT,OAAO,KAAK,QAAQ;GACtB;GACA,KAAK;IACH,QAAQ;IACR,MAAM,OAAO,KAAK,cAAc,KAAK;GACvC;EACF;CACF;CAEA,cACE,YACA,gBACA,mBACA,wBAA2C,SACnC;EACR,IAAI;EAGJ,QAAQ,gBAAR;GACE,KAAK,OAAO;IACV,IAAI,OAAO,eAAe,UACxB,MAAM,IAAI,MAAM,8BAA8B;IAEhD,MAAM,eAAe,WACnB,KAAK,QAAQ,MAAM,aAAa,iBAAiB,UAAU,GAAG,KAAK,CACrE;IACA,mBAAmB,KAAK,iBAAiB,YAAY,YAAY;IACjE;GACF;;GAEA,KAAK;IACH,IAAI,OAAO,eAAe,UACxB,aAAa,OAAO,KAAK,YAAY,KAAK;IAE5C,mBAAmB,gBAAgB,OAAO,YAAY,KAAK;IAC3D;GACF,KAAK;IACH,IAAI,OAAO,eAAe,UACxB,MAAM,IAAI,MAAM,8BAA8B;IAEhD,mBAAmB,gBAAgB,OACjC,YACA,OACA,KAAK,QAAQ,iBACf;IACA;;GAEF,SACE,MAAM,IAAI,MAAM,4BAA4B;EAChD;EAGA,QAAQ,mBAAR;GACE,KAAK;IACH,IAAI,0BAA0B,SAC5B,OAAO,iBAAiB,WAAW,SAAS,KAAK;SAC5C,IAAI,0BAA0B,SACnC,OAAO,KAAK,aAAa,gBAAgB,CAAC,CAAC,WAAW,WAAW,SAAS,KAAK;IAEjF;GACF,KAAK;IACH,IAAI,0BAA0B,SAC5B,OAAO,gBAAgB,OAAO,kBAAkB,KAAK,CAAC,CAAC,SAAS,KAAK;SAChE,IAAI,0BAA0B,SACnC,OAAO,iBAAiB,OAAO,KAAK,aAAa,gBAAgB,GAAG,KAAK,CAAC,CAAC,SACzE,KACF;IAEF;GACF,KAAK;IACH,IAAI,0BAA0B,SAC5B,OAAO,gBAAgB,OAAO,kBAAkB,OAAO,KAAK,QAAQ,iBAAiB;SAChF,IAAI,0BAA0B,SACnC,OAAO,iBAAiB,OAAO,KAAK,aAAa,gBAAgB,GAAG,OAAO;KACzE,GAAG,KAAK,QAAQ;KAChB,OAAO;IACT,CAAC;IAEH;;GAEF,SACE,MAAM,IAAI,MAAM,4CAA4C;EAChE;EAEA,MAAM,IAAI,MAAM,wCAAwC;CAC1D;CAEA,aACE,WACA,gBACA,mBACQ;EAER,IAAI;EAEJ,QAAQ,gBAAR;GACE,KAAK;IACH,IAAI,OAAO,cAAc,UACvB,MAAM,IAAI,MAAM,6BAA6B;IAE/C,kBAAkB,KAAK,gBAAgB,SAAS;IAChD;;GAEF,KAAK;IACH,IAAI,OAAO,cAAc,UACvB,YAAY,OAAO,KAAK,WAAW,KAAK;IAE1C,kBAAkB,wBAAwB,OAAO,WAAW,KAAK;IACjE;GACF,KAAK;IACH,IAAI,OAAO,cAAc,UACvB,MAAM,IAAI,MAAM,6BAA6B;IAE/C,kBAAkB,wBAAwB,OACxC,WACA,OACA,KAAK,QAAQ,gBACf;IACA;;GAEF,SACE,MAAM,IAAI,MAAM,2BAA2B;EAC/C;EAGA,QAAQ,mBAAR;GACE,KAAK,OACH,OAAO,gBAAgB,IAAI,KAAK,SAAS,KAAK;GAChD,KAAK,OACH,OAAO,wBAAwB,OAAO,iBAAiB,KAAK,CAAC,CAAC,SAAS,KAAK;GAC9E,KAAK,OACH,OAAO,wBAAwB,OAC7B,iBACA,OACA,KAAK,QAAQ,gBACf;;GAEF,SACE,MAAM,IAAI,MAAM,2CAA2C;EAC/D;CACF;AACF;;;ACnSA,SAAS,iBAAiB,QAAwB;CAGhD,MAAM,MAAM,OAAO,MAAM,IAAI;CAC7B,IAAI,MAAM;CACV,IAAI,IAAI;CAMR,OAJkB,OAAO,KAAK,IAAI,KAAK,EAAE,GAAG,QAGZ,CAAC,CAAC,MAAM,EACnB,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,YAAY;AACrD;AAEA,SAAS,SAAS,WAAmB,EAAE,YAAY,SAAS,CAAC,GAAW;CACtE,MAAM,aAAa,IAAI,WAAW,MAAM;CACxC,IAAI,WACF,OAAO,WAAW,cAAc,WAAW,OAAO,KAAK;CAEzD,OAAO,WAAW,aAAa,WAAW,OAAO,KAAK;AACxD;;;;;AAMA,SAAgB,QAAQ,SAAiC;CACvD,IAAI,SAAS;EACX,MAAM,YAAY,6BAA6B,OAAO;EACtD,MAAM,YAAY,WAAW,KAAK,aAAa,iBAAiB,SAAS,GAAG,KAAK,CAAC;EAClF,OAAO;GACL,YAAY,OAAO,SAAS,SAAS,CAAC;GACtC,WAAW,OAAO,SAAS,WAAW,EAAE,WAAW,MAAM,CAAC,CAAC;GAC3D,WAAW,iBAAiB,OAAO,SAAS,WAAW,EAAE,WAAW,MAAM,CAAC,CAAC,CAAC;EAC/E;CACF;CACA,MAAM,EAAE,WAAW,eAAe,OAAO,oBAAoB,MAAM;EACjE,YAAY;EACZ,mBAAmB;GAAE,MAAM;GAAQ,QAAQ;EAAM;EACjD,oBAAoB;GAAE,MAAM;GAAQ,QAAQ;EAAM;CACpD,CAAC;CAED,OAAO;EACL;EACA;EACA,WAJgB,iBAAiB,SAIzB;CACV;AACF;AAEA,MAAa,OAAO,OAAO,eAAuB,oBAA6C;CAE7F,MAAM,qBAAqB,KAAK,UAAU,OAAO,eAAe;CAKhE,MAAM,aAAa,OAAO,iBAAiB,aAAa;CAGxD,OAAO,IAAI,KAAK,YAAY,kBAAkB,CAAC,CAC5C,mBAAmB;EAAE,KAAK;EAAS,KAAK;CAAM,CAAC,CAAC,CAChD,KAAK,UAAU;AACpB"}
|
package/lib/crypto.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_crypto = require("./crypto-
|
|
2
|
+
const require_crypto = require("./crypto-CKLQSwr3.cjs");
|
|
3
3
|
exports.genKeys = require_crypto.genKeys;
|
|
4
4
|
exports.genSeed = require_crypto.genSeed;
|
|
5
5
|
exports.getMasterSeed = require_crypto.getMasterSeed;
|
package/lib/crypto.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as getMasterSeed, n as sign, r as genSeed, t as genKeys } from "./crypto-
|
|
1
|
+
import { i as getMasterSeed, n as sign, r as genSeed, t as genKeys } from "./crypto-hrnmToQa.js";
|
|
2
2
|
export { genKeys, genSeed, getMasterSeed, sign };
|
|
@@ -26,6 +26,55 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
enumerable: true
|
|
27
27
|
}) : target, mod));
|
|
28
28
|
//#endregion
|
|
29
|
+
//#region src/device/abort.ts
|
|
30
|
+
/** Error returned when the application aborts a device operation. */
|
|
31
|
+
var DeviceOperationAbortedError = class extends Error {
|
|
32
|
+
constructor() {
|
|
33
|
+
super("Device operation aborted");
|
|
34
|
+
this.name = "DeviceOperationAbortedError";
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const isDeviceOperationAbortedError = (error) => error instanceof Error && error.name === "DeviceOperationAbortedError";
|
|
38
|
+
const throwIfDeviceOperationAborted = (signal) => {
|
|
39
|
+
if (signal?.aborted) throw new DeviceOperationAbortedError();
|
|
40
|
+
};
|
|
41
|
+
const withDeviceOperationSignal = (operation, signal) => {
|
|
42
|
+
try {
|
|
43
|
+
throwIfDeviceOperationAborted(signal);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return Promise.reject(error);
|
|
46
|
+
}
|
|
47
|
+
if (!signal) return Promise.resolve().then(operation);
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const onAbort = () => reject(new DeviceOperationAbortedError());
|
|
50
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
51
|
+
Promise.resolve().then(() => {
|
|
52
|
+
throwIfDeviceOperationAborted(signal);
|
|
53
|
+
return operation();
|
|
54
|
+
}).then(resolve, (error) => {
|
|
55
|
+
reject(signal.aborted ? new DeviceOperationAbortedError() : error);
|
|
56
|
+
}).finally(() => signal.removeEventListener("abort", onAbort));
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const deviceOperationDelay = (delay, signal) => {
|
|
60
|
+
try {
|
|
61
|
+
throwIfDeviceOperationAborted(signal);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return Promise.reject(error);
|
|
64
|
+
}
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const timeout = setTimeout(() => {
|
|
67
|
+
signal?.removeEventListener("abort", onAbort);
|
|
68
|
+
resolve();
|
|
69
|
+
}, delay);
|
|
70
|
+
const onAbort = () => {
|
|
71
|
+
clearTimeout(timeout);
|
|
72
|
+
reject(new DeviceOperationAbortedError());
|
|
73
|
+
};
|
|
74
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
29
78
|
//#region ../../node_modules/.pnpm/axios-retry@4.5.0_axios@1.19.0/node_modules/axios-retry/dist/esm/index.js
|
|
30
79
|
var import_is_retry_allowed = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
31
80
|
const denyList = /* @__PURE__ */ new Set([
|
|
@@ -271,6 +320,7 @@ function createApiDevice(options, logger) {
|
|
|
271
320
|
if (typeof __seed === "string") return Promise.resolve(__seed);
|
|
272
321
|
return __seed;
|
|
273
322
|
};
|
|
323
|
+
const postWithSignal = async (url, data, signal) => withDeviceOperationSignal(() => signal ? deviceApi.post(url, data, { signal }) : deviceApi.post(url, data), signal);
|
|
274
324
|
const authenticate = async ({ challenge, workspaceName }) => {
|
|
275
325
|
const role = challenge.role;
|
|
276
326
|
if (role === "READ_ONLY_API_KEY") throw new Error("Invalid role for authenticate: READ_ONLY_API_KEY");
|
|
@@ -313,8 +363,8 @@ function createApiDevice(options, logger) {
|
|
|
313
363
|
const res = await deviceApi.post("/generate-key-fragments", payload);
|
|
314
364
|
return Buffer.from(res.data, "hex").toString("base64");
|
|
315
365
|
};
|
|
316
|
-
const getAttestation = async () => {
|
|
317
|
-
const { data: attestationStr } = await
|
|
366
|
+
const getAttestation = async (opts = {}) => {
|
|
367
|
+
const { data: attestationStr } = await postWithSignal("/get-attestation", { seed: await getSeed() }, opts.signal);
|
|
318
368
|
const attestationBuffer = Buffer.from(attestationStr, "hex");
|
|
319
369
|
const certLen = attestationBuffer.readInt8(98);
|
|
320
370
|
return {
|
|
@@ -326,8 +376,8 @@ function createApiDevice(options, logger) {
|
|
|
326
376
|
buffer: attestationBuffer
|
|
327
377
|
};
|
|
328
378
|
};
|
|
329
|
-
const getConfidentialityKey = async () => {
|
|
330
|
-
const res = await
|
|
379
|
+
const getConfidentialityKey = async (opts = {}) => {
|
|
380
|
+
const res = await postWithSignal("/get-confidentiality-key", { seed: await getSeed() }, opts.signal);
|
|
331
381
|
return {
|
|
332
382
|
confidentialityKeyCurve25519: res.data.confidentiality_key_curve25519,
|
|
333
383
|
confidentialityKeySignature: res.data.confidentiality_key_signature
|
|
@@ -345,13 +395,13 @@ function createApiDevice(options, logger) {
|
|
|
345
395
|
const getValidationPubKey = async () => {
|
|
346
396
|
return getPublicKey({ path: PATHS.VALIDATION });
|
|
347
397
|
};
|
|
348
|
-
const hasPairing = async () => {
|
|
398
|
+
const hasPairing = async (opts = {}) => {
|
|
349
399
|
const seed = await getSeed();
|
|
350
|
-
if ((await
|
|
351
|
-
return (await
|
|
400
|
+
if ((await postWithSignal("/get-partition-ids", { seed }, opts.signal)).data.length === 0) return "NO_PAIRING";
|
|
401
|
+
return (await postWithSignal("/partition-psk-status", { seed }, opts.signal)).data.psk_missing ? "PSK_MISSING" : "OK";
|
|
352
402
|
};
|
|
353
|
-
const initPairingHandshake = async () => {
|
|
354
|
-
const { data } = await
|
|
403
|
+
const initPairingHandshake = async (opts = {}) => {
|
|
404
|
+
const { data } = await postWithSignal("/initiate-pairing-handshake", { seed: await getSeed() }, opts.signal);
|
|
355
405
|
return {
|
|
356
406
|
pubKey: data.pubKey,
|
|
357
407
|
signature: Buffer.from(data.attestation, "hex").toString("base64")
|
|
@@ -416,7 +466,7 @@ function createApiDevice(options, logger) {
|
|
|
416
466
|
};
|
|
417
467
|
return (await deviceApi.post("/u2f-register-data", payload)).data;
|
|
418
468
|
};
|
|
419
|
-
const setPairing = async ({ pairing }) => {
|
|
469
|
+
const setPairing = async ({ pairing, signal }) => {
|
|
420
470
|
const payload = {
|
|
421
471
|
seed: await getSeed(),
|
|
422
472
|
blob: pairing.blob,
|
|
@@ -432,13 +482,13 @@ function createApiDevice(options, logger) {
|
|
|
432
482
|
signature: pairing.partitionKeyAttestation.signature
|
|
433
483
|
}
|
|
434
484
|
};
|
|
435
|
-
await
|
|
485
|
+
await postWithSignal("/set-partition-key", payload, signal);
|
|
436
486
|
};
|
|
437
|
-
const signRefreshPskAuth = async ({ ephemeralKey }) => {
|
|
438
|
-
const { data } = await
|
|
487
|
+
const signRefreshPskAuth = async ({ ephemeralKey, signal }) => {
|
|
488
|
+
const { data } = await postWithSignal("/sign-refresh-psk-auth", {
|
|
439
489
|
seed: await getSeed(),
|
|
440
490
|
ephemeral_key: ephemeralKey
|
|
441
|
-
});
|
|
491
|
+
}, signal);
|
|
442
492
|
return Buffer.from(data, "hex").toString("base64");
|
|
443
493
|
};
|
|
444
494
|
const finalizePskRefresh = async (params) => {
|
|
@@ -447,7 +497,7 @@ function createApiDevice(options, logger) {
|
|
|
447
497
|
handshake: Buffer.from(params.handshake, "base64").toString("hex"),
|
|
448
498
|
ciphertext: Buffer.from(params.encryptedPairingPayload, "base64").toString("hex")
|
|
449
499
|
};
|
|
450
|
-
await
|
|
500
|
+
await postWithSignal("/finalize-psk-refresh", payload, params.signal);
|
|
451
501
|
};
|
|
452
502
|
const startKKPatternAsResponder = async (params) => {
|
|
453
503
|
const payload = {
|
|
@@ -474,7 +524,7 @@ function createApiDevice(options, logger) {
|
|
|
474
524
|
handshake_attestation: "",
|
|
475
525
|
partition_id: partitionId
|
|
476
526
|
};
|
|
477
|
-
const { data: deviceResponse } = await
|
|
527
|
+
const { data: deviceResponse } = await postWithSignal("/start-k-pattern-as-responder", payload, params.signal);
|
|
478
528
|
if (deviceResponse !== "9000") throw new Error(`device-api device failed with code: ${deviceResponse}`);
|
|
479
529
|
};
|
|
480
530
|
const startPskSession = async (params) => {
|
|
@@ -486,7 +536,7 @@ function createApiDevice(options, logger) {
|
|
|
486
536
|
nonce: Buffer.from(nonce, "hex").toString("base64"),
|
|
487
537
|
partition_id: Buffer.from(partitionId, "hex").toString("base64")
|
|
488
538
|
};
|
|
489
|
-
const { data: deviceResponse } = await
|
|
539
|
+
const { data: deviceResponse } = await postWithSignal("/start-psk-session", payload, params.signal);
|
|
490
540
|
if (deviceResponse !== "9000") throw new Error(`device-api device failed with code: ${deviceResponse}`);
|
|
491
541
|
};
|
|
492
542
|
const getPublicKey = async (params) => {
|
|
@@ -509,22 +559,20 @@ function createApiDevice(options, logger) {
|
|
|
509
559
|
path: PATHS.VALIDATION,
|
|
510
560
|
actions
|
|
511
561
|
};
|
|
512
|
-
const { data: signature } = await
|
|
562
|
+
const { data: signature } = await postWithSignal("/validate-op", payload, params.signal);
|
|
513
563
|
return signature;
|
|
514
564
|
};
|
|
515
565
|
const sendAPDU = (_apdu) => {
|
|
516
566
|
logger.info("Can't send arbitrary APDU to software device");
|
|
517
567
|
return Promise.resolve("9000");
|
|
518
568
|
};
|
|
519
|
-
const getVersion = async () =>
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
const poll = async () => {
|
|
523
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
569
|
+
const getVersion = async (opts = {}) => withDeviceOperationSignal(() => Promise.resolve("1.2.3"), opts.signal);
|
|
570
|
+
const poll = async (opts = {}) => {
|
|
571
|
+
await deviceOperationDelay(1e3, opts.signal);
|
|
524
572
|
return { isAppOpened: true };
|
|
525
573
|
};
|
|
526
|
-
const pollApp = async () => {
|
|
527
|
-
await
|
|
574
|
+
const pollApp = async (_name, opts = {}) => {
|
|
575
|
+
await deviceOperationDelay(1e3, opts.signal);
|
|
528
576
|
return "9000";
|
|
529
577
|
};
|
|
530
578
|
return {
|
|
@@ -916,7 +964,14 @@ const withDevice = (deviceId) => (job) => new Observable((o) => {
|
|
|
916
964
|
deviceQueues[deviceId] = new Promise((resolve) => {
|
|
917
965
|
finish = resolve;
|
|
918
966
|
});
|
|
919
|
-
deviceQueue.then(() =>
|
|
967
|
+
deviceQueue.then(() => {
|
|
968
|
+
if (unsubscribed) {
|
|
969
|
+
finish();
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
return open(deviceId);
|
|
973
|
+
}).then(async (transport) => {
|
|
974
|
+
if (!transport) return;
|
|
920
975
|
if (unsubscribed) return finalize(transport, [finish]);
|
|
921
976
|
if (transport.requestConnectionPriority && typeof transport.requestConnectionPriority === "function") await transport.requestConnectionPriority("High");
|
|
922
977
|
return transport;
|
|
@@ -957,12 +1012,6 @@ const CANCEL_STATUS_CODES = [
|
|
|
957
1012
|
45075,
|
|
958
1013
|
21761
|
|
959
1014
|
];
|
|
960
|
-
const isDeviceCancelError = (error) => {
|
|
961
|
-
return isTransportStatusError(error) && CANCEL_STATUS_CODES.includes(error.statusCode);
|
|
962
|
-
};
|
|
963
|
-
const namedErrorPredicate = (name) => (error) => error instanceof Error && error.name === name;
|
|
964
|
-
const isCantOpenDeviceError = namedErrorPredicate("CantOpenDevice");
|
|
965
|
-
const isLockedDeviceError = namedErrorPredicate("LockedDeviceError");
|
|
966
1015
|
const isDeviceApiSwError = (error, sw) => {
|
|
967
1016
|
if (typeof error !== "object" || error === null || !("response" in error)) return false;
|
|
968
1017
|
const { response } = error;
|
|
@@ -972,6 +1021,13 @@ const isDeviceApiSwError = (error, sw) => {
|
|
|
972
1021
|
const hasSw = (obj) => typeof obj === "object" && obj !== null && "sw" in obj && obj.sw === sw;
|
|
973
1022
|
return hasSw(data) || hasSw(data.data);
|
|
974
1023
|
};
|
|
1024
|
+
const isDeviceCancelError = (error) => {
|
|
1025
|
+
if (isTransportStatusError(error)) return CANCEL_STATUS_CODES.includes(error.statusCode);
|
|
1026
|
+
return CANCEL_STATUS_CODES.some((status) => isDeviceApiSwError(error, status.toString(16)));
|
|
1027
|
+
};
|
|
1028
|
+
const namedErrorPredicate = (name) => (error) => error instanceof Error && error.name === name;
|
|
1029
|
+
const isCantOpenDeviceError = namedErrorPredicate("CantOpenDevice");
|
|
1030
|
+
const isLockedDeviceError = namedErrorPredicate("LockedDeviceError");
|
|
975
1031
|
const isPskMissingError = (error) => {
|
|
976
1032
|
return isTransportStatusError(error) && error.statusCode === 24677 || isDeviceApiSwError(error, "6065");
|
|
977
1033
|
};
|
|
@@ -979,6 +1035,6 @@ const isPskMismatchError = (error) => {
|
|
|
979
1035
|
return isTransportStatusError(error) && error.statusCode === 24679 || isDeviceApiSwError(error, "6067");
|
|
980
1036
|
};
|
|
981
1037
|
//#endregion
|
|
982
|
-
export { isPskMissingError as a, withDevicePolling as c, createApiDevice as d, APPID_VAULT_ADMINISTRATOR as f, STR_ROLES as g, SCRIPT_IDS as h, isPskMismatchError as i, DisconnectedDevice as l, PATHS as m, isDeviceCancelError as n, isTransportStatusError as o, PAGINATED_STATUS as p, isLockedDeviceError as r, registerTransportModule as s, isCantOpenDeviceError as t, LockedDeviceError as u };
|
|
1038
|
+
export { DeviceOperationAbortedError as _, isPskMissingError as a, throwIfDeviceOperationAborted as b, withDevicePolling as c, createApiDevice as d, APPID_VAULT_ADMINISTRATOR as f, STR_ROLES as g, SCRIPT_IDS as h, isPskMismatchError as i, DisconnectedDevice as l, PATHS as m, isDeviceCancelError as n, isTransportStatusError as o, PAGINATED_STATUS as p, isLockedDeviceError as r, registerTransportModule as s, isCantOpenDeviceError as t, LockedDeviceError as u, deviceOperationDelay as v, isDeviceOperationAbortedError as y };
|
|
983
1039
|
|
|
984
|
-
//# sourceMappingURL=device-
|
|
1040
|
+
//# sourceMappingURL=device-BnO26Hlr.js.map
|