@ledgerhq/hw-ledger-key-ring-protocol 0.2.1-nightly.0 → 0.2.1-spl-test.0
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +3 -3
- package/lib/ApduDevice.d.ts.map +1 -1
- package/lib/ApduDevice.js +37 -41
- package/lib/ApduDevice.js.map +1 -1
- package/lib/CommandBlock.d.ts +4 -4
- package/lib/CommandBlock.d.ts.map +1 -1
- package/lib/CommandBlock.js +18 -35
- package/lib/CommandBlock.js.map +1 -1
- package/lib/CommandStream.d.ts +1 -1
- package/lib/CommandStream.d.ts.map +1 -1
- package/lib/CommandStream.js +5 -7
- package/lib/CommandStream.js.map +1 -1
- package/lib/Crypto.d.ts +11 -11
- package/lib/Crypto.d.ts.map +1 -1
- package/lib/Device.d.ts +1 -1
- package/lib/Device.d.ts.map +1 -1
- package/lib/Device.js +28 -36
- package/lib/Device.js.map +1 -1
- package/lib/NobleCrypto.d.ts +13 -15
- package/lib/NobleCrypto.d.ts.map +1 -1
- package/lib/NobleCrypto.js +90 -148
- package/lib/NobleCrypto.js.map +1 -1
- package/lib/StreamTreeCipher.d.ts.map +1 -1
- package/lib/StreamTreeCipher.js +32 -36
- package/lib/StreamTreeCipher.js.map +1 -1
- package/lib/__tests__/codec.js +33 -33
- package/lib/__tests__/codec.js.map +1 -1
- package/lib-es/ApduDevice.d.ts.map +1 -1
- package/lib-es/ApduDevice.js +37 -41
- package/lib-es/ApduDevice.js.map +1 -1
- package/lib-es/CommandBlock.d.ts +4 -4
- package/lib-es/CommandBlock.d.ts.map +1 -1
- package/lib-es/CommandBlock.js +18 -35
- package/lib-es/CommandBlock.js.map +1 -1
- package/lib-es/CommandStream.d.ts +1 -1
- package/lib-es/CommandStream.d.ts.map +1 -1
- package/lib-es/CommandStream.js +5 -7
- package/lib-es/CommandStream.js.map +1 -1
- package/lib-es/Crypto.d.ts +11 -11
- package/lib-es/Crypto.d.ts.map +1 -1
- package/lib-es/Device.d.ts +1 -1
- package/lib-es/Device.d.ts.map +1 -1
- package/lib-es/Device.js +28 -36
- package/lib-es/Device.js.map +1 -1
- package/lib-es/NobleCrypto.d.ts +13 -15
- package/lib-es/NobleCrypto.d.ts.map +1 -1
- package/lib-es/NobleCrypto.js +90 -148
- package/lib-es/NobleCrypto.js.map +1 -1
- package/lib-es/StreamTreeCipher.d.ts.map +1 -1
- package/lib-es/StreamTreeCipher.js +32 -36
- package/lib-es/StreamTreeCipher.js.map +1 -1
- package/lib-es/__tests__/codec.js +33 -33
- package/lib-es/__tests__/codec.js.map +1 -1
- package/package.json +2 -2
- package/src/ApduDevice.ts +10 -14
- package/src/CommandBlock.ts +11 -14
- package/src/CommandStream.ts +6 -8
- package/src/Crypto.ts +11 -11
- package/src/Device.ts +26 -34
- package/src/NobleCrypto.ts +20 -59
- package/src/StreamTreeCipher.ts +15 -15
- package/src/__tests__/codec.ts +32 -32
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/__tests__/codec.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,IAAI,EACJ,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAEnC,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,EAAE,CAAC,iCAAiC,EAAE,
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/__tests__/codec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/hw-ledger-key-ring-protocol",
|
|
3
|
-
"version": "0.2.1-
|
|
3
|
+
"version": "0.2.1-spl-test.0",
|
|
4
4
|
"description": "Ledger Key Ring Protocol hardware layer",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ledger"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"tiny-secp256k1": "1",
|
|
25
25
|
"@ledgerhq/hw-transport": "6.31.4",
|
|
26
26
|
"@ledgerhq/logs": "6.12.0",
|
|
27
|
-
"@ledgerhq/live-env": "2.4.1-
|
|
27
|
+
"@ledgerhq/live-env": "2.4.1-spl-test.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/lodash": "4",
|
package/src/ApduDevice.ts
CHANGED
|
@@ -389,20 +389,16 @@ export class APDU {
|
|
|
389
389
|
}
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
-
|
|
392
|
+
function injectTrustedProperties(
|
|
393
393
|
command: Command,
|
|
394
394
|
properties: CommandResponse,
|
|
395
395
|
secret: Uint8Array,
|
|
396
|
-
):
|
|
396
|
+
): Command {
|
|
397
397
|
switch (command.getType()) {
|
|
398
398
|
case CommandType.Seed: {
|
|
399
399
|
const seedCommand = command as Seed;
|
|
400
400
|
const seedProperties = properties as SeedCommandResponse;
|
|
401
|
-
seedCommand.encryptedXpriv =
|
|
402
|
-
secret,
|
|
403
|
-
seedProperties.iv,
|
|
404
|
-
seedProperties.xpriv,
|
|
405
|
-
);
|
|
401
|
+
seedCommand.encryptedXpriv = crypto.decrypt(secret, seedProperties.iv, seedProperties.xpriv);
|
|
406
402
|
seedCommand.ephemeralPublicKey = seedProperties.ephemeralPublicKey;
|
|
407
403
|
seedCommand.initializationVector = seedProperties.commandIv;
|
|
408
404
|
seedCommand.groupKey = seedProperties.groupKey;
|
|
@@ -411,7 +407,7 @@ async function injectTrustedProperties(
|
|
|
411
407
|
case CommandType.Derive: {
|
|
412
408
|
const deriveCommand = command as Derive;
|
|
413
409
|
const deriveProperties = properties as SeedCommandResponse;
|
|
414
|
-
deriveCommand.encryptedXpriv =
|
|
410
|
+
deriveCommand.encryptedXpriv = crypto.decrypt(
|
|
415
411
|
secret,
|
|
416
412
|
deriveProperties.iv,
|
|
417
413
|
deriveProperties.xpriv,
|
|
@@ -428,7 +424,7 @@ async function injectTrustedProperties(
|
|
|
428
424
|
const publishKeyProperties = properties as PublishKeyCommandResponse;
|
|
429
425
|
publishKeyCommand.ephemeralPublicKey = publishKeyProperties.ephemeralPublicKey;
|
|
430
426
|
publishKeyCommand.initializationVector = publishKeyProperties.commandIv;
|
|
431
|
-
publishKeyCommand.encryptedXpriv =
|
|
427
|
+
publishKeyCommand.encryptedXpriv = crypto.decrypt(
|
|
432
428
|
secret,
|
|
433
429
|
publishKeyProperties.iv,
|
|
434
430
|
publishKeyProperties.xpriv,
|
|
@@ -449,7 +445,7 @@ findTrustedMember;
|
|
|
449
445
|
|
|
450
446
|
export class ApduDevice implements Device {
|
|
451
447
|
private transport: Transport;
|
|
452
|
-
private sessionKeyPair:
|
|
448
|
+
private sessionKeyPair: KeyPair;
|
|
453
449
|
|
|
454
450
|
constructor(transport: Transport) {
|
|
455
451
|
this.transport = transport;
|
|
@@ -465,7 +461,7 @@ export class ApduDevice implements Device {
|
|
|
465
461
|
return new PublicKey(publicKey);
|
|
466
462
|
}
|
|
467
463
|
|
|
468
|
-
|
|
464
|
+
getSeedId(data: Uint8Array): Promise<SeedIdResult> {
|
|
469
465
|
return APDU.getSeedId(this.transport, data);
|
|
470
466
|
}
|
|
471
467
|
|
|
@@ -614,7 +610,7 @@ export class ApduDevice implements Device {
|
|
|
614
610
|
}
|
|
615
611
|
|
|
616
612
|
async sign(stream: CommandBlock[]): Promise<CommandBlock> {
|
|
617
|
-
const sessionKey =
|
|
613
|
+
const sessionKey = this.sessionKeyPair;
|
|
618
614
|
const trustedProperties: CommandResponse[] = [];
|
|
619
615
|
|
|
620
616
|
// We expect the stream to have a single block to sign (the last one)
|
|
@@ -649,8 +645,8 @@ export class ApduDevice implements Device {
|
|
|
649
645
|
const signature = await APDU.finalizeSignature(this.transport);
|
|
650
646
|
|
|
651
647
|
// Decrypt and inject trusted issuer
|
|
652
|
-
const secret =
|
|
653
|
-
const issuer =
|
|
648
|
+
const secret = crypto.ecdh(sessionKey, signature.sessionKey);
|
|
649
|
+
const issuer = crypto.decrypt(secret, trustedIssuer.iv, trustedIssuer.issuer);
|
|
654
650
|
|
|
655
651
|
// Inject trusted properties for commands
|
|
656
652
|
for (let commandIndex = 0; commandIndex < blockToSign.commands.length; commandIndex++) {
|
package/src/CommandBlock.ts
CHANGED
|
@@ -202,14 +202,14 @@ export interface CommandBlock {
|
|
|
202
202
|
* @param parent The parent command block hash (if null, the block is the first block and a parent will be generated)
|
|
203
203
|
* @returns
|
|
204
204
|
*/
|
|
205
|
-
export
|
|
205
|
+
export function createCommandBlock(
|
|
206
206
|
issuer: Uint8Array,
|
|
207
207
|
commands: Command[],
|
|
208
208
|
signature: Uint8Array = new Uint8Array(),
|
|
209
209
|
parent: Uint8Array | null = null,
|
|
210
|
-
):
|
|
210
|
+
): CommandBlock {
|
|
211
211
|
if (parent === null) {
|
|
212
|
-
parent = parent =
|
|
212
|
+
parent = parent = crypto.randomBytes(32);
|
|
213
213
|
}
|
|
214
214
|
return {
|
|
215
215
|
version: 1,
|
|
@@ -220,28 +220,25 @@ export async function createCommandBlock(
|
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
export
|
|
223
|
+
export function signCommandBlock(
|
|
224
224
|
block: CommandBlock,
|
|
225
225
|
issuer: Uint8Array,
|
|
226
226
|
secretKey: Uint8Array,
|
|
227
|
-
):
|
|
228
|
-
const signature =
|
|
229
|
-
await hashCommandBlock(block),
|
|
230
|
-
await crypto.keypairFromSecretKey(secretKey),
|
|
231
|
-
);
|
|
227
|
+
): CommandBlock {
|
|
228
|
+
const signature = crypto.sign(hashCommandBlock(block), crypto.keypairFromSecretKey(secretKey));
|
|
232
229
|
return {
|
|
233
230
|
...block,
|
|
234
231
|
signature,
|
|
235
232
|
};
|
|
236
233
|
}
|
|
237
234
|
|
|
238
|
-
export
|
|
239
|
-
return
|
|
235
|
+
export function hashCommandBlock(block: CommandBlock): Uint8Array {
|
|
236
|
+
return crypto.hash(CommandStreamEncoder.encode([block]));
|
|
240
237
|
}
|
|
241
238
|
|
|
242
|
-
export
|
|
239
|
+
export function verifyCommandBlock(block: CommandBlock): boolean {
|
|
243
240
|
const unsignedBlock = { ...block };
|
|
244
241
|
unsignedBlock.signature = new Uint8Array();
|
|
245
|
-
const hash =
|
|
246
|
-
return
|
|
242
|
+
const hash = hashCommandBlock(unsignedBlock);
|
|
243
|
+
return crypto.verify(hash, block.signature, block.issuer);
|
|
247
244
|
}
|
package/src/CommandStream.ts
CHANGED
|
@@ -132,9 +132,9 @@ export class CommandStreamIssuer {
|
|
|
132
132
|
): Promise<CommandStream> {
|
|
133
133
|
const lastBlockHash =
|
|
134
134
|
this._stream.blocks.length > 0
|
|
135
|
-
?
|
|
135
|
+
? hashCommandBlock(this._stream.blocks[this._stream.blocks.length - 1])
|
|
136
136
|
: null;
|
|
137
|
-
const block =
|
|
137
|
+
const block = createCommandBlock(
|
|
138
138
|
ISSUER_PLACEHOLDER,
|
|
139
139
|
[],
|
|
140
140
|
new Uint8Array(),
|
|
@@ -167,7 +167,7 @@ export default class CommandStream {
|
|
|
167
167
|
return CommandStreamResolver.resolve(this._blocks);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
public getRootHash():
|
|
170
|
+
public getRootHash(): Uint8Array {
|
|
171
171
|
return hashCommandBlock(this._blocks[0]);
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -211,7 +211,7 @@ export default class CommandStream {
|
|
|
211
211
|
if (block.commands[0].getType() === CommandType.Derive) {
|
|
212
212
|
// Set the parent hash of the block to the root hash
|
|
213
213
|
const b = { ...block };
|
|
214
|
-
b.parent =
|
|
214
|
+
b.parent = hashCommandBlock(stream[0]);
|
|
215
215
|
stream = stream.concat([b]);
|
|
216
216
|
} else {
|
|
217
217
|
stream = stream.concat([block]);
|
|
@@ -227,10 +227,8 @@ export default class CommandStream {
|
|
|
227
227
|
parentHash: Uint8Array | null = null,
|
|
228
228
|
): Promise<CommandStream> {
|
|
229
229
|
const lastBlockHash =
|
|
230
|
-
this._blocks.length > 0
|
|
231
|
-
|
|
232
|
-
: null;
|
|
233
|
-
const block = await createCommandBlock(
|
|
230
|
+
this._blocks.length > 0 ? hashCommandBlock(this._blocks[this._blocks.length - 1]) : null;
|
|
231
|
+
const block = createCommandBlock(
|
|
234
232
|
ISSUER_PLACEHOLDER,
|
|
235
233
|
commands,
|
|
236
234
|
new Uint8Array(),
|
package/src/Crypto.ts
CHANGED
|
@@ -13,19 +13,19 @@ export interface KeyPairWithChainCode extends KeyPair {
|
|
|
13
13
|
*
|
|
14
14
|
*/
|
|
15
15
|
export interface Crypto {
|
|
16
|
-
randomKeypair():
|
|
17
|
-
keypairFromSecretKey(secretKey: Uint8Array):
|
|
18
|
-
sign(message: Uint8Array, keyPair: KeyPair):
|
|
19
|
-
verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array):
|
|
20
|
-
encrypt(secret: Uint8Array, nonce: Uint8Array, message: Uint8Array):
|
|
21
|
-
decrypt(secret: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array):
|
|
22
|
-
randomBytes(size: number):
|
|
23
|
-
ecdh(keyPair: KeyPair, publicKey: Uint8Array):
|
|
24
|
-
hash(message: Uint8Array):
|
|
25
|
-
computeSymmetricKey(privateKey: Uint8Array, extra: Uint8Array):
|
|
16
|
+
randomKeypair(): KeyPair;
|
|
17
|
+
keypairFromSecretKey(secretKey: Uint8Array): KeyPair;
|
|
18
|
+
sign(message: Uint8Array, keyPair: KeyPair): Uint8Array;
|
|
19
|
+
verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean;
|
|
20
|
+
encrypt(secret: Uint8Array, nonce: Uint8Array, message: Uint8Array): Uint8Array;
|
|
21
|
+
decrypt(secret: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array): Uint8Array;
|
|
22
|
+
randomBytes(size: number): Uint8Array;
|
|
23
|
+
ecdh(keyPair: KeyPair, publicKey: Uint8Array): Uint8Array;
|
|
24
|
+
hash(message: Uint8Array): Uint8Array;
|
|
25
|
+
computeSymmetricKey(privateKey: Uint8Array, extra: Uint8Array): Uint8Array;
|
|
26
26
|
from_hex(hex: string): Uint8Array;
|
|
27
27
|
to_hex(bytes?: Uint8Array): string;
|
|
28
|
-
derivePrivate(xpriv: Uint8Array, path: number[]):
|
|
28
|
+
derivePrivate(xpriv: Uint8Array, path: number[]): KeyPairWithChainCode;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export class DerivationPath {
|
package/src/Device.ts
CHANGED
|
@@ -61,20 +61,17 @@ export class SoftwareDevice implements Device {
|
|
|
61
61
|
return new PublicKey(this.keyPair.publicKey);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
private
|
|
65
|
-
const xpriv =
|
|
66
|
-
const pk =
|
|
64
|
+
private generateSharedKey(): SharedKey {
|
|
65
|
+
const xpriv = crypto.randomBytes(64);
|
|
66
|
+
const pk = crypto.derivePrivate(xpriv, []);
|
|
67
67
|
return { xpriv, publicKey: pk.publicKey };
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
private
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
const ecdh = await crypto.ecdh(kp, recipient);
|
|
76
|
-
const initializationVector = await crypto.randomBytes(16);
|
|
77
|
-
const encryptedXpriv = await crypto.encrypt(ecdh, initializationVector, sharedKey.xpriv);
|
|
70
|
+
private encryptSharedKey(sharedKey: SharedKey, recipient: Uint8Array): EncryptedSharedKey {
|
|
71
|
+
const kp = crypto.randomKeypair();
|
|
72
|
+
const ecdh = crypto.ecdh(kp, recipient);
|
|
73
|
+
const initializationVector = crypto.randomBytes(16);
|
|
74
|
+
const encryptedXpriv = crypto.encrypt(ecdh, initializationVector, sharedKey.xpriv);
|
|
78
75
|
return {
|
|
79
76
|
encryptedXpriv,
|
|
80
77
|
publicKey: sharedKey.publicKey,
|
|
@@ -83,9 +80,9 @@ export class SoftwareDevice implements Device {
|
|
|
83
80
|
};
|
|
84
81
|
}
|
|
85
82
|
|
|
86
|
-
private
|
|
87
|
-
const ecdh =
|
|
88
|
-
const xpriv =
|
|
83
|
+
private decryptSharedKey(encryptedSharedKey: EncryptedSharedKey): SharedKey {
|
|
84
|
+
const ecdh = crypto.ecdh(this.keyPair, encryptedSharedKey.ephemeralPublicKey);
|
|
85
|
+
const xpriv = crypto.decrypt(
|
|
89
86
|
ecdh,
|
|
90
87
|
encryptedSharedKey.initializationVector,
|
|
91
88
|
encryptedSharedKey.encryptedXpriv,
|
|
@@ -104,8 +101,8 @@ export class SoftwareDevice implements Device {
|
|
|
104
101
|
ephemeralPublicKey: event.ephemeralPublicKey,
|
|
105
102
|
initializationVector: event.nonce,
|
|
106
103
|
};
|
|
107
|
-
const sharedKey =
|
|
108
|
-
const newKey =
|
|
104
|
+
const sharedKey = this.decryptSharedKey(encryptedSharedKey);
|
|
105
|
+
const newKey = crypto.derivePrivate(sharedKey.xpriv, path);
|
|
109
106
|
const xpriv = new Uint8Array(64);
|
|
110
107
|
xpriv.set(newKey.privateKey);
|
|
111
108
|
xpriv.set(newKey.chainCode, 32);
|
|
@@ -136,10 +133,10 @@ export class SoftwareDevice implements Device {
|
|
|
136
133
|
switch (command.getType()) {
|
|
137
134
|
case CommandType.Seed: {
|
|
138
135
|
// Generate the shared key
|
|
139
|
-
sharedKey =
|
|
136
|
+
sharedKey = this.generateSharedKey();
|
|
140
137
|
|
|
141
138
|
// Encrypt the shared key and inject it in the command
|
|
142
|
-
const encryptedSharedKey =
|
|
139
|
+
const encryptedSharedKey = this.encryptSharedKey(sharedKey, this.keyPair.publicKey);
|
|
143
140
|
(command as Seed).groupKey = sharedKey.publicKey;
|
|
144
141
|
(command as Seed).encryptedXpriv = encryptedSharedKey.encryptedXpriv;
|
|
145
142
|
(command as Seed).ephemeralPublicKey = encryptedSharedKey.ephemeralPublicKey;
|
|
@@ -154,10 +151,7 @@ export class SoftwareDevice implements Device {
|
|
|
154
151
|
sharedKey = await this.deriveKey(tree, (command as Derive).path);
|
|
155
152
|
|
|
156
153
|
// Encrypt the shared key and inject it in the command
|
|
157
|
-
const encryptedDerivedKey =
|
|
158
|
-
sharedKey,
|
|
159
|
-
this.keyPair.publicKey,
|
|
160
|
-
);
|
|
154
|
+
const encryptedDerivedKey = this.encryptSharedKey(sharedKey, this.keyPair.publicKey);
|
|
161
155
|
(command as Derive).groupKey = sharedKey.publicKey;
|
|
162
156
|
(command as Derive).encryptedXpriv = encryptedDerivedKey.encryptedXpriv;
|
|
163
157
|
(command as Derive).initializationVector = encryptedDerivedKey.initializationVector;
|
|
@@ -170,7 +164,7 @@ export class SoftwareDevice implements Device {
|
|
|
170
164
|
// If the current stream is the seed stream, read the key from the first command in the first block
|
|
171
165
|
const encryptedKey = resolved.getEncryptedKey(this.keyPair.publicKey);
|
|
172
166
|
if (encryptedKey) {
|
|
173
|
-
sharedKey =
|
|
167
|
+
sharedKey = this.decryptSharedKey({
|
|
174
168
|
encryptedXpriv: encryptedKey.encryptedXpriv,
|
|
175
169
|
initializationVector: encryptedKey.initialiationVector,
|
|
176
170
|
publicKey: encryptedKey.issuer,
|
|
@@ -186,7 +180,7 @@ export class SoftwareDevice implements Device {
|
|
|
186
180
|
}
|
|
187
181
|
if (!sharedKey) throw new Error("Cannot find the shared key");
|
|
188
182
|
}
|
|
189
|
-
const encryptedSharedKey =
|
|
183
|
+
const encryptedSharedKey = this.encryptSharedKey(
|
|
190
184
|
sharedKey!,
|
|
191
185
|
(command as PublishKey).recipient,
|
|
192
186
|
);
|
|
@@ -197,12 +191,10 @@ export class SoftwareDevice implements Device {
|
|
|
197
191
|
}
|
|
198
192
|
}
|
|
199
193
|
}
|
|
200
|
-
const signature = (
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
this.keyPair.privateKey,
|
|
205
|
-
)
|
|
194
|
+
const signature = signCommandBlock(
|
|
195
|
+
lastBlock,
|
|
196
|
+
(await this.getPublicKey()).publicKey,
|
|
197
|
+
this.keyPair.privateKey,
|
|
206
198
|
).signature;
|
|
207
199
|
lastBlock.signature = signature;
|
|
208
200
|
return lastBlock;
|
|
@@ -219,12 +211,12 @@ export class SoftwareDevice implements Device {
|
|
|
219
211
|
publicKey: event.groupPublicKey,
|
|
220
212
|
ephemeralPublicKey: event.ephemeralPublicKey,
|
|
221
213
|
};
|
|
222
|
-
const sharedKey =
|
|
214
|
+
const sharedKey = this.decryptSharedKey(encryptedSharedKey);
|
|
223
215
|
|
|
224
216
|
// Derive the key to match the path
|
|
225
217
|
let index = DerivationPath.toIndexArray(event.stream.getStreamPath()!).length;
|
|
226
218
|
while (index < path.length) {
|
|
227
|
-
const derivation =
|
|
219
|
+
const derivation = crypto.derivePrivate(sharedKey.xpriv, [index]);
|
|
228
220
|
const xpriv = new Uint8Array(64);
|
|
229
221
|
xpriv.set(derivation.privateKey);
|
|
230
222
|
xpriv.set(derivation.chainCode, 32);
|
|
@@ -244,8 +236,8 @@ export class SoftwareDevice implements Device {
|
|
|
244
236
|
/**
|
|
245
237
|
*
|
|
246
238
|
*/
|
|
247
|
-
export
|
|
248
|
-
const kp =
|
|
239
|
+
export function createDevice(): Device {
|
|
240
|
+
const kp = crypto.randomKeypair();
|
|
249
241
|
return new SoftwareDevice(kp);
|
|
250
242
|
}
|
|
251
243
|
|
package/src/NobleCrypto.ts
CHANGED
|
@@ -11,7 +11,7 @@ const AES_BLOCK_SIZE = 16;
|
|
|
11
11
|
const PRIVATE_KEY_SIZE = 32;
|
|
12
12
|
|
|
13
13
|
export class NobleCryptoSecp256k1 implements Crypto {
|
|
14
|
-
|
|
14
|
+
randomKeypair(): KeyPair {
|
|
15
15
|
let pk: Uint8Array;
|
|
16
16
|
do {
|
|
17
17
|
pk = crypto.randomBytes(PRIVATE_KEY_SIZE);
|
|
@@ -19,7 +19,7 @@ export class NobleCryptoSecp256k1 implements Crypto {
|
|
|
19
19
|
return this.keypairFromSecretKey(pk);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
derivePrivate(xpriv: Uint8Array, path: number[]): KeyPairWithChainCode {
|
|
23
23
|
const pk = xpriv.slice(0, 32);
|
|
24
24
|
const chainCode = xpriv.slice(32);
|
|
25
25
|
let node = bip32.fromPrivateKey(Buffer.from(pk), Buffer.from(chainCode));
|
|
@@ -33,7 +33,7 @@ export class NobleCryptoSecp256k1 implements Crypto {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
keypairFromSecretKey(secretKey: Uint8Array): KeyPair {
|
|
37
37
|
return {
|
|
38
38
|
publicKey: secp256k1.publicKeyCreate(secretKey),
|
|
39
39
|
privateKey: secretKey,
|
|
@@ -65,17 +65,13 @@ export class NobleCryptoSecp256k1 implements Crypto {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
sign(message: Uint8Array, keyPair: KeyPair): Uint8Array {
|
|
69
69
|
const signature = secp256k1.ecdsaSign(message, keyPair.privateKey).signature;
|
|
70
70
|
// DER encoding
|
|
71
71
|
return this.derEncode(signature.slice(0, 32), signature.slice(32, 64));
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
message: Uint8Array,
|
|
76
|
-
signature: Uint8Array,
|
|
77
|
-
publicKey: Uint8Array,
|
|
78
|
-
): Promise<boolean> {
|
|
74
|
+
verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean {
|
|
79
75
|
// DER decoding
|
|
80
76
|
const { R, S } = this.derDecode(signature);
|
|
81
77
|
return secp256k1.ecdsaVerify(this.concat(R, S), message, publicKey);
|
|
@@ -121,32 +117,7 @@ export class NobleCryptoSecp256k1 implements Crypto {
|
|
|
121
117
|
return buffer;
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
|
|
125
|
-
// ISO9797M2 implementation
|
|
126
|
-
const padLength = AES_BLOCK_SIZE - (message.length % AES_BLOCK_SIZE);
|
|
127
|
-
if (padLength === AES_BLOCK_SIZE) {
|
|
128
|
-
return message;
|
|
129
|
-
}
|
|
130
|
-
const padding = new Uint8Array(padLength);
|
|
131
|
-
padding[0] = 0x80;
|
|
132
|
-
padding.fill(0, 1);
|
|
133
|
-
return this.concat(message, padding);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private unpad(message: Uint8Array): Uint8Array {
|
|
137
|
-
// ISO9797M2 implementation
|
|
138
|
-
for (let i = message.length - 1; i >= 0; i--) {
|
|
139
|
-
if (message[i] === 0x80) {
|
|
140
|
-
return message.slice(0, i);
|
|
141
|
-
}
|
|
142
|
-
if (message[i] !== 0x00) {
|
|
143
|
-
return message;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
throw new Error("Invalid padding");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async encrypt(secret: Uint8Array, nonce: Uint8Array, message: Uint8Array): Promise<Uint8Array> {
|
|
120
|
+
encrypt(secret: Uint8Array, nonce: Uint8Array, message: Uint8Array): Uint8Array {
|
|
150
121
|
const normalizedSecret = this.normalizeKey(secret);
|
|
151
122
|
const normalizeNonce = this.normalizeNonce(nonce);
|
|
152
123
|
const cipher = crypto.createCipheriv("aes-256-gcm", normalizedSecret, normalizeNonce);
|
|
@@ -157,11 +128,7 @@ export class NobleCryptoSecp256k1 implements Crypto {
|
|
|
157
128
|
return this.concat(bytes, cipher.getAuthTag());
|
|
158
129
|
}
|
|
159
130
|
|
|
160
|
-
|
|
161
|
-
secret: Uint8Array,
|
|
162
|
-
nonce: Uint8Array,
|
|
163
|
-
ciphertext: Uint8Array,
|
|
164
|
-
): Promise<Uint8Array> {
|
|
131
|
+
decrypt(secret: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array): Uint8Array {
|
|
165
132
|
const normalizedSecret = this.normalizeKey(secret);
|
|
166
133
|
const normalizeNonce = this.normalizeNonce(nonce);
|
|
167
134
|
const encryptedData = ciphertext.slice(0, ciphertext.length - AES_BLOCK_SIZE);
|
|
@@ -185,21 +152,18 @@ export class NobleCryptoSecp256k1 implements Crypto {
|
|
|
185
152
|
16 bytes : Tag/MAC (from AES-256-GCM)
|
|
186
153
|
variable : Encrypted data
|
|
187
154
|
*/
|
|
188
|
-
|
|
189
|
-
commandStreamPrivateKey: Uint8Array,
|
|
190
|
-
data: Uint8Array,
|
|
191
|
-
): Promise<Uint8Array> {
|
|
155
|
+
encryptUserData(commandStreamPrivateKey: Uint8Array, data: Uint8Array): Uint8Array {
|
|
192
156
|
// Generate ephemeral key pair
|
|
193
|
-
const ephemeralKeypair =
|
|
157
|
+
const ephemeralKeypair = this.randomKeypair();
|
|
194
158
|
|
|
195
159
|
// Derive the shared secret using ECDH
|
|
196
|
-
const sharedSecret =
|
|
197
|
-
|
|
160
|
+
const sharedSecret = this.ecdh(
|
|
161
|
+
this.keypairFromSecretKey(commandStreamPrivateKey),
|
|
198
162
|
ephemeralKeypair.publicKey,
|
|
199
163
|
);
|
|
200
164
|
|
|
201
165
|
// Normalize the shared secret to be used as AES key
|
|
202
|
-
const aesKey =
|
|
166
|
+
const aesKey = this.computeSymmetricKey(sharedSecret, new Uint8Array());
|
|
203
167
|
|
|
204
168
|
// Generate a random IV (nonce)
|
|
205
169
|
const iv = crypto.randomBytes(16);
|
|
@@ -223,10 +187,7 @@ variable : Encrypted data
|
|
|
223
187
|
return result;
|
|
224
188
|
}
|
|
225
189
|
|
|
226
|
-
|
|
227
|
-
commandStreamPrivateKey: Uint8Array,
|
|
228
|
-
data: Uint8Array,
|
|
229
|
-
): Promise<Uint8Array> {
|
|
190
|
+
decryptUserData(commandStreamPrivateKey: Uint8Array, data: Uint8Array): Uint8Array {
|
|
230
191
|
const version = data[0];
|
|
231
192
|
if (version !== 0x00) {
|
|
232
193
|
throw new Error("Unsupported format version");
|
|
@@ -237,13 +198,13 @@ variable : Encrypted data
|
|
|
237
198
|
const encryptedData = data.slice(66);
|
|
238
199
|
|
|
239
200
|
// Derive the shared secret using ECDH
|
|
240
|
-
const sharedSecret =
|
|
241
|
-
|
|
201
|
+
const sharedSecret = this.ecdh(
|
|
202
|
+
this.keypairFromSecretKey(commandStreamPrivateKey),
|
|
242
203
|
ephemeralPublicKey,
|
|
243
204
|
);
|
|
244
205
|
|
|
245
206
|
// Normalize the shared secret to be used as AES key
|
|
246
|
-
const aesKey =
|
|
207
|
+
const aesKey = this.computeSymmetricKey(sharedSecret, new Uint8Array());
|
|
247
208
|
|
|
248
209
|
// Decrypt the data using AES-256-GCM
|
|
249
210
|
const decipher = crypto.createDecipheriv("aes-256-gcm", aesKey, iv);
|
|
@@ -253,23 +214,23 @@ variable : Encrypted data
|
|
|
253
214
|
return new Uint8Array(decryptedData.buffer, decryptedData.byteOffset, decryptedData.byteLength);
|
|
254
215
|
}
|
|
255
216
|
|
|
256
|
-
|
|
217
|
+
randomBytes(size: number): Uint8Array {
|
|
257
218
|
return crypto.randomBytes(size);
|
|
258
219
|
}
|
|
259
220
|
|
|
260
|
-
|
|
221
|
+
ecdh(keyPair: KeyPair, publicKey: Uint8Array): Uint8Array {
|
|
261
222
|
const pubkey = Buffer.from(publicKey);
|
|
262
223
|
const privkey = Buffer.from(keyPair.privateKey);
|
|
263
224
|
const point = ecc.pointMultiply(pubkey, privkey, ecc.isPointCompressed(pubkey))!;
|
|
264
225
|
return point.slice(1);
|
|
265
226
|
}
|
|
266
227
|
|
|
267
|
-
|
|
228
|
+
computeSymmetricKey(privateKey: Uint8Array, extra: Uint8Array) {
|
|
268
229
|
const digest = hmac("sha256", Buffer.from(extra)).update(Buffer.from(privateKey)).digest();
|
|
269
230
|
return digest;
|
|
270
231
|
}
|
|
271
232
|
|
|
272
|
-
|
|
233
|
+
hash(message: Uint8Array): Uint8Array {
|
|
273
234
|
return crypto.createHash("sha256").update(Buffer.from(message)).digest();
|
|
274
235
|
}
|
|
275
236
|
|
package/src/StreamTreeCipher.ts
CHANGED
|
@@ -52,26 +52,26 @@ export class StreamTreeCipher {
|
|
|
52
52
|
nonce: Uint8Array | null = null,
|
|
53
53
|
): Promise<Uint8Array> {
|
|
54
54
|
if (nonce === null) {
|
|
55
|
-
nonce =
|
|
55
|
+
nonce = crypto.randomBytes(16);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// Generate ephemeral key pair
|
|
59
|
-
const ephemeralKeyPair =
|
|
59
|
+
const ephemeralKeyPair = crypto.randomKeypair();
|
|
60
60
|
|
|
61
61
|
// Get the group public key
|
|
62
62
|
const groupKeypair = await this.getGroupKeypair(tree, path);
|
|
63
63
|
|
|
64
64
|
// Compute the secret via ECDH
|
|
65
|
-
const secret =
|
|
65
|
+
const secret = crypto.ecdh(ephemeralKeyPair, groupKeypair.publicKey);
|
|
66
66
|
|
|
67
67
|
let encrypted: Uint8Array = new Uint8Array(0);
|
|
68
68
|
switch (this._mode) {
|
|
69
69
|
case StreamTreeCipherMode.AES_256_CBC: {
|
|
70
|
-
encrypted =
|
|
70
|
+
encrypted = crypto.encrypt(secret, nonce, message);
|
|
71
71
|
break;
|
|
72
72
|
}
|
|
73
73
|
case StreamTreeCipherMode.AES_256_GCM: {
|
|
74
|
-
encrypted =
|
|
74
|
+
encrypted = crypto.encrypt(secret, nonce, message);
|
|
75
75
|
break;
|
|
76
76
|
}
|
|
77
77
|
default:
|
|
@@ -97,16 +97,16 @@ export class StreamTreeCipher {
|
|
|
97
97
|
|
|
98
98
|
// Compute the relative path from the event to the path parameter
|
|
99
99
|
const privateKey = (await this._device.readKey(tree, path)).slice(0, 32);
|
|
100
|
-
const publicKey =
|
|
100
|
+
const publicKey = crypto.keypairFromSecretKey(privateKey).publicKey;
|
|
101
101
|
return { privateKey, publicKey };
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
private
|
|
104
|
+
private encodeData(
|
|
105
105
|
ephemeralPublicKey: Uint8Array,
|
|
106
106
|
nonce: Uint8Array,
|
|
107
107
|
data: Uint8Array,
|
|
108
108
|
message: Uint8Array,
|
|
109
|
-
)
|
|
109
|
+
) {
|
|
110
110
|
const result = new Uint8Array(1 + 33 + nonce.length + TAG_LENGTH + data.length);
|
|
111
111
|
let offset = 0;
|
|
112
112
|
// Version
|
|
@@ -120,7 +120,7 @@ export class StreamTreeCipher {
|
|
|
120
120
|
offset += nonce.length;
|
|
121
121
|
// Checksum
|
|
122
122
|
if (this._mode == StreamTreeCipherMode.AES_256_CBC) {
|
|
123
|
-
const checksum =
|
|
123
|
+
const checksum = this.computeChecksum(message);
|
|
124
124
|
result.set(checksum, offset);
|
|
125
125
|
offset += checksum.length;
|
|
126
126
|
}
|
|
@@ -170,20 +170,20 @@ export class StreamTreeCipher {
|
|
|
170
170
|
const checksum = decodedPayload.checksum;
|
|
171
171
|
|
|
172
172
|
const sharedKeyPair = await this.getGroupKeypair(tree, path);
|
|
173
|
-
const secret =
|
|
173
|
+
const secret = crypto.ecdh(sharedKeyPair, ephemeralKey);
|
|
174
174
|
|
|
175
175
|
let decrypted = new Uint8Array(0);
|
|
176
176
|
switch (this._mode) {
|
|
177
177
|
case StreamTreeCipherMode.AES_256_CBC: {
|
|
178
|
-
decrypted =
|
|
179
|
-
const computedChecksum =
|
|
178
|
+
decrypted = crypto.decrypt(secret, nonce, encryptedMessage);
|
|
179
|
+
const computedChecksum = this.computeChecksum(decrypted);
|
|
180
180
|
if (crypto.to_hex(computedChecksum) !== crypto.to_hex(checksum)) {
|
|
181
181
|
throw new Error("Invalid checksum");
|
|
182
182
|
}
|
|
183
183
|
break;
|
|
184
184
|
}
|
|
185
185
|
case StreamTreeCipherMode.AES_256_GCM: {
|
|
186
|
-
decrypted =
|
|
186
|
+
decrypted = crypto.decrypt(secret, nonce, encryptedMessage);
|
|
187
187
|
break;
|
|
188
188
|
}
|
|
189
189
|
default:
|
|
@@ -193,8 +193,8 @@ export class StreamTreeCipher {
|
|
|
193
193
|
return decrypted;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
private
|
|
197
|
-
const hash =
|
|
196
|
+
private computeChecksum(message: Uint8Array): Uint8Array {
|
|
197
|
+
const hash = crypto.hash(message);
|
|
198
198
|
return hash.slice(0, 16);
|
|
199
199
|
}
|
|
200
200
|
|