rwadurian/backend/services/mpc-service/tests/unit/domain/share-encryption.spec.ts

175 lines
5.9 KiB
TypeScript

/**
* Share Encryption Domain Service Unit Tests
*/
import { ShareEncryptionDomainService } from '../../../src/domain/services/share-encryption.domain-service';
import { ShareData } from '../../../src/domain/value-objects';
describe('ShareEncryptionDomainService', () => {
let service: ShareEncryptionDomainService;
beforeEach(() => {
service = new ShareEncryptionDomainService();
});
describe('encrypt/decrypt', () => {
it('should encrypt and decrypt data correctly', () => {
const rawData = Buffer.from('This is the raw share data to encrypt');
const masterKey = service.generateMasterKey();
const encrypted = service.encrypt(rawData, masterKey);
const decrypted = service.decrypt(encrypted, masterKey);
expect(decrypted).toEqual(rawData);
});
it('should produce different ciphertexts for same plaintext', () => {
const rawData = Buffer.from('Same plaintext data');
const masterKey = service.generateMasterKey();
const encrypted1 = service.encrypt(rawData, masterKey);
const encrypted2 = service.encrypt(rawData, masterKey);
// IV is random, so ciphertexts should be different
expect(encrypted1.encryptedData).not.toEqual(encrypted2.encryptedData);
expect(encrypted1.iv).not.toEqual(encrypted2.iv);
});
it('should fail decryption with wrong key', () => {
const rawData = Buffer.from('Secret data');
const correctKey = service.generateMasterKey();
const wrongKey = service.generateMasterKey();
const encrypted = service.encrypt(rawData, correctKey);
expect(() => service.decrypt(encrypted, wrongKey)).toThrow();
});
it('should fail decryption with tampered ciphertext', () => {
const rawData = Buffer.from('Secret data');
const masterKey = service.generateMasterKey();
const encrypted = service.encrypt(rawData, masterKey);
// Tamper with the ciphertext
const tamperedData = Buffer.from(encrypted.encryptedData);
tamperedData[0] ^= 0xFF;
const tampered = ShareData.create(tamperedData, encrypted.iv, encrypted.authTag);
expect(() => service.decrypt(tampered, masterKey)).toThrow();
});
it('should fail decryption with tampered authTag', () => {
const rawData = Buffer.from('Secret data');
const masterKey = service.generateMasterKey();
const encrypted = service.encrypt(rawData, masterKey);
// Tamper with the auth tag
const tamperedTag = Buffer.from(encrypted.authTag);
tamperedTag[0] ^= 0xFF;
const tampered = ShareData.create(encrypted.encryptedData, encrypted.iv, tamperedTag);
expect(() => service.decrypt(tampered, masterKey)).toThrow();
});
});
describe('generateMasterKey', () => {
it('should generate 32-byte key', () => {
const key = service.generateMasterKey();
expect(key).toHaveLength(32);
});
it('should generate unique keys', () => {
const key1 = service.generateMasterKey();
const key2 = service.generateMasterKey();
expect(key1).not.toEqual(key2);
});
});
describe('deriveKeyFromPassword', () => {
it('should derive consistent key from password', () => {
const password = 'my-secure-password';
const salt = service.generateSalt();
const key1 = service.deriveKeyFromPassword(password, salt);
const key2 = service.deriveKeyFromPassword(password, salt);
expect(key1).toEqual(key2);
expect(key1).toHaveLength(32);
});
it('should derive different keys for different passwords', () => {
const salt = service.generateSalt();
const key1 = service.deriveKeyFromPassword('password1', salt);
const key2 = service.deriveKeyFromPassword('password2', salt);
expect(key1).not.toEqual(key2);
});
it('should derive different keys for different salts', () => {
const password = 'my-password';
const salt1 = service.generateSalt();
const salt2 = service.generateSalt();
const key1 = service.deriveKeyFromPassword(password, salt1);
const key2 = service.deriveKeyFromPassword(password, salt2);
expect(key1).not.toEqual(key2);
});
it('should throw error for empty password', () => {
const salt = service.generateSalt();
expect(() => service.deriveKeyFromPassword('', salt)).toThrow();
});
it('should throw error for short salt', () => {
expect(() => service.deriveKeyFromPassword('password', Buffer.alloc(8))).toThrow();
});
});
describe('validateMasterKey', () => {
it('should throw error for invalid key length', () => {
const rawData = Buffer.from('data');
const shortKey = Buffer.alloc(16);
expect(() => service.encrypt(rawData, shortKey)).toThrow();
});
});
describe('computeHmac/verifyHmac', () => {
it('should compute and verify HMAC', () => {
const data = Buffer.from('data to authenticate');
const key = service.generateMasterKey();
const hmac = service.computeHmac(data, key);
const isValid = service.verifyHmac(data, key, hmac);
expect(isValid).toBe(true);
});
it('should fail verification with wrong key', () => {
const data = Buffer.from('data to authenticate');
const correctKey = service.generateMasterKey();
const wrongKey = service.generateMasterKey();
const hmac = service.computeHmac(data, correctKey);
const isValid = service.verifyHmac(data, wrongKey, hmac);
expect(isValid).toBe(false);
});
it('should fail verification with tampered data', () => {
const data = Buffer.from('original data');
const key = service.generateMasterKey();
const hmac = service.computeHmac(data, key);
const tamperedData = Buffer.from('tampered data');
const isValid = service.verifyHmac(tamperedData, key, hmac);
expect(isValid).toBe(false);
});
});
});