Pull out pbkdf2Sha512Crypto

This commit is contained in:
Simon Warta 2022-02-27 19:54:15 +01:00
parent 1b49d85dd7
commit b855c80a58
2 changed files with 63 additions and 13 deletions

View File

@ -1,7 +1,7 @@
import { fromHex, toAscii, toUtf8 } from "@cosmjs/encoding";
import { assert } from "@cosmjs/utils";
import { getSubtle, pbkdf2Sha512, pbkdf2Sha512Subtle } from "./pbkdf2";
import { getCryptoModule, getSubtle, pbkdf2Sha512, pbkdf2Sha512Crypto, pbkdf2Sha512Subtle } from "./pbkdf2";
interface TestVector {
secret: Uint8Array;
@ -139,4 +139,23 @@ describe("pbkdf2", () => {
}
});
});
describe("pbkdf2Sha512Crypto", () => {
it("works", async () => {
const crypto = await getCryptoModule();
assert(crypto);
{
const { secret, salt, iterations, keylen, expected } = botanTest;
const hash = await pbkdf2Sha512Crypto(crypto, secret, salt, iterations, keylen);
expect(hash).toEqual(expected);
}
for (const [index, test] of brycxTests.entries()) {
const { secret, salt, iterations, keylen, expected } = test;
const hash = await pbkdf2Sha512Crypto(crypto, secret, salt, iterations, keylen);
expect(hash).withContext(`brycx tests index ${index}`).toEqual(expected);
}
});
});
});

View File

@ -1,11 +1,20 @@
import { assert } from "@cosmjs/utils";
export async function getCryptoModule(): Promise<any | undefined> {
try {
const crypto = await import("crypto");
return crypto;
} catch {
return undefined;
}
}
export async function getSubtle(): Promise<any | undefined> {
const g: any = globalThis;
let subtle = g.crypto && g.crypto.subtle;
if (!subtle) {
const crypto: any = await import("crypto");
if (crypto.webcrypto && crypto.webcrypto.subtle) {
const crypto = await getCryptoModule();
if (crypto && crypto.webcrypto && crypto.webcrypto.subtle) {
subtle = crypto.webcrypto.subtle;
}
}
@ -41,6 +50,29 @@ export async function pbkdf2Sha512Subtle(
);
}
export async function pbkdf2Sha512Crypto(
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
crypto: any,
secret: Uint8Array,
salt: Uint8Array,
iterations: number,
keylen: number,
): Promise<Uint8Array> {
assert(crypto, "Argument crypto is falsy");
assert(typeof crypto === "object", "Argument crypto is not of type object");
assert(typeof crypto.pbkdf2 === "function", "crypto.pbkdf2 is not a function");
return new Promise((resolve, reject) => {
crypto.pbkdf2(secret, salt, iterations, keylen, "sha512", (error: any, result: any) => {
if (error) {
reject(error);
} else {
resolve(Uint8Array.from(result));
}
});
});
}
/**
* A pbkdf2 implementation for BIP39. This is not exported at package level and thus a private API.
*/
@ -54,15 +86,14 @@ export async function pbkdf2Sha512(
if (subtle) {
return pbkdf2Sha512Subtle(subtle, secret, salt, iterations, keylen);
} else {
const module = await import("crypto");
return new Promise((resolve, reject) => {
module.pbkdf2(secret, salt, iterations, keylen, "sha512", (error, result) => {
if (error) {
reject(error);
} else {
resolve(Uint8Array.from(result));
}
});
});
const crypto = await getCryptoModule();
if (crypto) {
return pbkdf2Sha512Crypto(crypto, secret, salt, iterations, keylen);
} else {
throw new Error(
"Could not find a pbkdf2 implementation in subtle (WebCrypto) or the crypto module. " +
"If you need a pure software implementation, please open an issue at https://github.com/cosmos/cosmjs",
);
}
}
}