//go:build darwin // +build darwin package macse import ( "bytes" "testing" ) const testKeyLabel = "berlin.sneak.app.secret.test.se-key" // testKeyHash stores the hash of the created test key for cleanup. var testKeyHash string //nolint:gochecknoglobals // skipIfNoSecureEnclave skips the test if SE access is unavailable. func skipIfNoSecureEnclave(t *testing.T) { t.Helper() probeLabel := "berlin.sneak.app.secret.test.se-probe" _, hash, err := CreateKey(probeLabel) if err != nil { t.Skipf("Secure Enclave unavailable (skipping): %v", err) } if hash != "" { _ = DeleteKey(hash) } } func TestCreateAndDeleteKey(t *testing.T) { skipIfNoSecureEnclave(t) if testKeyHash != "" { _ = DeleteKey(testKeyHash) } pubKey, hash, err := CreateKey(testKeyLabel) if err != nil { t.Fatalf("CreateKey failed: %v", err) } testKeyHash = hash t.Logf("Created key with hash: %s", hash) // Verify valid uncompressed P-256 public key if len(pubKey) != p256UncompressedKeySize { t.Fatalf("expected public key length %d, got %d", p256UncompressedKeySize, len(pubKey)) } if pubKey[0] != 0x04 { t.Fatalf("expected uncompressed point prefix 0x04, got 0x%02x", pubKey[0]) } if hash == "" { t.Fatal("expected non-empty hash") } // Delete the key if err := DeleteKey(hash); err != nil { t.Fatalf("DeleteKey failed: %v", err) } testKeyHash = "" t.Log("Key created, verified, and deleted successfully") } func TestEncryptDecryptRoundTrip(t *testing.T) { skipIfNoSecureEnclave(t) _, hash, err := CreateKey(testKeyLabel) if err != nil { t.Fatalf("CreateKey failed: %v", err) } testKeyHash = hash defer func() { if testKeyHash != "" { _ = DeleteKey(testKeyHash) testKeyHash = "" } }() // Test data simulating an age private key plaintext := []byte("AGE-SECRET-KEY-1QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ") // Encrypt ciphertext, err := Encrypt(testKeyLabel, plaintext) if err != nil { t.Fatalf("Encrypt failed: %v", err) } t.Logf("Plaintext: %d bytes, Ciphertext: %d bytes", len(plaintext), len(ciphertext)) if bytes.Equal(ciphertext, plaintext) { t.Fatal("ciphertext should differ from plaintext") } // Decrypt decrypted, err := Decrypt(testKeyLabel, ciphertext) if err != nil { t.Fatalf("Decrypt failed: %v", err) } if !bytes.Equal(decrypted, plaintext) { t.Fatalf("decrypted data does not match original plaintext") } t.Log("ECIES encrypt/decrypt round-trip successful") } func TestEncryptProducesDifferentCiphertexts(t *testing.T) { skipIfNoSecureEnclave(t) _, hash, err := CreateKey(testKeyLabel) if err != nil { t.Fatalf("CreateKey failed: %v", err) } testKeyHash = hash defer func() { if testKeyHash != "" { _ = DeleteKey(testKeyHash) testKeyHash = "" } }() plaintext := []byte("test-secret-data") ct1, err := Encrypt(testKeyLabel, plaintext) if err != nil { t.Fatalf("first Encrypt failed: %v", err) } ct2, err := Encrypt(testKeyLabel, plaintext) if err != nil { t.Fatalf("second Encrypt failed: %v", err) } // ECIES uses a random ephemeral key each time, so ciphertexts should differ if bytes.Equal(ct1, ct2) { t.Fatal("two encryptions of same plaintext should produce different ciphertexts") } // Both should decrypt to the same plaintext dec1, err := Decrypt(testKeyLabel, ct1) if err != nil { t.Fatalf("first Decrypt failed: %v", err) } dec2, err := Decrypt(testKeyLabel, ct2) if err != nil { t.Fatalf("second Decrypt failed: %v", err) } if !bytes.Equal(dec1, plaintext) || !bytes.Equal(dec2, plaintext) { t.Fatal("both ciphertexts should decrypt to original plaintext") } t.Log("ECIES correctly produces different ciphertexts that decrypt to same plaintext") }