// Copyright 2024 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 cryptotestimport ()var lengths = []int{0, 156, 8192, 8193, 8208}// MakeAEAD returns a cipher.AEAD instance.//// Multiple calls to MakeAEAD must return equivalent instances, so for example// the key must be fixed.typeMakeAEADfunc() (cipher.AEAD, error)// TestAEAD performs a set of tests on cipher.AEAD implementations, checking// the documented requirements of NonceSize, Overhead, Seal and Open.func ( *testing.T, MakeAEAD) { , := ()if != nil { .Fatal() } .Run("Roundtrip", func( *testing.T) {// Test all combinations of plaintext and additional data lengths.for , := rangelengths {for , := rangelengths { .Run(fmt.Sprintf("Plaintext-Length=%d,AddData-Length=%d", , ), func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() , := make([]byte, ), make([]byte, ) .Read() .Read() := sealMsg(, , nil, , , ) := openWithoutError(, , nil, , , )if !bytes.Equal(, ) { .Errorf("plaintext is different after a seal/open cycle; got %s, want %s", truncateHex(), truncateHex()) } }) } } }) .Run("InputNotModified", func( *testing.T) {// Test all combinations of plaintext and additional data lengths.for , := rangelengths {for , := rangelengths { .Run(fmt.Sprintf("Plaintext-Length=%d,AddData-Length=%d", , ), func( *testing.T) { .Run("Seal", func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() , := make([]byte, ), make([]byte, ) .Read()copy(, ) := make([]byte, ) .Read()sealMsg(, , nil, , , )if !bytes.Equal(, ) { .Errorf("Seal modified src; got %s, want %s", truncateHex(), truncateHex()) } }) .Run("Open", func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() , := make([]byte, ), make([]byte, ) .Read() .Read()// Record the ciphertext that shouldn't be modified as the input of // Open. := sealMsg(, , nil, , , ) := make([]byte, len())copy(, )openWithoutError(, , nil, , , )if !bytes.Equal(, ) { .Errorf("Open modified src; got %s, want %s", truncateHex(), truncateHex()) } }) }) } } }) .Run("BufferOverlap", func( *testing.T) {// Test all combinations of plaintext and additional data lengths.for , := rangelengths {if <= 1 { // We need enough room for an inexact overlap to occur.continue }for , := rangelengths { .Run(fmt.Sprintf("Plaintext-Length=%d,AddData-Length=%d", , ), func( *testing.T) { .Run("Seal", func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read()// Make a buffer that can hold a plaintext and ciphertext as we // overlap their slices to check for panic on inexact overlaps. := + .Overhead() := make([]byte, +) .Read() := make([]byte, ) .Read()// Make plaintext and dst slices point to same array with inexact overlap. := [:] := [1:1] // Shift dst to not start at start of plaintext.mustPanic(, "invalid buffer overlap", func() { sealMsg(, , , , , ) })// Only overlap on one byte = [:] = [-1 : -1]mustPanic(, "invalid buffer overlap", func() { sealMsg(, , , , , ) }) }) .Run("Open", func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read()// Create a valid ciphertext to test Open with. := make([]byte, ) .Read() := make([]byte, ) .Read() := sealMsg(, , nil, , , )// Make a buffer that can hold a plaintext and ciphertext as we // overlap their slices to check for panic on inexact overlaps. := make([]byte, +len())// Make ciphertext and dst slices point to same array with inexact overlap. := [:len()]copy(, ) := [1:1] // Shift dst to not start at start of ciphertext.mustPanic(, "invalid buffer overlap", func() { .Open(, , , ) })// Only overlap on one byte. = [:len()]copy(, )// Make sure it is the actual ciphertext being overlapped and not // the hash digest which might be extracted/truncated in some // implementations: Go one byte past the hash digest/tag and into // the ciphertext. := len() - .Overhead() = [-1 : -1]mustPanic(, "invalid buffer overlap", func() { .Open(, , , ) }) }) }) } } }) .Run("AppendDst", func( *testing.T) {// Test all combinations of plaintext and additional data lengths.for , := rangelengths {for , := rangelengths { .Run(fmt.Sprintf("Plaintext-Length=%d,AddData-Length=%d", , ), func( *testing.T) { .Run("Seal", func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() := []byte("a") := make([]byte, 512) .Read() := [][]byte{, }// Check each prefix gets appended to by Seal without altering them.for , := range { , := make([]byte, ), make([]byte, ) .Read() .Read() := sealMsg(, , , , , )// Check that Seal didn't alter the prefixif !bytes.Equal([:len()], ) { .Errorf("Seal alters dst instead of appending; got %s, want %s", truncateHex([:len()]), truncateHex()) }ifisDeterministic() { := [len():]// Check that the appended ciphertext wasn't affected by the prefixif := sealMsg(, , nil, , , ); !bytes.Equal(, ) { .Errorf("Seal behavior affected by pre-existing data in dst; got %s, want %s", truncateHex(), truncateHex()) } } } }) .Run("Open", func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() := []byte("a") := make([]byte, 512) .Read() := [][]byte{, }// Check each prefix gets appended to by Open without altering them.for , := range { , := make([]byte, ), make([]byte, ) .Read() .Read() := sealMsg(, , nil, , , ) := openWithoutError(, , , , , )// Check that Open didn't alter the prefixif !bytes.Equal([:len()], ) { .Errorf("Open alters dst instead of appending; got %s, want %s", truncateHex([:len()]), truncateHex()) } := [len():]// Check that the appended plaintext wasn't affected by the prefixif !bytes.Equal(, ) { .Errorf("Open behavior affected by pre-existing data in dst; got %s, want %s", truncateHex(), truncateHex()) } } }) }) } } }) .Run("WrongNonce", func( *testing.T) {if .NonceSize() == 0 { .Skip("AEAD does not use a nonce") }// Test all combinations of plaintext and additional data lengths.for , := rangelengths {for , := rangelengths { .Run(fmt.Sprintf("Plaintext-Length=%d,AddData-Length=%d", , ), func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() , := make([]byte, ), make([]byte, ) .Read() .Read() := sealMsg(, , nil, , , )// Perturb the nonce and check for an error when Opening := make([]byte, .NonceSize())copy(, ) [len()-1] += 1 , := .Open(nil, , , )if == nil { .Errorf("Open did not error when given different nonce than Sealed with") } }) } } }) .Run("WrongAddData", func( *testing.T) {// Test all combinations of plaintext and additional data lengths.for , := rangelengths {for , := rangelengths {if == 0 {continue } .Run(fmt.Sprintf("Plaintext-Length=%d,AddData-Length=%d", , ), func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() , := make([]byte, ), make([]byte, ) .Read() .Read() := sealMsg(, , nil, , , )// Perturb the Additional Data and check for an error when Opening := make([]byte, )copy(, ) [len()-1] += 1 , := .Open(nil, , , )if == nil { .Errorf("Open did not error when given different Additional Data than Sealed with") } }) } } }) .Run("WrongCiphertext", func( *testing.T) {// Test all combinations of plaintext and additional data lengths.for , := rangelengths {for , := rangelengths { .Run(fmt.Sprintf("Plaintext-Length=%d,AddData-Length=%d", , ), func( *testing.T) { := newRandReader() := make([]byte, .NonceSize()) .Read() , := make([]byte, ), make([]byte, ) .Read() .Read() := sealMsg(, , nil, , , )// Perturb the ciphertext and check for an error when Opening := make([]byte, len())copy(, ) [len()-1] += 1 , := .Open(nil, , , )if == nil { .Errorf("Open did not error when given different ciphertext than was produced by Seal") } }) } } })}// Helper function to Seal a plaintext with additional data. Checks that// ciphertext isn't bigger than the plaintext length plus Overhead()func sealMsg( *testing.T, cipher.AEAD, , , , []byte) []byte { .Helper() := len() = .Seal(, , , ) := len() - // Appended ciphertext shouldn't ever be longer than the length of the // plaintext plus Overheadif > len()+.Overhead() { .Errorf("length of ciphertext from Seal exceeds length of plaintext by more than Overhead(); got %d, want <=%d", , len()+.Overhead()) }return}func isDeterministic( cipher.AEAD) bool {// Check if the AEAD is deterministic by checking if the same plaintext // encrypted with the same nonce and additional data produces the same // ciphertext. := make([]byte, .NonceSize()) := []byte("additional data") := []byte("plaintext") := .Seal(nil, , , ) := .Seal(nil, , , )returnbytes.Equal(, )}// Helper function to Open and authenticate ciphertext. Checks that Open// doesn't error (assuming ciphertext was well-formed with corresponding nonce// and additional data).func openWithoutError( *testing.T, cipher.AEAD, , , , []byte) []byte { .Helper() , := .Open(, , , )if != nil { .Fatalf("Open returned error on properly formed ciphertext; got \"%s\", want \"nil\"", ) }return}
The pages are generated with Goldsv0.7.3. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.