| // 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 cipher_test | |
| import ( | |
| . "crypto/cipher" | |
| "reflect" | |
| "testing" | |
| ) | |
| // Historically, crypto/aes's Block would implement some undocumented | |
| // methods for crypto/cipher to use from NewCTR, NewCBCEncrypter, etc. | |
| // This is no longer the case, but for now test that the mechanism is | |
| // still working until we explicitly decide to remove it. | |
| type block struct { | |
| Block | |
| } | |
| func (block) BlockSize() int { | |
| return 16 | |
| } | |
| type specialCTR struct { | |
| Stream | |
| } | |
| func (block) NewCTR(iv []byte) Stream { | |
| return specialCTR{} | |
| } | |
| func TestCTRAble(t *testing.T) { | |
| b := block{} | |
| s := NewCTR(b, make([]byte, 16)) | |
| if _, ok := s.(specialCTR); !ok { | |
| t.Errorf("NewCTR did not return specialCTR") | |
| } | |
| } | |
| type specialCBC struct { | |
| BlockMode | |
| } | |
| func (block) NewCBCEncrypter(iv []byte) BlockMode { | |
| return specialCBC{} | |
| } | |
| func (block) NewCBCDecrypter(iv []byte) BlockMode { | |
| return specialCBC{} | |
| } | |
| func TestCBCAble(t *testing.T) { | |
| b := block{} | |
| s := NewCBCEncrypter(b, make([]byte, 16)) | |
| if _, ok := s.(specialCBC); !ok { | |
| t.Errorf("NewCBCEncrypter did not return specialCBC") | |
| } | |
| s = NewCBCDecrypter(b, make([]byte, 16)) | |
| if _, ok := s.(specialCBC); !ok { | |
| t.Errorf("NewCBCDecrypter did not return specialCBC") | |
| } | |
| } | |
| type specialGCM struct { | |
| AEAD | |
| } | |
| func (block) NewGCM(nonceSize, tagSize int) (AEAD, error) { | |
| return specialGCM{}, nil | |
| } | |
| func TestGCM(t *testing.T) { | |
| b := block{} | |
| s, err := NewGCM(b) | |
| if err != nil { | |
| t.Errorf("NewGCM failed: %v", err) | |
| } | |
| if _, ok := s.(specialGCM); !ok { | |
| t.Errorf("NewGCM did not return specialGCM") | |
| } | |
| } | |
| // TestNoExtraMethods makes sure we don't accidentally expose methods on the | |
| // underlying implementations of modes. | |
| func TestNoExtraMethods(t *testing.T) { | |
| testAllImplementations(t, testNoExtraMethods) | |
| } | |
| func testNoExtraMethods(t *testing.T, newBlock func([]byte) Block) { | |
| b := newBlock(make([]byte, 16)) | |
| ctr := NewCTR(b, make([]byte, 16)) | |
| ctrExpected := []string{"XORKeyStream"} | |
| if got := exportedMethods(ctr); !reflect.DeepEqual(got, ctrExpected) { | |
| t.Errorf("CTR: got %v, want %v", got, ctrExpected) | |
| } | |
| cbc := NewCBCEncrypter(b, make([]byte, 16)) | |
| cbcExpected := []string{"BlockSize", "CryptBlocks", "SetIV"} | |
| if got := exportedMethods(cbc); !reflect.DeepEqual(got, cbcExpected) { | |
| t.Errorf("CBC: got %v, want %v", got, cbcExpected) | |
| } | |
| cbc = NewCBCDecrypter(b, make([]byte, 16)) | |
| if got := exportedMethods(cbc); !reflect.DeepEqual(got, cbcExpected) { | |
| t.Errorf("CBC: got %v, want %v", got, cbcExpected) | |
| } | |
| gcm, _ := NewGCM(b) | |
| gcmExpected := []string{"NonceSize", "Open", "Overhead", "Seal"} | |
| if got := exportedMethods(gcm); !reflect.DeepEqual(got, gcmExpected) { | |
| t.Errorf("GCM: got %v, want %v", got, gcmExpected) | |
| } | |
| } | |
| func exportedMethods(x any) []string { | |
| var methods []string | |
| v := reflect.ValueOf(x) | |
| for i := 0; i < v.NumMethod(); i++ { | |
| if v.Type().Method(i).IsExported() { | |
| methods = append(methods, v.Type().Method(i).Name) | |
| } | |
| } | |
| return methods | |
| } |