Add a crypto module to convert ECDSA private CryptoKey into a public key

This commit is contained in:
Alex Gleason 2024-10-08 13:56:46 -05:00
parent 6430dd11ad
commit 1ed6cac1c4
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
2 changed files with 53 additions and 0 deletions

28
src/utils/crypto.test.ts Normal file
View file

@ -0,0 +1,28 @@
import { assertEquals } from '@std/assert';
import { getEcdsaPublicKey } from '@/utils/crypto.ts';
Deno.test('getEcdsaPublicKey', async () => {
const { publicKey, privateKey } = await crypto.subtle.generateKey(
{
name: 'ECDSA',
namedCurve: 'P-256',
},
true,
['sign', 'verify'],
);
const result = await getEcdsaPublicKey(privateKey, true);
assertKeysEqual(result, publicKey);
});
/** Assert that two CryptoKey objects are equal by value. Keys must be exportable. */
async function assertKeysEqual(a: CryptoKey, b: CryptoKey): Promise<void> {
const [jwk1, jwk2] = await Promise.all([
crypto.subtle.exportKey('jwk', a),
crypto.subtle.exportKey('jwk', b),
]);
assertEquals(jwk1, jwk2);
}

25
src/utils/crypto.ts Normal file
View file

@ -0,0 +1,25 @@
/**
* Convert an ECDSA private key into a public key.
* https://stackoverflow.com/a/72153942
*/
export async function getEcdsaPublicKey(
privateKey: CryptoKey,
extractable: boolean,
): Promise<CryptoKey> {
if (privateKey.type !== 'private') {
throw new Error('Expected a private key.');
}
if (privateKey.algorithm.name !== 'ECDSA') {
throw new Error('Expected a private key with the ECDSA algorithm.');
}
const jwk = await crypto.subtle.exportKey('jwk', privateKey);
const keyUsages: KeyUsage[] = ['verify'];
// Remove the private property from the JWK.
delete jwk.d;
jwk.key_ops = keyUsages;
jwk.ext = extractable;
return crypto.subtle.importKey('jwk', jwk, privateKey.algorithm, extractable, keyUsages);
}