// Copyright 2009 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 block import ( "bytes"; "fmt"; "io"; "testing"; "testing/iotest"; ) // Simple Cipher for testing: adds an incrementing amount // to each byte in each type IncCipher struct { blockSize int; delta byte; encrypting bool; } func (c *IncCipher) BlockSize() int { return c.blockSize } func (c *IncCipher) Encrypt(src, dst []byte) { if !c.encrypting { panicln("encrypt: not encrypting") } if len(src) != c.blockSize || len(dst) != c.blockSize { panicln("encrypt: wrong block size", c.blockSize, len(src), len(dst)) } c.delta++; for i, b := range src { dst[i] = b + c.delta } } func (c *IncCipher) Decrypt(src, dst []byte) { if c.encrypting { panicln("decrypt: not decrypting") } if len(src) != c.blockSize || len(dst) != c.blockSize { panicln("decrypt: wrong block size", c.blockSize, len(src), len(dst)) } c.delta--; for i, b := range src { dst[i] = b + c.delta } } func TestECBEncrypter(t *testing.T) { var plain, crypt [256]byte; for i := 0; i < len(plain); i++ { plain[i] = byte(i) } b := new(bytes.Buffer); for block := 1; block <= 64; block *= 2 { // compute encrypted version delta := byte(0); for i := 0; i < len(crypt); i++ { if i%block == 0 { delta++ } crypt[i] = plain[i] + delta; } for frag := 0; frag < 2; frag++ { c := &IncCipher{block, 0, true}; b.Reset(); r := bytes.NewBuffer(&plain); w := NewECBEncrypter(c, b); // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ... // if frag != 0, move the 1 to the end to cause fragmentation. if frag == 0 { _, err := io.Copyn(w, r, 1); if err != nil { t.Errorf("block=%d frag=0: first Copyn: %s", block, err); continue; } } for n := 1; n <= len(plain)/2; n *= 2 { _, err := io.Copyn(w, r, int64(n)); if err != nil { t.Errorf("block=%d frag=%d: Copyn %d: %s", block, frag, n, err) } } if frag != 0 { _, err := io.Copyn(w, r, 1); if err != nil { t.Errorf("block=%d frag=1: last Copyn: %s", block, err); continue; } } // check output data := b.Bytes(); if len(data) != len(crypt) { t.Errorf("block=%d frag=%d: want %d bytes, got %d", block, frag, len(crypt), len(data)); continue; } if string(data) != string(&crypt) { t.Errorf("block=%d frag=%d: want %x got %x", block, frag, data, crypt) } } } } func testECBDecrypter(t *testing.T, maxio int) { var readers = []func(io.Reader) io.Reader{ func(r io.Reader) io.Reader { return r }, iotest.OneByteReader, iotest.HalfReader, }; var plain, crypt [256]byte; for i := 0; i < len(plain); i++ { plain[i] = byte(255 - i) } b := new(bytes.Buffer); for block := 1; block <= 64 && block <= maxio; block *= 2 { // compute encrypted version delta := byte(0); for i := 0; i < len(crypt); i++ { if i%block == 0 { delta++ } crypt[i] = plain[i] + delta; } for mode := 0; mode < len(readers); mode++ { for frag := 0; frag < 2; frag++ { test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio); c := &IncCipher{block, 0, false}; b.Reset(); r := NewECBDecrypter(c, readers[mode](bytes.NewBuffer(crypt[0:maxio]))); // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ... // if frag == 1, move the 1 to the end to cause fragmentation. if frag == 0 { _, err := io.Copyn(b, r, 1); if err != nil { t.Errorf("%s: first Copyn: %s", test, err); continue; } } for n := 1; n <= maxio/2; n *= 2 { _, err := io.Copyn(b, r, int64(n)); if err != nil { t.Errorf("%s: Copyn %d: %s", test, n, err) } } if frag != 0 { _, err := io.Copyn(b, r, 1); if err != nil { t.Errorf("%s: last Copyn: %s", test, err); continue; } } // check output data := b.Bytes(); if len(data) != maxio { t.Errorf("%s: want %d bytes, got %d", test, maxio, len(data)); continue; } if string(data) != string(plain[0:maxio]) { t.Errorf("%s: input=%x want %x got %x", test, crypt[0:maxio], plain[0:maxio], data) } } } } } func TestECBDecrypter(t *testing.T) { // Do shorter I/O sizes first; they're easier to debug. for n := 1; n <= 256 && !t.Failed(); n *= 2 { testECBDecrypter(t, n) } }