@ledgerhq/revault-sdk 0.25.0 → 0.25.1
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 +1214 -1359
- package/lib/bake.cjs.map +1 -1
- package/lib/bake.d.cts +564 -562
- package/lib/bake.d.ts +564 -562
- package/lib/bake.js +1204 -1359
- package/lib/bake.js.map +1 -1
- package/lib/chunk-CKQMccvm.cjs +28 -0
- package/lib/crypto-BDBF_rfw.cjs +268 -0
- package/lib/crypto-BDBF_rfw.cjs.map +1 -0
- package/lib/crypto-CPCBrCSZ.js +245 -0
- package/lib/crypto-CPCBrCSZ.js.map +1 -0
- package/lib/crypto.cjs +5 -11
- package/lib/crypto.d.cts +10 -7
- package/lib/crypto.d.ts +10 -7
- package/lib/crypto.js +2 -11
- package/lib/device-0lcfYGHr.cjs +793 -0
- package/lib/device-0lcfYGHr.cjs.map +1 -0
- package/lib/device-B8Fww8_6.js +719 -0
- package/lib/device-B8Fww8_6.js.map +1 -0
- package/lib/device.cjs +6 -13
- package/lib/device.d.cts +2 -50
- package/lib/device.d.ts +2 -50
- package/lib/device.js +2 -13
- package/lib/engine.cjs +835 -886
- package/lib/engine.cjs.map +1 -1
- package/lib/engine.d.cts +3 -25
- package/lib/engine.d.ts +3 -25
- package/lib/engine.js +828 -885
- package/lib/engine.js.map +1 -1
- package/lib/index--fscLDTT.d.ts +237 -0
- package/lib/index-BE7oUpCb.d.cts +237 -0
- package/lib/index-C4Xjiv0k.d.cts +23 -0
- package/lib/index-CVjhPoZh.d.ts +23 -0
- package/lib/index.cjs +0 -1
- package/lib/index.d.cts +10 -5
- package/lib/index.d.ts +10 -5
- package/lib/index.js +1 -1
- package/lib/logger-Cme0iL1f.d.cts +10 -0
- package/lib/logger-DWLViq7U.d.ts +10 -0
- package/lib/onboarding.cjs +179 -181
- package/lib/onboarding.cjs.map +1 -1
- package/lib/onboarding.d.cts +1751 -1722
- package/lib/onboarding.d.ts +1751 -1722
- package/lib/onboarding.js +175 -181
- package/lib/onboarding.js.map +1 -1
- package/lib/trpc-CWGPr8Ox.d.ts +20 -0
- package/lib/trpc-C_dUOB1u.d.cts +20 -0
- package/lib/types-4CfR5--z.d.ts +203 -0
- package/lib/types-Byf9V35t.d.cts +203 -0
- package/lib/types-CQROu0nu.d.cts +6 -0
- package/lib/types-_QeBv1U4.d.ts +6 -0
- package/lib/types.cjs +0 -1
- package/lib/types.d.cts +3 -4
- package/lib/types.d.ts +3 -4
- package/lib/types.js +1 -1
- package/lib/utils-BGbdjOP9.js +61 -0
- package/lib/utils-BGbdjOP9.js.map +1 -0
- package/lib/utils-DbSFXp4c.cjs +86 -0
- package/lib/utils-DbSFXp4c.cjs.map +1 -0
- package/package.json +6 -6
- package/lib/chunk-2WGM7EWA.cjs +0 -282
- package/lib/chunk-2WGM7EWA.cjs.map +0 -1
- package/lib/chunk-AXI72NFY.js +0 -50
- package/lib/chunk-AXI72NFY.js.map +0 -1
- package/lib/chunk-DRMYBKL3.cjs +0 -820
- package/lib/chunk-DRMYBKL3.cjs.map +0 -1
- package/lib/chunk-KV5FO7N5.js +0 -282
- package/lib/chunk-KV5FO7N5.js.map +0 -1
- package/lib/chunk-LH4QQXUH.cjs +0 -50
- package/lib/chunk-LH4QQXUH.cjs.map +0 -1
- package/lib/chunk-PFZIW6UP.js +0 -820
- package/lib/chunk-PFZIW6UP.js.map +0 -1
- package/lib/crypto.cjs.map +0 -1
- package/lib/crypto.js.map +0 -1
- package/lib/device.cjs.map +0 -1
- package/lib/device.js.map +0 -1
- package/lib/index.cjs.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/logger-C-TPbnjv.d.cts +0 -9
- package/lib/logger-C-TPbnjv.d.ts +0 -9
- package/lib/types-C-ngtI5m.d.ts +0 -202
- package/lib/types-CpGEbAxh.d.cts +0 -19
- package/lib/types-CpGEbAxh.d.ts +0 -19
- package/lib/types-CryvY9pW.d.cts +0 -202
- package/lib/types-DJfbanPz.d.cts +0 -167
- package/lib/types-DJfbanPz.d.ts +0 -167
- package/lib/types.cjs.map +0 -1
- package/lib/types.js.map +0 -1
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
const require_chunk = require("./chunk-CKQMccvm.cjs");
|
|
2
|
+
let _noble_hashes_sha2_js = require("@noble/hashes/sha2.js");
|
|
3
|
+
let _scure_bip39 = require("@scure/bip39");
|
|
4
|
+
let _scure_bip39_wordlists_english_js = require("@scure/bip39/wordlists/english.js");
|
|
5
|
+
let elliptic = require("elliptic");
|
|
6
|
+
elliptic = require_chunk.__toESM(elliptic);
|
|
7
|
+
let jose = require("jose");
|
|
8
|
+
jose = require_chunk.__toESM(jose);
|
|
9
|
+
let asn1_js = require("asn1.js");
|
|
10
|
+
asn1_js = require_chunk.__toESM(asn1_js);
|
|
11
|
+
let bn_js = require("bn.js");
|
|
12
|
+
bn_js = require_chunk.__toESM(bn_js);
|
|
13
|
+
let node_crypto = require("node:crypto");
|
|
14
|
+
node_crypto = require_chunk.__toESM(node_crypto);
|
|
15
|
+
//#region src/crypto/gen-seed.ts
|
|
16
|
+
/**
|
|
17
|
+
* Generate a deterministic BIP39 mnemonic from a salt and device index.
|
|
18
|
+
*
|
|
19
|
+
* Produces `entropyToMnemonic(SHA256(salt + "_" + index))`, matching
|
|
20
|
+
* the behavior of `@ledgerhq/vault-common`'s `genSeed`.
|
|
21
|
+
*
|
|
22
|
+
* @param salt The workspace salt
|
|
23
|
+
* @param index The device index (1-based)
|
|
24
|
+
* @returns A 24-word BIP39 mnemonic string
|
|
25
|
+
*/
|
|
26
|
+
function genSeed(salt, index) {
|
|
27
|
+
return (0, _scure_bip39.entropyToMnemonic)((0, _noble_hashes_sha2_js.sha256)(new TextEncoder().encode(`${salt}_${index}`)), _scure_bip39_wordlists_english_js.wordlist);
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/crypto/key-encoder.ts
|
|
31
|
+
const ECPrivateKeyASN = asn1_js.default.define("ECPrivateKey", function() {
|
|
32
|
+
const self = this;
|
|
33
|
+
self.seq().obj(self.key("version").int(), self.key("privateKey").octstr(), self.key("parameters").explicit(0).objid().optional(), self.key("publicKey").explicit(1).bitstr().optional());
|
|
34
|
+
});
|
|
35
|
+
const ECPrivateKey8ASN = asn1_js.default.define(
|
|
36
|
+
"ECPrivateKey",
|
|
37
|
+
/* v8 ignore next -- @preserve */
|
|
38
|
+
function() {
|
|
39
|
+
const self = this;
|
|
40
|
+
self.seq().obj(self.key("version").int(), self.key("privateKeyAlgorithm").seq().obj(self.key("ecPublicKey").objid(), self.key("curve").objid()), self.key("privateKey").octstr().contains(ECPrivateKeyASN), self.key("attributes").explicit(0).bitstr().optional());
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
const SubjectPublicKeyInfoASN = asn1_js.default.define("SubjectPublicKeyInfo", function() {
|
|
44
|
+
const self = this;
|
|
45
|
+
self.seq().obj(self.key("algorithm").seq().obj(self.key("id").objid(), self.key("curve").objid()), self.key("pub").bitstr());
|
|
46
|
+
});
|
|
47
|
+
const curves = {
|
|
48
|
+
secp256k1: {
|
|
49
|
+
curveParameters: [
|
|
50
|
+
1,
|
|
51
|
+
3,
|
|
52
|
+
132,
|
|
53
|
+
0,
|
|
54
|
+
10
|
|
55
|
+
],
|
|
56
|
+
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
57
|
+
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
58
|
+
curve: new elliptic.default.ec("secp256k1")
|
|
59
|
+
},
|
|
60
|
+
p256: {
|
|
61
|
+
curveParameters: [
|
|
62
|
+
1,
|
|
63
|
+
2,
|
|
64
|
+
840,
|
|
65
|
+
10045,
|
|
66
|
+
3,
|
|
67
|
+
1,
|
|
68
|
+
7
|
|
69
|
+
],
|
|
70
|
+
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
71
|
+
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
72
|
+
curve: new elliptic.default.ec("p256")
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var KeyEncoder = class {
|
|
76
|
+
algorithmID;
|
|
77
|
+
options;
|
|
78
|
+
constructor(options) {
|
|
79
|
+
/* v8 ignore else -- @preserve */
|
|
80
|
+
if (typeof options === "string") {
|
|
81
|
+
/* v8 ignore if -- @preserve */
|
|
82
|
+
if (options !== "secp256k1" && options !== "p256") throw new Error(`Unknown curve ${options}`);
|
|
83
|
+
options = curves[options];
|
|
84
|
+
}
|
|
85
|
+
this.options = options;
|
|
86
|
+
this.algorithmID = [
|
|
87
|
+
1,
|
|
88
|
+
2,
|
|
89
|
+
840,
|
|
90
|
+
10045,
|
|
91
|
+
2,
|
|
92
|
+
1
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
/* v8 ignore next -- @preserve */
|
|
96
|
+
PKCS1toPKCS8(privateKey) {
|
|
97
|
+
return {
|
|
98
|
+
version: new bn_js.default(0),
|
|
99
|
+
privateKey,
|
|
100
|
+
privateKeyAlgorithm: {
|
|
101
|
+
ecPublicKey: this.algorithmID,
|
|
102
|
+
curve: privateKey.parameters
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
privateKeyObject(rawPrivateKey, rawPublicKey) {
|
|
107
|
+
const privateKeyObject = {
|
|
108
|
+
version: new bn_js.default(1),
|
|
109
|
+
privateKey: Buffer.from(rawPrivateKey, "hex"),
|
|
110
|
+
parameters: this.options.curveParameters
|
|
111
|
+
};
|
|
112
|
+
/* v8 ignore else -- @preserve */
|
|
113
|
+
if (rawPublicKey) privateKeyObject.publicKey = {
|
|
114
|
+
unused: 0,
|
|
115
|
+
data: Buffer.from(rawPublicKey, "hex")
|
|
116
|
+
};
|
|
117
|
+
return privateKeyObject;
|
|
118
|
+
}
|
|
119
|
+
publicKeyObject(rawPublicKey) {
|
|
120
|
+
return {
|
|
121
|
+
algorithm: {
|
|
122
|
+
id: this.algorithmID,
|
|
123
|
+
curve: this.options.curveParameters
|
|
124
|
+
},
|
|
125
|
+
pub: {
|
|
126
|
+
unused: 0,
|
|
127
|
+
data: Buffer.from(rawPublicKey, "hex")
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
encodePrivate(privateKey, originalFormat, destinationFormat, destinationFormatType = "pkcs1") {
|
|
132
|
+
let privateKeyObject;
|
|
133
|
+
switch (originalFormat) {
|
|
134
|
+
case "raw": {
|
|
135
|
+
if (typeof privateKey !== "string") throw new Error("private key must be a string");
|
|
136
|
+
const rawPublicKey = this.options.curve.keyFromPrivate(privateKey, "hex").getPublic("hex");
|
|
137
|
+
privateKeyObject = this.privateKeyObject(privateKey, rawPublicKey);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case "der":
|
|
141
|
+
if (typeof privateKey === "string") privateKey = Buffer.from(privateKey, "hex");
|
|
142
|
+
privateKeyObject = ECPrivateKeyASN.decode(privateKey, "der");
|
|
143
|
+
break;
|
|
144
|
+
case "pem":
|
|
145
|
+
if (typeof privateKey !== "string") throw new Error("private key must be a string");
|
|
146
|
+
privateKeyObject = ECPrivateKeyASN.decode(privateKey, "pem", this.options.privatePEMOptions);
|
|
147
|
+
break;
|
|
148
|
+
default: throw new Error("invalid private key format");
|
|
149
|
+
}
|
|
150
|
+
switch (destinationFormat) {
|
|
151
|
+
case "raw":
|
|
152
|
+
if (destinationFormatType === "pkcs1") return privateKeyObject.privateKey.toString("hex");
|
|
153
|
+
else if (destinationFormatType === "pkcs8") return this.PKCS1toPKCS8(privateKeyObject).privateKey.privateKey.toString("hex");
|
|
154
|
+
break;
|
|
155
|
+
case "der":
|
|
156
|
+
if (destinationFormatType === "pkcs1") return ECPrivateKeyASN.encode(privateKeyObject, "der").toString("hex");
|
|
157
|
+
else if (destinationFormatType === "pkcs8") return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), "der").toString("hex");
|
|
158
|
+
break;
|
|
159
|
+
case "pem":
|
|
160
|
+
if (destinationFormatType === "pkcs1") return ECPrivateKeyASN.encode(privateKeyObject, "pem", this.options.privatePEMOptions);
|
|
161
|
+
else if (destinationFormatType === "pkcs8") return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), "pem", {
|
|
162
|
+
...this.options.privatePEMOptions,
|
|
163
|
+
label: "PRIVATE KEY"
|
|
164
|
+
});
|
|
165
|
+
break;
|
|
166
|
+
default: throw new Error("invalid destination format for private key");
|
|
167
|
+
}
|
|
168
|
+
throw new Error("unsupported destination format or type");
|
|
169
|
+
}
|
|
170
|
+
encodePublic(publicKey, originalFormat, destinationFormat) {
|
|
171
|
+
let publicKeyObject;
|
|
172
|
+
switch (originalFormat) {
|
|
173
|
+
case "raw":
|
|
174
|
+
if (typeof publicKey !== "string") throw new Error("public key must be a string");
|
|
175
|
+
publicKeyObject = this.publicKeyObject(publicKey);
|
|
176
|
+
break;
|
|
177
|
+
case "der":
|
|
178
|
+
if (typeof publicKey === "string") publicKey = Buffer.from(publicKey, "hex");
|
|
179
|
+
publicKeyObject = SubjectPublicKeyInfoASN.decode(publicKey, "der");
|
|
180
|
+
break;
|
|
181
|
+
case "pem":
|
|
182
|
+
if (typeof publicKey !== "string") throw new Error("public key must be a string");
|
|
183
|
+
publicKeyObject = SubjectPublicKeyInfoASN.decode(publicKey, "pem", this.options.publicPEMOptions);
|
|
184
|
+
break;
|
|
185
|
+
default: throw new Error("invalid public key format");
|
|
186
|
+
}
|
|
187
|
+
switch (destinationFormat) {
|
|
188
|
+
case "raw": return publicKeyObject.pub.data.toString("hex");
|
|
189
|
+
case "der": return SubjectPublicKeyInfoASN.encode(publicKeyObject, "der").toString("hex");
|
|
190
|
+
case "pem": return SubjectPublicKeyInfoASN.encode(publicKeyObject, "pem", this.options.publicPEMOptions);
|
|
191
|
+
default: throw new Error("invalid destination format for public key");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/crypto/utils.ts
|
|
197
|
+
function extractPublicKey(pemKey) {
|
|
198
|
+
const pem = pemKey.split("\n");
|
|
199
|
+
pem.shift();
|
|
200
|
+
pem.pop();
|
|
201
|
+
return Buffer.from(pem.join(""), "base64").slice(26).toString("hex").toUpperCase();
|
|
202
|
+
}
|
|
203
|
+
function hexToPem(hexString, { isPrivate = true } = {}) {
|
|
204
|
+
const keyEncoder = new KeyEncoder("p256");
|
|
205
|
+
if (isPrivate) return keyEncoder.encodePrivate(hexString, "raw", "pem");
|
|
206
|
+
return keyEncoder.encodePublic(hexString, "raw", "pem");
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* If `entropy` is passed, will generate keys pair deterministically
|
|
210
|
+
* else, random keys pair generated
|
|
211
|
+
*/
|
|
212
|
+
function genKeys(entropy) {
|
|
213
|
+
if (entropy) {
|
|
214
|
+
const ec = new elliptic.default.ec("p256");
|
|
215
|
+
const hashedEntropy = node_crypto.default.createHash("sha256").update(entropy).digest("hex");
|
|
216
|
+
const keyPair = ec.genKeyPair({ entropy: Buffer.from(hashedEntropy, "hex") });
|
|
217
|
+
return {
|
|
218
|
+
privateKey: String(hexToPem(keyPair.getPrivate("hex"))),
|
|
219
|
+
publicKey: String(hexToPem(keyPair.getPublic("hex"), { isPrivate: false })),
|
|
220
|
+
hexPubKey: extractPublicKey(String(hexToPem(keyPair.getPublic("hex"), { isPrivate: false })))
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const { publicKey, privateKey } = node_crypto.default.generateKeyPairSync("ec", {
|
|
224
|
+
namedCurve: "P-256",
|
|
225
|
+
publicKeyEncoding: {
|
|
226
|
+
type: "spki",
|
|
227
|
+
format: "pem"
|
|
228
|
+
},
|
|
229
|
+
privateKeyEncoding: {
|
|
230
|
+
type: "sec1",
|
|
231
|
+
format: "pem"
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
return {
|
|
235
|
+
privateKey,
|
|
236
|
+
publicKey,
|
|
237
|
+
hexPubKey: extractPublicKey(publicKey)
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const sign = async (privateKeyPem, base64Challenge) => {
|
|
241
|
+
const challengeDataBytes = jose.base64url.decode(base64Challenge);
|
|
242
|
+
const privateKey = node_crypto.default.createPrivateKey(privateKeyPem);
|
|
243
|
+
return await new jose.CompactSign(challengeDataBytes).setProtectedHeader({
|
|
244
|
+
alg: "ES256",
|
|
245
|
+
typ: "JWT"
|
|
246
|
+
}).sign(privateKey);
|
|
247
|
+
};
|
|
248
|
+
//#endregion
|
|
249
|
+
Object.defineProperty(exports, "genKeys", {
|
|
250
|
+
enumerable: true,
|
|
251
|
+
get: function() {
|
|
252
|
+
return genKeys;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
Object.defineProperty(exports, "genSeed", {
|
|
256
|
+
enumerable: true,
|
|
257
|
+
get: function() {
|
|
258
|
+
return genSeed;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
Object.defineProperty(exports, "sign", {
|
|
262
|
+
enumerable: true,
|
|
263
|
+
get: function() {
|
|
264
|
+
return sign;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
//# sourceMappingURL=crypto-BDBF_rfw.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-BDBF_rfw.cjs","names":["wordlist","asn1","BN","crypto"],"sources":["../src/crypto/gen-seed.ts","../src/crypto/key-encoder.ts","../src/crypto/utils.ts"],"sourcesContent":["import { sha256 } from \"@noble/hashes/sha2.js\";\nimport { entropyToMnemonic } 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","// ========================================================================== //\n// //\n// DISCLAIMER //\n// //\n// This code has been blindly copy-pasted from: //\n// https://github.com/LedgerHQ/pkey-ts //\n// //\n// ========================================================================== //\n//\n// @ts-expect-error this library does not ship types\nimport asn1 from \"asn1.js\";\nimport BN from \"bn.js\";\nimport elliptic from \"elliptic\";\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: elliptic.ec;\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: new elliptic.ec(\"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: new elliptic.ec(\"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 keyPair = this.options.curve.keyFromPrivate(privateKey, \"hex\");\n const rawPublicKey = keyPair.getPublic(\"hex\");\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 elliptic from \"elliptic\";\nimport * as jose from \"jose\";\n\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 ec = new elliptic.ec(\"p256\");\n const hashedEntropy = crypto.createHash(\"sha256\").update(entropy).digest(\"hex\");\n const keyPair = ec.genKeyPair({\n entropy: Buffer.from(hashedEntropy, \"hex\"),\n });\n return {\n privateKey: String(hexToPem(keyPair.getPrivate(\"hex\"))),\n publicKey: String(hexToPem(keyPair.getPublic(\"hex\"), { isPrivate: false })),\n hexPubKey: extractPublicKey(String(hexToPem(keyPair.getPublic(\"hex\"), { 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 await new jose.CompactSign(challengeDataBytes)\n .setProtectedHeader({ alg: \"ES256\", typ: \"JWT\" })\n .sign(privateKey);\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
+
import { entropyToMnemonic } from "@scure/bip39";
|
|
3
|
+
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
4
|
+
import elliptic from "elliptic";
|
|
5
|
+
import * as jose from "jose";
|
|
6
|
+
import asn1 from "asn1.js";
|
|
7
|
+
import BN from "bn.js";
|
|
8
|
+
import crypto from "node:crypto";
|
|
9
|
+
//#region src/crypto/gen-seed.ts
|
|
10
|
+
/**
|
|
11
|
+
* Generate a deterministic BIP39 mnemonic from a salt and device index.
|
|
12
|
+
*
|
|
13
|
+
* Produces `entropyToMnemonic(SHA256(salt + "_" + index))`, matching
|
|
14
|
+
* the behavior of `@ledgerhq/vault-common`'s `genSeed`.
|
|
15
|
+
*
|
|
16
|
+
* @param salt The workspace salt
|
|
17
|
+
* @param index The device index (1-based)
|
|
18
|
+
* @returns A 24-word BIP39 mnemonic string
|
|
19
|
+
*/
|
|
20
|
+
function genSeed(salt, index) {
|
|
21
|
+
return entropyToMnemonic(sha256(new TextEncoder().encode(`${salt}_${index}`)), wordlist);
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/crypto/key-encoder.ts
|
|
25
|
+
const ECPrivateKeyASN = asn1.define("ECPrivateKey", function() {
|
|
26
|
+
const self = this;
|
|
27
|
+
self.seq().obj(self.key("version").int(), self.key("privateKey").octstr(), self.key("parameters").explicit(0).objid().optional(), self.key("publicKey").explicit(1).bitstr().optional());
|
|
28
|
+
});
|
|
29
|
+
const ECPrivateKey8ASN = asn1.define(
|
|
30
|
+
"ECPrivateKey",
|
|
31
|
+
/* v8 ignore next -- @preserve */
|
|
32
|
+
function() {
|
|
33
|
+
const self = this;
|
|
34
|
+
self.seq().obj(self.key("version").int(), self.key("privateKeyAlgorithm").seq().obj(self.key("ecPublicKey").objid(), self.key("curve").objid()), self.key("privateKey").octstr().contains(ECPrivateKeyASN), self.key("attributes").explicit(0).bitstr().optional());
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
const SubjectPublicKeyInfoASN = asn1.define("SubjectPublicKeyInfo", function() {
|
|
38
|
+
const self = this;
|
|
39
|
+
self.seq().obj(self.key("algorithm").seq().obj(self.key("id").objid(), self.key("curve").objid()), self.key("pub").bitstr());
|
|
40
|
+
});
|
|
41
|
+
const curves = {
|
|
42
|
+
secp256k1: {
|
|
43
|
+
curveParameters: [
|
|
44
|
+
1,
|
|
45
|
+
3,
|
|
46
|
+
132,
|
|
47
|
+
0,
|
|
48
|
+
10
|
|
49
|
+
],
|
|
50
|
+
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
51
|
+
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
52
|
+
curve: new elliptic.ec("secp256k1")
|
|
53
|
+
},
|
|
54
|
+
p256: {
|
|
55
|
+
curveParameters: [
|
|
56
|
+
1,
|
|
57
|
+
2,
|
|
58
|
+
840,
|
|
59
|
+
10045,
|
|
60
|
+
3,
|
|
61
|
+
1,
|
|
62
|
+
7
|
|
63
|
+
],
|
|
64
|
+
privatePEMOptions: { label: "EC PRIVATE KEY" },
|
|
65
|
+
publicPEMOptions: { label: "PUBLIC KEY" },
|
|
66
|
+
curve: new elliptic.ec("p256")
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var KeyEncoder = class {
|
|
70
|
+
algorithmID;
|
|
71
|
+
options;
|
|
72
|
+
constructor(options) {
|
|
73
|
+
/* v8 ignore else -- @preserve */
|
|
74
|
+
if (typeof options === "string") {
|
|
75
|
+
/* v8 ignore if -- @preserve */
|
|
76
|
+
if (options !== "secp256k1" && options !== "p256") throw new Error(`Unknown curve ${options}`);
|
|
77
|
+
options = curves[options];
|
|
78
|
+
}
|
|
79
|
+
this.options = options;
|
|
80
|
+
this.algorithmID = [
|
|
81
|
+
1,
|
|
82
|
+
2,
|
|
83
|
+
840,
|
|
84
|
+
10045,
|
|
85
|
+
2,
|
|
86
|
+
1
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
/* v8 ignore next -- @preserve */
|
|
90
|
+
PKCS1toPKCS8(privateKey) {
|
|
91
|
+
return {
|
|
92
|
+
version: new BN(0),
|
|
93
|
+
privateKey,
|
|
94
|
+
privateKeyAlgorithm: {
|
|
95
|
+
ecPublicKey: this.algorithmID,
|
|
96
|
+
curve: privateKey.parameters
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
privateKeyObject(rawPrivateKey, rawPublicKey) {
|
|
101
|
+
const privateKeyObject = {
|
|
102
|
+
version: new BN(1),
|
|
103
|
+
privateKey: Buffer.from(rawPrivateKey, "hex"),
|
|
104
|
+
parameters: this.options.curveParameters
|
|
105
|
+
};
|
|
106
|
+
/* v8 ignore else -- @preserve */
|
|
107
|
+
if (rawPublicKey) privateKeyObject.publicKey = {
|
|
108
|
+
unused: 0,
|
|
109
|
+
data: Buffer.from(rawPublicKey, "hex")
|
|
110
|
+
};
|
|
111
|
+
return privateKeyObject;
|
|
112
|
+
}
|
|
113
|
+
publicKeyObject(rawPublicKey) {
|
|
114
|
+
return {
|
|
115
|
+
algorithm: {
|
|
116
|
+
id: this.algorithmID,
|
|
117
|
+
curve: this.options.curveParameters
|
|
118
|
+
},
|
|
119
|
+
pub: {
|
|
120
|
+
unused: 0,
|
|
121
|
+
data: Buffer.from(rawPublicKey, "hex")
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
encodePrivate(privateKey, originalFormat, destinationFormat, destinationFormatType = "pkcs1") {
|
|
126
|
+
let privateKeyObject;
|
|
127
|
+
switch (originalFormat) {
|
|
128
|
+
case "raw": {
|
|
129
|
+
if (typeof privateKey !== "string") throw new Error("private key must be a string");
|
|
130
|
+
const rawPublicKey = this.options.curve.keyFromPrivate(privateKey, "hex").getPublic("hex");
|
|
131
|
+
privateKeyObject = this.privateKeyObject(privateKey, rawPublicKey);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case "der":
|
|
135
|
+
if (typeof privateKey === "string") privateKey = Buffer.from(privateKey, "hex");
|
|
136
|
+
privateKeyObject = ECPrivateKeyASN.decode(privateKey, "der");
|
|
137
|
+
break;
|
|
138
|
+
case "pem":
|
|
139
|
+
if (typeof privateKey !== "string") throw new Error("private key must be a string");
|
|
140
|
+
privateKeyObject = ECPrivateKeyASN.decode(privateKey, "pem", this.options.privatePEMOptions);
|
|
141
|
+
break;
|
|
142
|
+
default: throw new Error("invalid private key format");
|
|
143
|
+
}
|
|
144
|
+
switch (destinationFormat) {
|
|
145
|
+
case "raw":
|
|
146
|
+
if (destinationFormatType === "pkcs1") return privateKeyObject.privateKey.toString("hex");
|
|
147
|
+
else if (destinationFormatType === "pkcs8") return this.PKCS1toPKCS8(privateKeyObject).privateKey.privateKey.toString("hex");
|
|
148
|
+
break;
|
|
149
|
+
case "der":
|
|
150
|
+
if (destinationFormatType === "pkcs1") return ECPrivateKeyASN.encode(privateKeyObject, "der").toString("hex");
|
|
151
|
+
else if (destinationFormatType === "pkcs8") return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), "der").toString("hex");
|
|
152
|
+
break;
|
|
153
|
+
case "pem":
|
|
154
|
+
if (destinationFormatType === "pkcs1") return ECPrivateKeyASN.encode(privateKeyObject, "pem", this.options.privatePEMOptions);
|
|
155
|
+
else if (destinationFormatType === "pkcs8") return ECPrivateKey8ASN.encode(this.PKCS1toPKCS8(privateKeyObject), "pem", {
|
|
156
|
+
...this.options.privatePEMOptions,
|
|
157
|
+
label: "PRIVATE KEY"
|
|
158
|
+
});
|
|
159
|
+
break;
|
|
160
|
+
default: throw new Error("invalid destination format for private key");
|
|
161
|
+
}
|
|
162
|
+
throw new Error("unsupported destination format or type");
|
|
163
|
+
}
|
|
164
|
+
encodePublic(publicKey, originalFormat, destinationFormat) {
|
|
165
|
+
let publicKeyObject;
|
|
166
|
+
switch (originalFormat) {
|
|
167
|
+
case "raw":
|
|
168
|
+
if (typeof publicKey !== "string") throw new Error("public key must be a string");
|
|
169
|
+
publicKeyObject = this.publicKeyObject(publicKey);
|
|
170
|
+
break;
|
|
171
|
+
case "der":
|
|
172
|
+
if (typeof publicKey === "string") publicKey = Buffer.from(publicKey, "hex");
|
|
173
|
+
publicKeyObject = SubjectPublicKeyInfoASN.decode(publicKey, "der");
|
|
174
|
+
break;
|
|
175
|
+
case "pem":
|
|
176
|
+
if (typeof publicKey !== "string") throw new Error("public key must be a string");
|
|
177
|
+
publicKeyObject = SubjectPublicKeyInfoASN.decode(publicKey, "pem", this.options.publicPEMOptions);
|
|
178
|
+
break;
|
|
179
|
+
default: throw new Error("invalid public key format");
|
|
180
|
+
}
|
|
181
|
+
switch (destinationFormat) {
|
|
182
|
+
case "raw": return publicKeyObject.pub.data.toString("hex");
|
|
183
|
+
case "der": return SubjectPublicKeyInfoASN.encode(publicKeyObject, "der").toString("hex");
|
|
184
|
+
case "pem": return SubjectPublicKeyInfoASN.encode(publicKeyObject, "pem", this.options.publicPEMOptions);
|
|
185
|
+
default: throw new Error("invalid destination format for public key");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/crypto/utils.ts
|
|
191
|
+
function extractPublicKey(pemKey) {
|
|
192
|
+
const pem = pemKey.split("\n");
|
|
193
|
+
pem.shift();
|
|
194
|
+
pem.pop();
|
|
195
|
+
return Buffer.from(pem.join(""), "base64").slice(26).toString("hex").toUpperCase();
|
|
196
|
+
}
|
|
197
|
+
function hexToPem(hexString, { isPrivate = true } = {}) {
|
|
198
|
+
const keyEncoder = new KeyEncoder("p256");
|
|
199
|
+
if (isPrivate) return keyEncoder.encodePrivate(hexString, "raw", "pem");
|
|
200
|
+
return keyEncoder.encodePublic(hexString, "raw", "pem");
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* If `entropy` is passed, will generate keys pair deterministically
|
|
204
|
+
* else, random keys pair generated
|
|
205
|
+
*/
|
|
206
|
+
function genKeys(entropy) {
|
|
207
|
+
if (entropy) {
|
|
208
|
+
const ec = new elliptic.ec("p256");
|
|
209
|
+
const hashedEntropy = crypto.createHash("sha256").update(entropy).digest("hex");
|
|
210
|
+
const keyPair = ec.genKeyPair({ entropy: Buffer.from(hashedEntropy, "hex") });
|
|
211
|
+
return {
|
|
212
|
+
privateKey: String(hexToPem(keyPair.getPrivate("hex"))),
|
|
213
|
+
publicKey: String(hexToPem(keyPair.getPublic("hex"), { isPrivate: false })),
|
|
214
|
+
hexPubKey: extractPublicKey(String(hexToPem(keyPair.getPublic("hex"), { isPrivate: false })))
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("ec", {
|
|
218
|
+
namedCurve: "P-256",
|
|
219
|
+
publicKeyEncoding: {
|
|
220
|
+
type: "spki",
|
|
221
|
+
format: "pem"
|
|
222
|
+
},
|
|
223
|
+
privateKeyEncoding: {
|
|
224
|
+
type: "sec1",
|
|
225
|
+
format: "pem"
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
return {
|
|
229
|
+
privateKey,
|
|
230
|
+
publicKey,
|
|
231
|
+
hexPubKey: extractPublicKey(publicKey)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const sign = async (privateKeyPem, base64Challenge) => {
|
|
235
|
+
const challengeDataBytes = jose.base64url.decode(base64Challenge);
|
|
236
|
+
const privateKey = crypto.createPrivateKey(privateKeyPem);
|
|
237
|
+
return await new jose.CompactSign(challengeDataBytes).setProtectedHeader({
|
|
238
|
+
alg: "ES256",
|
|
239
|
+
typ: "JWT"
|
|
240
|
+
}).sign(privateKey);
|
|
241
|
+
};
|
|
242
|
+
//#endregion
|
|
243
|
+
export { sign as n, genSeed as r, genKeys as t };
|
|
244
|
+
|
|
245
|
+
//# sourceMappingURL=crypto-CPCBrCSZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-CPCBrCSZ.js","names":[],"sources":["../src/crypto/gen-seed.ts","../src/crypto/key-encoder.ts","../src/crypto/utils.ts"],"sourcesContent":["import { sha256 } from \"@noble/hashes/sha2.js\";\nimport { entropyToMnemonic } 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","// ========================================================================== //\n// //\n// DISCLAIMER //\n// //\n// This code has been blindly copy-pasted from: //\n// https://github.com/LedgerHQ/pkey-ts //\n// //\n// ========================================================================== //\n//\n// @ts-expect-error this library does not ship types\nimport asn1 from \"asn1.js\";\nimport BN from \"bn.js\";\nimport elliptic from \"elliptic\";\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: elliptic.ec;\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: new elliptic.ec(\"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: new elliptic.ec(\"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 keyPair = this.options.curve.keyFromPrivate(privateKey, \"hex\");\n const rawPublicKey = keyPair.getPublic(\"hex\");\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 elliptic from \"elliptic\";\nimport * as jose from \"jose\";\n\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 ec = new elliptic.ec(\"p256\");\n const hashedEntropy = crypto.createHash(\"sha256\").update(entropy).digest(\"hex\");\n const keyPair = ec.genKeyPair({\n entropy: Buffer.from(hashedEntropy, \"hex\"),\n });\n return {\n privateKey: String(hexToPem(keyPair.getPrivate(\"hex\"))),\n publicKey: String(hexToPem(keyPair.getPublic(\"hex\"), { isPrivate: false })),\n hexPubKey: extractPublicKey(String(hexToPem(keyPair.getPublic(\"hex\"), { 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 await new jose.CompactSign(challengeDataBytes)\n .setProtectedHeader({ alg: \"ES256\", typ: \"JWT\" })\n .sign(privateKey);\n};\n"],"mappings":"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"}
|
package/lib/crypto.cjs
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
exports.genKeys = _chunk2WGM7EWAcjs.genKeys; exports.genSeed = _chunk2WGM7EWAcjs.genSeed; exports.sign = _chunk2WGM7EWAcjs.sign;
|
|
11
|
-
//# sourceMappingURL=crypto.cjs.map
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_crypto = require("./crypto-BDBF_rfw.cjs");
|
|
3
|
+
exports.genKeys = require_crypto.genKeys;
|
|
4
|
+
exports.genSeed = require_crypto.genSeed;
|
|
5
|
+
exports.sign = require_crypto.sign;
|
package/lib/crypto.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/crypto/gen-seed.d.ts
|
|
1
2
|
/**
|
|
2
3
|
* Generate a deterministic BIP39 mnemonic from a salt and device index.
|
|
3
4
|
*
|
|
@@ -9,18 +10,20 @@
|
|
|
9
10
|
* @returns A 24-word BIP39 mnemonic string
|
|
10
11
|
*/
|
|
11
12
|
declare function genSeed(salt: string, index: number): string;
|
|
12
|
-
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/crypto/types.d.ts
|
|
13
15
|
type GeneratedKeys = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
privateKey: string;
|
|
17
|
+
publicKey: string;
|
|
18
|
+
hexPubKey: string;
|
|
17
19
|
};
|
|
18
|
-
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/crypto/utils.d.ts
|
|
19
22
|
/**
|
|
20
23
|
* If `entropy` is passed, will generate keys pair deterministically
|
|
21
24
|
* else, random keys pair generated
|
|
22
25
|
*/
|
|
23
26
|
declare function genKeys(entropy?: string): GeneratedKeys;
|
|
24
27
|
declare const sign: (privateKeyPem: string, base64Challenge: string) => Promise<string>;
|
|
25
|
-
|
|
26
|
-
export { type GeneratedKeys, genKeys, genSeed, sign };
|
|
28
|
+
//#endregion
|
|
29
|
+
export { type GeneratedKeys, genKeys, genSeed, sign };
|