Skip to content

Commit

Permalink
fix: lkrp async await usage
Browse files Browse the repository at this point in the history
  • Loading branch information
KVNLS committed Oct 25, 2024
1 parent b746774 commit 5cdd04d
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 224 deletions.
24 changes: 10 additions & 14 deletions libs/hw-ledger-key-ring-protocol/src/ApduDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,20 +389,16 @@ export class APDU {
}
}

async function injectTrustedProperties(
function injectTrustedProperties(
command: Command,
properties: CommandResponse,
secret: Uint8Array,
): Promise<Command> {
): Command {
switch (command.getType()) {
case CommandType.Seed: {
const seedCommand = command as Seed;
const seedProperties = properties as SeedCommandResponse;
seedCommand.encryptedXpriv = await crypto.decrypt(
secret,
seedProperties.iv,
seedProperties.xpriv,
);
seedCommand.encryptedXpriv = crypto.decrypt(secret, seedProperties.iv, seedProperties.xpriv);
seedCommand.ephemeralPublicKey = seedProperties.ephemeralPublicKey;
seedCommand.initializationVector = seedProperties.commandIv;
seedCommand.groupKey = seedProperties.groupKey;
Expand All @@ -411,7 +407,7 @@ async function injectTrustedProperties(
case CommandType.Derive: {
const deriveCommand = command as Derive;
const deriveProperties = properties as SeedCommandResponse;
deriveCommand.encryptedXpriv = await crypto.decrypt(
deriveCommand.encryptedXpriv = crypto.decrypt(
secret,
deriveProperties.iv,
deriveProperties.xpriv,
Expand All @@ -428,7 +424,7 @@ async function injectTrustedProperties(
const publishKeyProperties = properties as PublishKeyCommandResponse;
publishKeyCommand.ephemeralPublicKey = publishKeyProperties.ephemeralPublicKey;
publishKeyCommand.initializationVector = publishKeyProperties.commandIv;
publishKeyCommand.encryptedXpriv = await crypto.decrypt(
publishKeyCommand.encryptedXpriv = crypto.decrypt(
secret,
publishKeyProperties.iv,
publishKeyProperties.xpriv,
Expand All @@ -449,7 +445,7 @@ findTrustedMember;

export class ApduDevice implements Device {
private transport: Transport;
private sessionKeyPair: Promise<KeyPair>;
private sessionKeyPair: KeyPair;

constructor(transport: Transport) {
this.transport = transport;
Expand All @@ -465,7 +461,7 @@ export class ApduDevice implements Device {
return new PublicKey(publicKey);
}

async getSeedId(data: Uint8Array): Promise<SeedIdResult> {
getSeedId(data: Uint8Array): Promise<SeedIdResult> {
return APDU.getSeedId(this.transport, data);
}

Expand Down Expand Up @@ -614,7 +610,7 @@ export class ApduDevice implements Device {
}

async sign(stream: CommandBlock[]): Promise<CommandBlock> {
const sessionKey = await this.sessionKeyPair;
const sessionKey = this.sessionKeyPair;
const trustedProperties: CommandResponse[] = [];

// We expect the stream to have a single block to sign (the last one)
Expand Down Expand Up @@ -649,8 +645,8 @@ export class ApduDevice implements Device {
const signature = await APDU.finalizeSignature(this.transport);

// Decrypt and inject trusted issuer
const secret = await crypto.ecdh(sessionKey, signature.sessionKey);
const issuer = await crypto.decrypt(secret, trustedIssuer.iv, trustedIssuer.issuer);
const secret = crypto.ecdh(sessionKey, signature.sessionKey);
const issuer = crypto.decrypt(secret, trustedIssuer.iv, trustedIssuer.issuer);

// Inject trusted properties for commands
for (let commandIndex = 0; commandIndex < blockToSign.commands.length; commandIndex++) {
Expand Down
25 changes: 11 additions & 14 deletions libs/hw-ledger-key-ring-protocol/src/CommandBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,14 @@ export interface CommandBlock {
* @param parent The parent command block hash (if null, the block is the first block and a parent will be generated)
* @returns
*/
export async function createCommandBlock(
export function createCommandBlock(
issuer: Uint8Array,
commands: Command[],
signature: Uint8Array = new Uint8Array(),
parent: Uint8Array | null = null,
): Promise<CommandBlock> {
): CommandBlock {
if (parent === null) {
parent = parent = await crypto.randomBytes(32);
parent = parent = crypto.randomBytes(32);
}
return {
version: 1,
Expand All @@ -220,28 +220,25 @@ export async function createCommandBlock(
};
}

export async function signCommandBlock(
export function signCommandBlock(
block: CommandBlock,
issuer: Uint8Array,
secretKey: Uint8Array,
): Promise<CommandBlock> {
const signature = await crypto.sign(
await hashCommandBlock(block),
await crypto.keypairFromSecretKey(secretKey),
);
): CommandBlock {
const signature = crypto.sign(hashCommandBlock(block), crypto.keypairFromSecretKey(secretKey));
return {
...block,
signature,
};
}

export async function hashCommandBlock(block: CommandBlock): Promise<Uint8Array> {
return await crypto.hash(CommandStreamEncoder.encode([block]));
export function hashCommandBlock(block: CommandBlock): Uint8Array {
return crypto.hash(CommandStreamEncoder.encode([block]));
}

export async function verifyCommandBlock(block: CommandBlock): Promise<boolean> {
export function verifyCommandBlock(block: CommandBlock): boolean {
const unsignedBlock = { ...block };
unsignedBlock.signature = new Uint8Array();
const hash = await hashCommandBlock(unsignedBlock);
return await crypto.verify(hash, block.signature, block.issuer);
const hash = hashCommandBlock(unsignedBlock);
return crypto.verify(hash, block.signature, block.issuer);
}
14 changes: 6 additions & 8 deletions libs/hw-ledger-key-ring-protocol/src/CommandStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ export class CommandStreamIssuer {
): Promise<CommandStream> {
const lastBlockHash =
this._stream.blocks.length > 0
? await hashCommandBlock(this._stream.blocks[this._stream.blocks.length - 1])
? hashCommandBlock(this._stream.blocks[this._stream.blocks.length - 1])
: null;
const block = await createCommandBlock(
const block = createCommandBlock(
ISSUER_PLACEHOLDER,
[],
new Uint8Array(),
Expand Down Expand Up @@ -167,7 +167,7 @@ export default class CommandStream {
return CommandStreamResolver.resolve(this._blocks);
}

public getRootHash(): Promise<Uint8Array> {
public getRootHash(): Uint8Array {
return hashCommandBlock(this._blocks[0]);
}

Expand Down Expand Up @@ -211,7 +211,7 @@ export default class CommandStream {
if (block.commands[0].getType() === CommandType.Derive) {
// Set the parent hash of the block to the root hash
const b = { ...block };
b.parent = await hashCommandBlock(stream[0]);
b.parent = hashCommandBlock(stream[0]);
stream = stream.concat([b]);
} else {
stream = stream.concat([block]);
Expand All @@ -227,10 +227,8 @@ export default class CommandStream {
parentHash: Uint8Array | null = null,
): Promise<CommandStream> {
const lastBlockHash =
this._blocks.length > 0
? await hashCommandBlock(this._blocks[this._blocks.length - 1])
: null;
const block = await createCommandBlock(
this._blocks.length > 0 ? hashCommandBlock(this._blocks[this._blocks.length - 1]) : null;
const block = createCommandBlock(
ISSUER_PLACEHOLDER,
commands,
new Uint8Array(),
Expand Down
22 changes: 11 additions & 11 deletions libs/hw-ledger-key-ring-protocol/src/Crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ export interface KeyPairWithChainCode extends KeyPair {
*
*/
export interface Crypto {
randomKeypair(): Promise<KeyPair>;
keypairFromSecretKey(secretKey: Uint8Array): Promise<KeyPair>;
sign(message: Uint8Array, keyPair: KeyPair): Promise<Uint8Array>;
verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): Promise<boolean>;
encrypt(secret: Uint8Array, nonce: Uint8Array, message: Uint8Array): Promise<Uint8Array>;
decrypt(secret: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array>;
randomBytes(size: number): Promise<Uint8Array>;
ecdh(keyPair: KeyPair, publicKey: Uint8Array): Promise<Uint8Array>;
hash(message: Uint8Array): Promise<Uint8Array>;
computeSymmetricKey(privateKey: Uint8Array, extra: Uint8Array): Promise<Uint8Array>;
randomKeypair(): KeyPair;
keypairFromSecretKey(secretKey: Uint8Array): KeyPair;
sign(message: Uint8Array, keyPair: KeyPair): Uint8Array;
verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean;
encrypt(secret: Uint8Array, nonce: Uint8Array, message: Uint8Array): Uint8Array;
decrypt(secret: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array): Uint8Array;
randomBytes(size: number): Uint8Array;
ecdh(keyPair: KeyPair, publicKey: Uint8Array): Uint8Array;
hash(message: Uint8Array): Uint8Array;
computeSymmetricKey(privateKey: Uint8Array, extra: Uint8Array): Uint8Array;
from_hex(hex: string): Uint8Array;
to_hex(bytes?: Uint8Array): string;
derivePrivate(xpriv: Uint8Array, path: number[]): Promise<KeyPairWithChainCode>;
derivePrivate(xpriv: Uint8Array, path: number[]): KeyPairWithChainCode;
}

export class DerivationPath {
Expand Down
60 changes: 26 additions & 34 deletions libs/hw-ledger-key-ring-protocol/src/Device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,17 @@ export class SoftwareDevice implements Device {
return new PublicKey(this.keyPair.publicKey);
}

private async generateSharedKey(): Promise<SharedKey> {
const xpriv = await crypto.randomBytes(64);
const pk = await crypto.derivePrivate(xpriv, []);
private generateSharedKey(): SharedKey {
const xpriv = crypto.randomBytes(64);
const pk = crypto.derivePrivate(xpriv, []);
return { xpriv, publicKey: pk.publicKey };
}

private async encryptSharedKey(
sharedKey: SharedKey,
recipient: Uint8Array,
): Promise<EncryptedSharedKey> {
const kp = await crypto.randomKeypair();
const ecdh = await crypto.ecdh(kp, recipient);
const initializationVector = await crypto.randomBytes(16);
const encryptedXpriv = await crypto.encrypt(ecdh, initializationVector, sharedKey.xpriv);
private encryptSharedKey(sharedKey: SharedKey, recipient: Uint8Array): EncryptedSharedKey {
const kp = crypto.randomKeypair();
const ecdh = crypto.ecdh(kp, recipient);
const initializationVector = crypto.randomBytes(16);
const encryptedXpriv = crypto.encrypt(ecdh, initializationVector, sharedKey.xpriv);
return {
encryptedXpriv,
publicKey: sharedKey.publicKey,
Expand All @@ -83,9 +80,9 @@ export class SoftwareDevice implements Device {
};
}

private async decryptSharedKey(encryptedSharedKey: EncryptedSharedKey): Promise<SharedKey> {
const ecdh = await crypto.ecdh(this.keyPair, encryptedSharedKey.ephemeralPublicKey);
const xpriv = await crypto.decrypt(
private decryptSharedKey(encryptedSharedKey: EncryptedSharedKey): SharedKey {
const ecdh = crypto.ecdh(this.keyPair, encryptedSharedKey.ephemeralPublicKey);
const xpriv = crypto.decrypt(
ecdh,
encryptedSharedKey.initializationVector,
encryptedSharedKey.encryptedXpriv,
Expand All @@ -104,8 +101,8 @@ export class SoftwareDevice implements Device {
ephemeralPublicKey: event.ephemeralPublicKey,
initializationVector: event.nonce,
};
const sharedKey = await this.decryptSharedKey(encryptedSharedKey);
const newKey = await crypto.derivePrivate(sharedKey.xpriv, path);
const sharedKey = this.decryptSharedKey(encryptedSharedKey);
const newKey = crypto.derivePrivate(sharedKey.xpriv, path);
const xpriv = new Uint8Array(64);
xpriv.set(newKey.privateKey);
xpriv.set(newKey.chainCode, 32);
Expand Down Expand Up @@ -136,10 +133,10 @@ export class SoftwareDevice implements Device {
switch (command.getType()) {
case CommandType.Seed: {
// Generate the shared key
sharedKey = await this.generateSharedKey();
sharedKey = this.generateSharedKey();

// Encrypt the shared key and inject it in the command
const encryptedSharedKey = await this.encryptSharedKey(sharedKey, this.keyPair.publicKey);
const encryptedSharedKey = this.encryptSharedKey(sharedKey, this.keyPair.publicKey);
(command as Seed).groupKey = sharedKey.publicKey;
(command as Seed).encryptedXpriv = encryptedSharedKey.encryptedXpriv;
(command as Seed).ephemeralPublicKey = encryptedSharedKey.ephemeralPublicKey;
Expand All @@ -154,10 +151,7 @@ export class SoftwareDevice implements Device {
sharedKey = await this.deriveKey(tree, (command as Derive).path);

// Encrypt the shared key and inject it in the command
const encryptedDerivedKey = await this.encryptSharedKey(
sharedKey,
this.keyPair.publicKey,
);
const encryptedDerivedKey = this.encryptSharedKey(sharedKey, this.keyPair.publicKey);
(command as Derive).groupKey = sharedKey.publicKey;
(command as Derive).encryptedXpriv = encryptedDerivedKey.encryptedXpriv;
(command as Derive).initializationVector = encryptedDerivedKey.initializationVector;
Expand All @@ -170,7 +164,7 @@ export class SoftwareDevice implements Device {
// If the current stream is the seed stream, read the key from the first command in the first block
const encryptedKey = resolved.getEncryptedKey(this.keyPair.publicKey);
if (encryptedKey) {
sharedKey = await this.decryptSharedKey({
sharedKey = this.decryptSharedKey({
encryptedXpriv: encryptedKey.encryptedXpriv,
initializationVector: encryptedKey.initialiationVector,
publicKey: encryptedKey.issuer,
Expand All @@ -186,7 +180,7 @@ export class SoftwareDevice implements Device {
}
if (!sharedKey) throw new Error("Cannot find the shared key");
}
const encryptedSharedKey = await this.encryptSharedKey(
const encryptedSharedKey = this.encryptSharedKey(
sharedKey!,
(command as PublishKey).recipient,
);
Expand All @@ -197,12 +191,10 @@ export class SoftwareDevice implements Device {
}
}
}
const signature = (
await signCommandBlock(
lastBlock,
(await this.getPublicKey()).publicKey,
this.keyPair.privateKey,
)
const signature = signCommandBlock(
lastBlock,
(await this.getPublicKey()).publicKey,
this.keyPair.privateKey,
).signature;
lastBlock.signature = signature;
return lastBlock;
Expand All @@ -219,12 +211,12 @@ export class SoftwareDevice implements Device {
publicKey: event.groupPublicKey,
ephemeralPublicKey: event.ephemeralPublicKey,
};
const sharedKey = await this.decryptSharedKey(encryptedSharedKey);
const sharedKey = this.decryptSharedKey(encryptedSharedKey);

// Derive the key to match the path
let index = DerivationPath.toIndexArray(event.stream.getStreamPath()!).length;
while (index < path.length) {
const derivation = await crypto.derivePrivate(sharedKey.xpriv, [index]);
const derivation = crypto.derivePrivate(sharedKey.xpriv, [index]);
const xpriv = new Uint8Array(64);
xpriv.set(derivation.privateKey);
xpriv.set(derivation.chainCode, 32);
Expand All @@ -244,8 +236,8 @@ export class SoftwareDevice implements Device {
/**
*
*/
export async function createDevice(): Promise<Device> {
const kp = await crypto.randomKeypair();
export function createDevice(): Device {
const kp = crypto.randomKeypair();
return new SoftwareDevice(kp);
}

Expand Down
Loading

0 comments on commit 5cdd04d

Please sign in to comment.