| // Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| package cipher_test |
| |
| import ( |
| "bytes" |
| "crypto/aes" |
| "crypto/cipher" |
| "crypto/internal/cryptotest" |
| "crypto/internal/cryptotest/wycheproof" |
| "testing" |
| ) |
| |
| func TestGCMWycheproof(t *testing.T) { |
| cryptotest.TestAllImplementations(t, "gcm", func(t *testing.T) { |
| file := "aes_gcm_test.json" |
| var testdata wycheproof.AeadTestSchemaV1Json |
| wycheproof.LoadVectorFile(t, file, &testdata) |
| |
| for _, tg := range testdata.TestGroups { |
| for _, tv := range tg.Tests { |
| t.Run(wycheproof.TestName(file, tv), func(t *testing.T) { |
| t.Parallel() |
| |
| aesCipher, err := aes.NewCipher(wycheproof.MustDecodeHex(tv.Key)) |
| if err != nil { |
| t.Fatalf("failed to construct cipher: %s", err) |
| } |
| aead, err := cipher.NewGCM(aesCipher) |
| if err != nil { |
| t.Fatalf("failed to construct cipher: %s", err) |
| } |
| |
| iv := wycheproof.MustDecodeHex(tv.Iv) |
| tag := wycheproof.MustDecodeHex(tv.Tag) |
| ct := wycheproof.MustDecodeHex(tv.Ct) |
| msg := wycheproof.MustDecodeHex(tv.Msg) |
| aad := wycheproof.MustDecodeHex(tv.Aad) |
| |
| // The Go implementation panics on invalid nonce sizes rather |
| // than returning an error. Verify this behavior. |
| if len(iv) != aead.NonceSize() { |
| ctWithTag := append(ct, tag...) |
| wycheproof.MustPanic(t, "Seal", func() { aead.Seal(nil, iv, msg, aad) }) |
| wycheproof.MustPanic(t, "Open", func() { aead.Open(nil, iv, ctWithTag, aad) }) |
| return |
| } |
| |
| genCT := aead.Seal(nil, iv, msg, aad) |
| genMsg, err := aead.Open(nil, iv, genCT, aad) |
| if err != nil { |
| t.Errorf("failed to decrypt generated ciphertext: %s", err) |
| } |
| if !bytes.Equal(genMsg, msg) { |
| t.Errorf("unexpected roundtripped plaintext: got %x, want %x", genMsg, msg) |
| } |
| |
| ctWithTag := append(ct, tag...) |
| msg2, err := aead.Open(nil, iv, ctWithTag, aad) |
| wantPass := wycheproof.ShouldPass(t, tv.Result, tv.Flags, nil) |
| if !wantPass && err == nil { |
| t.Error("decryption succeeded when it should've failed") |
| } else if wantPass { |
| if err != nil { |
| t.Fatalf("decryption failed: %s", err) |
| } |
| if !bytes.Equal(genCT, ctWithTag) { |
| t.Errorf("generated ciphertext doesn't match expected: got %x, want %x", genCT, ctWithTag) |
| } |
| if !bytes.Equal(msg, msg2) { |
| t.Errorf("decrypted ciphertext doesn't match expected: got %x, want %x", msg2, msg) |
| } |
| } |
| }) |
| } |
| } |
| }) |
| } |