package security import ( "bytes" "strings" "testing" ) func TestCipherRoundTripAndAADBinding(t *testing.T) { cipher, err := NewCipher(bytes.Repeat([]byte{1}, 32), bytes.Repeat([]byte{2}, 32)) if err != nil { t.Fatal(err) } ciphertext, nonce, err := cipher.Encrypt("+8613812345678", []byte("ticket:project-a:phone")) if err != nil { t.Fatal(err) } got, err := cipher.Decrypt(ciphertext, nonce, []byte("ticket:project-a:phone")) if err != nil || got != "+8613812345678" { t.Fatalf("round trip got %q, %v", got, err) } if _, err := cipher.Decrypt(ciphertext, nonce, []byte("ticket:project-b:phone")); err == nil { t.Fatal("expected AAD mismatch to fail") } } func TestCipherUsesUniqueNoncesAndStableHMAC(t *testing.T) { cipher, _ := NewCipher(bytes.Repeat([]byte{1}, 32), bytes.Repeat([]byte{2}, 32)) one, nonceOne, _ := cipher.Encrypt("13812345678", nil) two, nonceTwo, _ := cipher.Encrypt("13812345678", nil) if bytes.Equal(nonceOne, nonceTwo) || bytes.Equal(one, two) { t.Fatal("expected randomized encryption") } if cipher.Digest("13812345678") != cipher.Digest("13812345678") { t.Fatal("expected stable HMAC digest") } } func TestNormalizePhone(t *testing.T) { got, err := NormalizePhone("+86 (138) 1234-5678") if err != nil || got != "+8613812345678" { t.Fatalf("got %q, %v", got, err) } for _, invalid := range []string{"123", "+01234567", "138-ABC-0000", strings.Repeat("1", 16)} { if _, err := NormalizePhone(invalid); err == nil { t.Fatalf("expected %q to fail", invalid) } } } func TestTokenHasHighEntropyAndHashes(t *testing.T) { one, err := GenerateToken() if err != nil { t.Fatal(err) } two, _ := GenerateToken() if one == two || len(one) < 40 { t.Fatalf("unexpected tokens %q and %q", one, two) } if HashToken(one) == HashToken(two) || len(HashToken(one)) != 64 { t.Fatal("unexpected token hashes") } } func TestPasswordHash(t *testing.T) { hash, err := HashPassword("correct horse battery staple") if err != nil { t.Fatal(err) } if !VerifyPassword(hash, "correct horse battery staple") || VerifyPassword(hash, "wrong password") { t.Fatal("password verification mismatch") } if _, err := HashPassword("short"); err == nil { t.Fatal("expected short password rejection") } if _, err := HashPassword("XQK123456"); err != nil { t.Fatal("expected a nine-character password to satisfy the API policy") } }