// 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 ()// Each test is executed with each of the buffer lengths in bufLens.var ( bufLens = []int{0, 1, 3, 4, 8, 10, 15, 16, 20, 32, 50, 4096, 5000} bufCap = 10000)// MakeStream returns a cipher.Stream instance.//// Multiple calls to MakeStream must return equivalent instances,// so for example the key and/or IV must be fixed.typeMakeStreamfunc() cipher.Stream// TestStream performs a set of tests on cipher.Stream implementations,// checking the documented requirements of XORKeyStream.func ( *testing.T, MakeStream) { .Run("XORSemantics", func( *testing.T) {ifstrings.Contains(.Name(), "TestCFBStream") {// This is ugly, but so is CFB's abuse of cipher.Stream. // Don't want to make it easier for anyone else to do that. .Skip("CFB implements cipher.Stream but does not follow XOR semantics") }// Test that XORKeyStream inverts itself for encryption/decryption. .Run("Roundtrip", func( *testing.T) {for , := rangebufLens { .Run(fmt.Sprintf("BuffLength=%d", ), func( *testing.T) { := newRandReader() := make([]byte, ) .Read() := make([]byte, ) := make([]byte, ) ().XORKeyStream(, ) // Encrypt plaintext ().XORKeyStream(, ) // Decrypt ciphertextif !bytes.Equal(, ) { .Errorf("plaintext is different after an encrypt/decrypt cycle; got %s, want %s", truncateHex(), truncateHex()) } }) } })// Test that XORKeyStream behaves the same as directly XORing // plaintext with the stream. .Run("DirectXOR", func( *testing.T) {for , := rangebufLens { .Run(fmt.Sprintf("BuffLength=%d", ), func( *testing.T) { := newRandReader() := make([]byte, ) .Read()// Encrypting all zeros should reveal the stream itself , := make([]byte, ), make([]byte, ) ().XORKeyStream(, )// Encrypt plaintext by directly XORing the streamsubtle.XORBytes(, , )// Encrypt plaintext with XORKeyStream := make([]byte, ) ().XORKeyStream(, )if !bytes.Equal(, ) { .Errorf("xor semantics were not preserved; got %s, want %s", truncateHex(), truncateHex()) } }) } }) }) .Run("EmptyInput", func( *testing.T) { := newRandReader() , := make([]byte, 100), make([]byte, 100) .Read() := bytes.Clone() ().XORKeyStream(, [:0])if !bytes.Equal(, ) { .Errorf("XORKeyStream modified dst on empty input; got %s, want %s", truncateHex(), truncateHex()) } }) .Run("AlterInput", func( *testing.T) { := newRandReader() , , := make([]byte, bufCap), make([]byte, bufCap), make([]byte, bufCap) .Read()for , := rangebufLens { .Run(fmt.Sprintf("BuffLength=%d", ), func( *testing.T) {copy(, ) ().XORKeyStream([:], [:])if !bytes.Equal(, ) { .Errorf("XORKeyStream modified src; got %s, want %s", truncateHex(), truncateHex()) } }) } }) .Run("Aliasing", func( *testing.T) { := newRandReader() , := make([]byte, bufCap), make([]byte, bufCap)for , := rangebufLens {// Record what output is when src and dst are different .Read() ().XORKeyStream([:], [:])// Check that the same output is generated when src=dst alias to the same // memory ().XORKeyStream([:], [:])if !bytes.Equal([:], [:]) { .Errorf("block cipher produced different output when dst = src; got %x, want %x", [:], [:]) } } }) .Run("OutOfBoundsWrite", func( *testing.T) { // Issue 21104 := newRandReader() := make([]byte, bufCap) .Read() := make([]byte, bufCap)for , := rangebufLens {copy(, ) // Reset ciphertext buffer .Run(fmt.Sprintf("BuffLength=%d", ), func( *testing.T) {mustPanic(, "output smaller than input", func() { ().XORKeyStream([:], ) })if !bytes.Equal([:], [:]) { .Errorf("XORKeyStream did out of bounds write; got %s, want %s", truncateHex([:]), truncateHex([:])) } }) } }) .Run("BufferOverlap", func( *testing.T) { := newRandReader() := make([]byte, bufCap) .Read()for , := rangebufLens {if == 0 || == 1 {continue } .Run(fmt.Sprintf("BuffLength=%d", ), func( *testing.T) {// Make src and dst slices point to same array with inexact overlap := [:] := [1 : +1]mustPanic(, "invalid buffer overlap", func() { ().XORKeyStream(, ) })// Only overlap on one byte = [:] = [-1 : 2*-1]mustPanic(, "invalid buffer overlap", func() { ().XORKeyStream(, ) })// src comes after dst with one byte overlap = [-1 : 2*-1] = [:]mustPanic(, "invalid buffer overlap", func() { ().XORKeyStream(, ) }) }) } }) .Run("KeepState", func( *testing.T) { := newRandReader() := make([]byte, bufCap) .Read() := make([]byte, bufCap)// Make one long call to XORKeyStream ().XORKeyStream(, )for , := rangebufLens {if == 0 {continue } := fmt.Sprintf("step %d: ", ) := make([]byte, bufCap)// Make a bunch of small calls to (stateful) XORKeyStream := () := 0for + < len() { .XORKeyStream([:], [:+]) += } .XORKeyStream([:], [:])if !bytes.Equal(, ) { .Errorf(+"successive XORKeyStream calls returned a different result than a single one; got %s, want %s", truncateHex(), truncateHex()) } } })}// TestStreamFromBlock creates a Stream from a cipher.Block used in a// cipher.BlockMode. It addresses Issue 68377 by checking for a panic when the// BlockMode uses an IV with incorrect length.// For a valid IV, it also runs all TestStream tests on the resulting stream.func ( *testing.T, cipher.Block, func( cipher.Block, []byte) cipher.Stream) { .Run("WrongIVLen", func( *testing.T) { .Skip("see Issue 68377") := newRandReader() := make([]byte, .BlockSize()+1) .Read()mustPanic(, "IV length must equal block size", func() { (, ) }) }) .Run("BlockModeStream", func( *testing.T) { := newRandReader() := make([]byte, .BlockSize()) .Read()TestStream(, func() cipher.Stream { return (, ) }) })}func truncateHex( []byte) string { := 50iflen() <= {returnfmt.Sprintf("%x", ) }returnfmt.Sprintf("%x...", [:])}
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.