diff --git a/src/utils/auth.bench.ts b/src/utils/auth.bench.ts index fbffc857..8c3da7cf 100644 --- a/src/utils/auth.bench.ts +++ b/src/utils/auth.bench.ts @@ -1,4 +1,6 @@ -import { generateToken, getTokenHash } from '@/utils/auth.ts'; +import { generateSecretKey } from 'nostr-tools'; + +import { decryptSecretKey, encryptSecretKey, generateToken, getTokenHash } from '@/utils/auth.ts'; Deno.bench('generateToken', async () => { await generateToken(); @@ -9,3 +11,18 @@ Deno.bench('getTokenHash', async (b) => { b.start(); await getTokenHash(token); }); + +Deno.bench('encryptSecretKey', async (b) => { + const sk = generateSecretKey(); + const decrypted = generateSecretKey(); + b.start(); + await encryptSecretKey(sk, decrypted); +}); + +Deno.bench('decryptSecretKey', async (b) => { + const sk = generateSecretKey(); + const decrypted = generateSecretKey(); + const encrypted = await encryptSecretKey(sk, decrypted); + b.start(); + await decryptSecretKey(sk, encrypted); +}); diff --git a/src/utils/auth.test.ts b/src/utils/auth.test.ts index a0256b5d..e9e610c1 100644 --- a/src/utils/auth.test.ts +++ b/src/utils/auth.test.ts @@ -1,7 +1,8 @@ import { assertEquals } from '@std/assert'; -import { decodeHex } from '@std/encoding/hex'; +import { decodeHex, encodeHex } from '@std/encoding/hex'; +import { generateSecretKey } from 'nostr-tools'; -import { generateToken, getTokenHash } from '@/utils/auth.ts'; +import { decryptSecretKey, encryptSecretKey, generateToken, getTokenHash } from '@/utils/auth.ts'; Deno.test('generateToken', async () => { const sk = decodeHex('a0968751df8fd42f362213f08751911672f2a037113b392403bbb7dd31b71c95'); @@ -9,10 +10,20 @@ Deno.test('generateToken', async () => { const { token, hash } = await generateToken(sk); assertEquals(token, 'token15ztgw5wl3l2z7d3zz0cgw5v3zee09gphzyanjfqrhwma6vdhrj2sauwknd'); - assertEquals(hash, decodeHex('ab4c4ead4d1c72a38fffd45b999937b7e3f25f867b19aaf252df858e77b66a8a')); + assertEquals(encodeHex(hash), 'ab4c4ead4d1c72a38fffd45b999937b7e3f25f867b19aaf252df858e77b66a8a'); }); Deno.test('getTokenHash', async () => { const hash = await getTokenHash('token15ztgw5wl3l2z7d3zz0cgw5v3zee09gphzyanjfqrhwma6vdhrj2sauwknd'); - assertEquals(hash, decodeHex('ab4c4ead4d1c72a38fffd45b999937b7e3f25f867b19aaf252df858e77b66a8a')); + assertEquals(encodeHex(hash), 'ab4c4ead4d1c72a38fffd45b999937b7e3f25f867b19aaf252df858e77b66a8a'); +}); + +Deno.test('encryptSecretKey & decryptSecretKey', async () => { + const sk = generateSecretKey(); + const data = generateSecretKey(); + + const encrypted = await encryptSecretKey(sk, data); + const decrypted = await decryptSecretKey(sk, encrypted); + + assertEquals(encodeHex(decrypted), encodeHex(data)); }); diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 8d71ed6f..05e838a9 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -28,3 +28,27 @@ export async function getTokenHash(token: `token1${string}`): Promise { + const secretKey = await crypto.subtle.importKey('raw', sk, { name: 'AES-GCM' }, false, ['encrypt']); + const iv = crypto.getRandomValues(new Uint8Array(12)); + const buffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, secretKey, decrypted); + + return new Uint8Array([...iv, ...new Uint8Array(buffer)]); +} + +/** + * Decrypt a secret key with AES-GCM. + * This function is used to retrieve the secret key from the database. + */ +export async function decryptSecretKey(sk: Uint8Array, encrypted: Uint8Array): Promise { + const secretKey = await crypto.subtle.importKey('raw', sk, { name: 'AES-GCM' }, false, ['decrypt']); + const iv = encrypted.slice(0, 12); + const buffer = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, secretKey, encrypted.slice(12)); + + return new Uint8Array(buffer); +}