package crypto import ( "bytes" "testing" ) func TestGenerateKey(t *testing.T) { key, err := GenerateKey() if err != nil { t.Fatalf("GenerateKey: %v", err) } if len(key) != KeySize { t.Fatalf("key length: got %d, want %d", len(key), KeySize) } // Should be random (not all zeros). if bytes.Equal(key, make([]byte, KeySize)) { t.Fatal("key is all zeros") } } func TestGenerateSalt(t *testing.T) { salt, err := GenerateSalt() if err != nil { t.Fatalf("GenerateSalt: %v", err) } if len(salt) != SaltSize { t.Fatalf("salt length: got %d, want %d", len(salt), SaltSize) } } func TestEncryptDecrypt(t *testing.T) { key, _ := GenerateKey() plaintext := []byte("hello, metacrypt!") ciphertext, err := Encrypt(key, plaintext) if err != nil { t.Fatalf("Encrypt: %v", err) } // Version byte should be present. if ciphertext[0] != BarrierVersion { t.Fatalf("version byte: got %d, want %d", ciphertext[0], BarrierVersion) } decrypted, err := Decrypt(key, ciphertext) if err != nil { t.Fatalf("Decrypt: %v", err) } if !bytes.Equal(plaintext, decrypted) { t.Fatalf("roundtrip failed: got %q, want %q", decrypted, plaintext) } } func TestDecryptWrongKey(t *testing.T) { key1, _ := GenerateKey() key2, _ := GenerateKey() plaintext := []byte("secret data") ciphertext, _ := Encrypt(key1, plaintext) _, err := Decrypt(key2, ciphertext) if err != ErrDecryptionFailed { t.Fatalf("expected ErrDecryptionFailed, got: %v", err) } } func TestDecryptInvalidCiphertext(t *testing.T) { key, _ := GenerateKey() _, err := Decrypt(key, []byte("short")) if err != ErrInvalidCiphertext { t.Fatalf("expected ErrInvalidCiphertext, got: %v", err) } } func TestDeriveKey(t *testing.T) { password := []byte("test-password") salt, _ := GenerateSalt() params := Argon2Params{Time: 1, Memory: 64 * 1024, Threads: 1} key := DeriveKey(password, salt, params) if len(key) != KeySize { t.Fatalf("derived key length: got %d, want %d", len(key), KeySize) } // Same inputs should produce same output. key2 := DeriveKey(password, salt, params) if !bytes.Equal(key, key2) { t.Fatal("determinism: same inputs produced different keys") } // Different password should produce different output. key3 := DeriveKey([]byte("different"), salt, params) if bytes.Equal(key, key3) { t.Fatal("different passwords produced same key") } } func TestZeroize(t *testing.T) { data := []byte{1, 2, 3, 4, 5} Zeroize(data) for i, b := range data { if b != 0 { t.Fatalf("byte %d not zeroed: %d", i, b) } } } func TestConstantTimeEqual(t *testing.T) { a := []byte("hello") b := []byte("hello") c := []byte("world") if !ConstantTimeEqual(a, b) { t.Fatal("equal slices reported as not equal") } if ConstantTimeEqual(a, c) { t.Fatal("different slices reported as equal") } } func TestEncryptProducesDifferentCiphertext(t *testing.T) { key, _ := GenerateKey() plaintext := []byte("same data") ct1, _ := Encrypt(key, plaintext) ct2, _ := Encrypt(key, plaintext) if bytes.Equal(ct1, ct2) { t.Fatal("two encryptions of same plaintext produced identical ciphertext (nonce reuse)") } }