- Add test for base64 string output - Add test for 32-byte key length - Add test for uniqueness Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { arrayToBase64, base64ToArray, deriveKey, encrypt, decrypt, generateMasterKey } from '../../src/lib/crypto-utils';
|
|
|
|
describe('crypto-utils', () => {
|
|
describe('arrayToBase64', () => {
|
|
it('should convert Uint8Array to base64 string', () => {
|
|
const arr = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
|
|
const result = arrayToBase64(arr);
|
|
expect(result).toBe('SGVsbG8=');
|
|
});
|
|
|
|
it('should handle empty array', () => {
|
|
const arr = new Uint8Array([]);
|
|
const result = arrayToBase64(arr);
|
|
expect(result).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('base64ToArray', () => {
|
|
it('should convert base64 string to Uint8Array', () => {
|
|
const base64 = 'SGVsbG8=';
|
|
const result = base64ToArray(base64);
|
|
expect(result).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
|
|
});
|
|
|
|
it('should handle empty string', () => {
|
|
const result = base64ToArray('');
|
|
expect(result).toEqual(new Uint8Array([]));
|
|
});
|
|
});
|
|
|
|
describe('encrypt and decrypt', () => {
|
|
it('should encrypt and decrypt text correctly', async () => {
|
|
// Use real Web Crypto API (setup.ts polyfills this)
|
|
const key = await crypto.subtle.generateKey(
|
|
{ name: 'AES-GCM', length: 256 },
|
|
true,
|
|
['encrypt', 'decrypt']
|
|
);
|
|
|
|
const plaintext = 'secret message';
|
|
const encrypted = await encrypt(plaintext, key);
|
|
|
|
expect(encrypted.iv).toBeDefined();
|
|
expect(encrypted.data).toBeDefined();
|
|
expect(encrypted.data).not.toBe(plaintext);
|
|
|
|
const decrypted = await decrypt(encrypted, key);
|
|
expect(decrypted).toBe(plaintext);
|
|
});
|
|
});
|
|
|
|
describe('deriveKey', () => {
|
|
it('should derive a key from a master key', async () => {
|
|
const masterKey = 'test-master-key-123';
|
|
const key = await deriveKey(masterKey);
|
|
|
|
expect(key).toBeDefined();
|
|
expect(key.type).toBe('secret');
|
|
expect(key.algorithm).toHaveProperty('name', 'AES-GCM');
|
|
});
|
|
|
|
it('should derive same key from same master key and salt', async () => {
|
|
const masterKey = 'test-master-key-123';
|
|
const salt = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
|
|
|
const key1 = await deriveKey(masterKey, salt);
|
|
const key2 = await deriveKey(masterKey, salt);
|
|
|
|
// Keys should be usable for encryption/decryption
|
|
const plaintext = 'test data';
|
|
const encrypted = await encrypt(plaintext, key1);
|
|
const decrypted = await decrypt(encrypted, key2);
|
|
|
|
expect(decrypted).toBe(plaintext);
|
|
});
|
|
});
|
|
|
|
describe('generateMasterKey', () => {
|
|
it('should return a base64 string', () => {
|
|
const key = generateMasterKey();
|
|
expect(typeof key).toBe('string');
|
|
// Base64 regex pattern
|
|
expect(key).toMatch(/^[A-Za-z0-9+/]+=*$/);
|
|
});
|
|
|
|
it('should generate 32 bytes (256 bits)', () => {
|
|
const key = generateMasterKey();
|
|
const decoded = base64ToArray(key);
|
|
expect(decoded.length).toBe(32);
|
|
});
|
|
|
|
it('should generate unique values on each call', () => {
|
|
const key1 = generateMasterKey();
|
|
const key2 = generateMasterKey();
|
|
expect(key1).not.toBe(key2);
|
|
});
|
|
});
|
|
});
|