diff --git a/src/client/crypto/index.test.ts b/src/client/crypto/index.test.ts index 03151fd..610164d 100644 --- a/src/client/crypto/index.test.ts +++ b/src/client/crypto/index.test.ts @@ -1,4 +1,4 @@ -import { encrypt, decrypt, generateECDHKeyPair, deriveECDHKey } from './index' +import { exportPublicKey, encrypt, decrypt, generateECDHKeyPair, deriveECDHKey, hasWebCryptoAPI, importPublicKey } from './index' describe('crypto', () => { @@ -21,6 +21,22 @@ describe('crypto', () => { }) }) + describe('hasWebCryptoAPI', () => { + it('returns true when crypto.subtle api is available', () => { + expect(hasWebCryptoAPI()).toBe(true) + }) + }) + + describe('exportPublicKey and importPublicKey', () => { + it('exports public key', async () => { + const value = await exportPublicKey(keypair1.publicKey) + console.log(value) + const key = await importPublicKey(value) + expect(key).toBeTruthy() + expect(key).toEqual(keypair1.publicKey) + }) + }) + describe('encrypt and decrypt', () => { it('can be encrypted with one pair and decrypted with other', async () => { const message = 'test message' diff --git a/src/client/crypto/index.ts b/src/client/crypto/index.ts index 39460d4..d87e99f 100644 --- a/src/client/crypto/index.ts +++ b/src/client/crypto/index.ts @@ -1,3 +1,12 @@ + +export function hasWebCryptoAPI(): boolean { + return !!(window && window.crypto && window.crypto.subtle) +} + +export function hasWebCryptoAPI2(): boolean { + return !!(window?.crypto?.subtle) +} + export async function generateECDHKeyPair() { const key = await window.crypto.subtle.generateKey( { @@ -59,10 +68,38 @@ export async function decrypt(key: CryptoKey, data: string): Promise { return ab2str(decrypted) } +export async function exportPublicKey(key: CryptoKey) { + return await window.crypto.subtle.exportKey('jwk', key) + // const pkcs8 = await window.crypto.subtle.exportKey('pkcs8', key) + // const base64 = window.btoa(ab2str(pkcs8, Uint8Array)) + // const value = + // `-----BEGIN PUBLIC KEY-----\n${base64}\n-----END PUBLIC KEY-----` + // return value +} -function ab2str(buf: ArrayBuffer): string { +function ab2str( + buf: ArrayBuffer, + ArrayType: typeof Uint16Array | typeof Uint8Array = Uint16Array, +): string { return String.fromCharCode.apply( - null, new Uint16Array(buf) as unknown as number[]) + null, new ArrayType(buf) as unknown as number[]) +} + +export async function importPublicKey(keyData: JsonWebKey) { + if (keyData.kty !== 'EC' || keyData.crv !== 'P-256') { + throw new Error(`Unsupported key type: ${keyData.kty}, crv: ${keyData.crv}`) + } + const key = await window.crypto.subtle.importKey( + 'jwk', + keyData, + { + name: 'ECDH', + namedCurve: keyData.crv, + }, + /* extractable */ true, + [], + ) + return key } function str2ab(str: string): ArrayBuffer {