package crypto import ( "bytes" "crypto/ed25519" "testing" ) // TestGenerateEd25519KeyPair verifies that key generation returns valid, // distinct keys and that the public key is derivable from the private key. func TestGenerateEd25519KeyPair(t *testing.T) { pub1, priv1, err := GenerateEd25519KeyPair() if err != nil { t.Fatalf("GenerateEd25519KeyPair: %v", err) } pub2, priv2, err := GenerateEd25519KeyPair() if err != nil { t.Fatalf("GenerateEd25519KeyPair second call: %v", err) } // Keys should be different across calls. if bytes.Equal(priv1, priv2) { t.Error("two calls produced identical private keys") } if bytes.Equal(pub1, pub2) { t.Error("two calls produced identical public keys") } // Public key must be extractable from private key. derived, ok := priv1.Public().(ed25519.PublicKey) if !ok { t.Fatal("priv1.Public() did not return ed25519.PublicKey") } if !bytes.Equal(derived, pub1) { t.Error("public key derived from private key does not match generated public key") } } // TestEd25519PEMRoundTrip verifies that a private key can be encoded to PEM // and decoded back to the identical key. func TestEd25519PEMRoundTrip(t *testing.T) { _, priv, err := GenerateEd25519KeyPair() if err != nil { t.Fatalf("GenerateEd25519KeyPair: %v", err) } pem, err := MarshalPrivateKeyPEM(priv) if err != nil { t.Fatalf("MarshalPrivateKeyPEM: %v", err) } if len(pem) == 0 { t.Fatal("MarshalPrivateKeyPEM returned empty PEM") } decoded, err := ParsePrivateKeyPEM(pem) if err != nil { t.Fatalf("ParsePrivateKeyPEM: %v", err) } if !bytes.Equal(priv, decoded) { t.Error("decoded private key does not match original") } } // TestParsePrivateKeyPEMErrors validates error cases. func TestParsePrivateKeyPEMErrors(t *testing.T) { // Empty input if _, err := ParsePrivateKeyPEM([]byte{}); err == nil { t.Error("expected error for empty PEM, got nil") } // Wrong PEM type (using a fake RSA block header) fakePEM := []byte("-----BEGIN RSA PRIVATE KEY-----\nYWJj\n-----END RSA PRIVATE KEY-----\n") if _, err := ParsePrivateKeyPEM(fakePEM); err == nil { t.Error("expected error for wrong PEM type, got nil") } // Corrupt DER inside valid PEM block corruptPEM := []byte("-----BEGIN PRIVATE KEY-----\nYWJj\n-----END PRIVATE KEY-----\n") if _, err := ParsePrivateKeyPEM(corruptPEM); err == nil { t.Error("expected error for corrupt DER, got nil") } } // TestSealOpenAESGCMRoundTrip verifies that sealed data can be opened. func TestSealOpenAESGCMRoundTrip(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } plaintext := []byte("hello world secret data") ct, nonce, err := SealAESGCM(key, plaintext) if err != nil { t.Fatalf("SealAESGCM: %v", err) } if len(ct) == 0 || len(nonce) == 0 { t.Fatal("SealAESGCM returned empty ciphertext or nonce") } got, err := OpenAESGCM(key, nonce, ct) if err != nil { t.Fatalf("OpenAESGCM: %v", err) } if !bytes.Equal(got, plaintext) { t.Errorf("decrypted = %q, want %q", got, plaintext) } } // TestSealNoncesAreUnique verifies that repeated seals produce different nonces. func TestSealNoncesAreUnique(t *testing.T) { key := make([]byte, 32) plaintext := []byte("same plaintext") _, nonce1, err := SealAESGCM(key, plaintext) if err != nil { t.Fatalf("SealAESGCM (1): %v", err) } _, nonce2, err := SealAESGCM(key, plaintext) if err != nil { t.Fatalf("SealAESGCM (2): %v", err) } if bytes.Equal(nonce1, nonce2) { t.Error("two seals of the same plaintext produced identical nonces — crypto/rand may be broken") } } // TestOpenAESGCMWrongKey verifies that decryption with the wrong key fails. func TestOpenAESGCMWrongKey(t *testing.T) { key := make([]byte, 32) wrongKey := make([]byte, 32) wrongKey[0] = 0xFF ct, nonce, err := SealAESGCM(key, []byte("secret")) if err != nil { t.Fatalf("SealAESGCM: %v", err) } if _, err := OpenAESGCM(wrongKey, nonce, ct); err == nil { t.Error("expected error when opening with wrong key, got nil") } } // TestOpenAESGCMTamperedCiphertext verifies that tampering is detected. func TestOpenAESGCMTamperedCiphertext(t *testing.T) { key := make([]byte, 32) ct, nonce, err := SealAESGCM(key, []byte("secret")) if err != nil { t.Fatalf("SealAESGCM: %v", err) } // Flip one bit in the ciphertext. ct[0] ^= 0x01 if _, err := OpenAESGCM(key, nonce, ct); err == nil { t.Error("expected error for tampered ciphertext, got nil") } } // TestOpenAESGCMWrongKeySize verifies that keys with wrong size are rejected. func TestOpenAESGCMWrongKeySize(t *testing.T) { if _, _, err := SealAESGCM([]byte("short"), []byte("data")); err == nil { t.Error("expected error for short key in Seal, got nil") } if _, err := OpenAESGCM([]byte("short"), make([]byte, 12), []byte("data")); err == nil { t.Error("expected error for short key in Open, got nil") } } // TestDeriveKey verifies that DeriveKey produces consistent, non-empty output. func TestDeriveKey(t *testing.T) { salt, err := NewSalt() if err != nil { t.Fatalf("NewSalt: %v", err) } key1, err := DeriveKey("my-passphrase", salt) if err != nil { t.Fatalf("DeriveKey: %v", err) } if len(key1) != 32 { t.Errorf("DeriveKey returned %d bytes, want 32", len(key1)) } // Same inputs → same output (deterministic). key2, err := DeriveKey("my-passphrase", salt) if err != nil { t.Fatalf("DeriveKey (2): %v", err) } if !bytes.Equal(key1, key2) { t.Error("DeriveKey is not deterministic") } // Different passphrase → different key. key3, err := DeriveKey("different-passphrase", salt) if err != nil { t.Fatalf("DeriveKey (3): %v", err) } if bytes.Equal(key1, key3) { t.Error("different passphrases produced the same key") } // Different salt → different key. salt2, err := NewSalt() if err != nil { t.Fatalf("NewSalt (2): %v", err) } key4, err := DeriveKey("my-passphrase", salt2) if err != nil { t.Fatalf("DeriveKey (4): %v", err) } if bytes.Equal(key1, key4) { t.Error("different salts produced the same key") } } // TestDeriveKeyErrors verifies invalid input rejection. func TestDeriveKeyErrors(t *testing.T) { // Short salt if _, err := DeriveKey("passphrase", []byte("short")); err == nil { t.Error("expected error for short salt, got nil") } // Empty passphrase salt, _ := NewSalt() if _, err := DeriveKey("", salt); err == nil { t.Error("expected error for empty passphrase, got nil") } } // TestNewSaltUniqueness verifies that two salts are different. func TestNewSaltUniqueness(t *testing.T) { s1, err := NewSalt() if err != nil { t.Fatalf("NewSalt (1): %v", err) } s2, err := NewSalt() if err != nil { t.Fatalf("NewSalt (2): %v", err) } if bytes.Equal(s1, s2) { t.Error("two NewSalt calls returned identical salts") } } // TestRandomBytes verifies length and uniqueness. func TestRandomBytes(t *testing.T) { b1, err := RandomBytes(32) if err != nil { t.Fatalf("RandomBytes: %v", err) } if len(b1) != 32 { t.Errorf("RandomBytes returned %d bytes, want 32", len(b1)) } b2, err := RandomBytes(32) if err != nil { t.Fatalf("RandomBytes (2): %v", err) } if bytes.Equal(b1, b2) { t.Error("two RandomBytes calls returned identical values") } }