blob: e20c73a14c54c46d30539136229fa1845d2a780c [file] [log] [blame]
// 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.
// Electronic codebook (ECB) mode.
// ECB is a fancy name for ``encrypt and decrypt each block separately.''
// It's a pretty bad thing to do for any large amount of data (more than one block),
// because the individual blocks can still be identified, duplicated, and reordered.
// The ECB implementation exists mainly to provide buffering for
// the other modes, which wrap it by providing modified Ciphers.
// See NIST SP 800-38A, pp 9-10
package block
import (
"io";
"os";
"strconv";
)
type ecbDecrypter struct {
c Cipher;
r io.Reader;
blockSize int; // block size
// Buffered data.
// The buffer buf is used as storage for both
// plain or crypt; at least one of those is nil at any given time.
buf []byte;
plain []byte; // plain text waiting to be read
crypt []byte; // ciphertext waiting to be decrypted
}
// Read into x.crypt until it has a full block or EOF or an error happens.
func (x *ecbDecrypter) fillCrypt() os.Error {
var err os.Error;
for len(x.crypt) < x.blockSize {
off := len(x.crypt);
var m int;
m, err = x.r.Read(x.crypt[off:x.blockSize]);
x.crypt = x.crypt[0:off+m];
if m == 0 {
break;
}
// If an error happened but we got enough
// data to do some decryption, we can decrypt
// first and report the error (with some data) later.
// But if we don't have enough to decrypt,
// have to stop now.
if err != nil && len(x.crypt) < x.blockSize {
break;
}
}
return err;
}
// Read from plain text buffer into p.
func (x *ecbDecrypter) readPlain(p []byte) int {
n := len(x.plain);
if n > len(p) {
n = len(p);
}
for i := 0; i < n; i++ {
p[i] = x.plain[i];
}
if n < len(x.plain) {
x.plain = x.plain[n:len(x.plain)];
} else {
x.plain = nil;
}
return n;
}
type ecbFragmentError int
func (n ecbFragmentError) String() string {
return "crypto/block: " + strconv.Itoa(int(n)) + "-byte fragment at EOF";
}
func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) {
if len(p) == 0 {
return;
}
// If there's no plaintext waiting and p is not big enough
// to hold a whole cipher block, we'll have to work in the
// cipher text buffer. Set it to non-nil so that the
// code below will fill it.
if x.plain == nil && len(p) < x.blockSize && x.crypt == nil {
x.crypt = x.buf[0:0];
}
// If there is a leftover cipher text buffer,
// try to accumulate a full block.
if x.crypt != nil {
err = x.fillCrypt();
if err != nil || len(x.crypt) == 0 {
return;
}
x.c.Decrypt(x.crypt, x.crypt);
x.plain = x.crypt;
x.crypt = nil;
}
// If there is a leftover plain text buffer, read from it.
if x.plain != nil {
n = x.readPlain(p);
return;
}
// Read and decrypt directly in caller's buffer.
n, err = io.ReadAtLeast(x.r, p, x.blockSize);
if err == os.EOF && n > 0 {
// EOF is only okay on block boundary
err = os.ErrorString("block fragment at EOF during decryption");
return;
}
var i int;
for i = 0; i+x.blockSize <= n; i += x.blockSize {
a := p[i:i+x.blockSize];
x.c.Decrypt(a, a);
}
// There might be an encrypted fringe remaining.
// Save it for next time.
if i < n {
p = p[i:n];
for j, v := range p {
x.buf[j] = v;
}
x.crypt = x.buf[0:len(p)];
n = i;
}
return;
}
// NewECBDecrypter returns a reader that reads data from r and decrypts it using c.
// It decrypts by calling c.Decrypt on each block in sequence;
// this mode is known as electronic codebook mode, or ECB.
// The returned Reader does not buffer or read ahead except
// as required by the cipher's block size.
func NewECBDecrypter(c Cipher, r io.Reader) io.Reader {
x := new(ecbDecrypter);
x.c = c;
x.r = r;
x.blockSize = c.BlockSize();
x.buf = make([]byte, x.blockSize);
return x;
}
type ecbEncrypter struct {
c Cipher;
w io.Writer;
blockSize int;
// Buffered data.
// The buffer buf is used as storage for both
// plain or crypt. If both are non-nil, plain
// follows crypt in buf.
buf []byte;
plain []byte; // plain text waiting to be encrypted
crypt []byte; // encrypted text waiting to be written
}
// Flush the x.crypt buffer to x.w.
func (x *ecbEncrypter) flushCrypt() os.Error {
if len(x.crypt) == 0 {
return nil;
}
n, err := x.w.Write(x.crypt);
if n < len(x.crypt) {
x.crypt = x.crypt[n:len(x.crypt)];
if err == nil {
err = io.ErrShortWrite;
}
}
if err != nil {
return err;
}
x.crypt = nil;
return nil;
}
// Slide x.plain down to the beginning of x.buf.
// Plain is known to have less than one block of data,
// so this is cheap enough.
func (x *ecbEncrypter) slidePlain() {
if len(x.plain) == 0 {
x.plain = x.buf[0:0];
} else if cap(x.plain) < cap(x.buf) {
// plain and buf share same data,
// but buf is before plain, so forward loop is correct
for i := 0; i < len(x.plain); i++ {
x.buf[i] = x.plain[i];
}
x.plain = x.buf[0:len(x.plain)];
}
}
// Fill x.plain from the data in p.
// Return the number of bytes copied.
func (x *ecbEncrypter) fillPlain(p []byte) int {
off := len(x.plain);
n := len(p);
if max := cap(x.plain) - off; n > max {
n = max;
}
x.plain = x.plain[0:off+n];
for i := 0; i < n; i++ {
x.plain[off + i] = p[i];
}
return n;
}
// Encrypt x.plain; record encrypted range as x.crypt.
func (x *ecbEncrypter) encrypt() {
var i int;
n := len(x.plain);
for i = 0; i+x.blockSize <= n; i += x.blockSize {
a := x.plain[i:i+x.blockSize];
x.c.Encrypt(a, a);
}
x.crypt = x.plain[0:i];
x.plain = x.plain[i:n];
}
func (x *ecbEncrypter) Write(p []byte) (n int, err os.Error) {
for {
// If there is data waiting to be written, write it.
// This can happen on the first iteration
// if a write failed in an earlier call.
if err = x.flushCrypt(); err != nil {
return;
}
// Now that encrypted data is gone (flush ran),
// perhaps we need to slide the plaintext down.
x.slidePlain();
// Fill plaintext buffer from p.
m := x.fillPlain(p);
if m == 0 {
break;
}
n += m;
p = p[m:len(p)];
// Encrypt, adjusting crypt and plain.
x.encrypt();
// Write x.crypt.
if err = x.flushCrypt(); err != nil {
break;
}
}
return;
}
// NewECBEncrypter returns a writer that encrypts data using c and writes it to w.
// It encrypts by calling c.Encrypt on each block in sequence;
// this mode is known as electronic codebook mode, or ECB.
// The returned Writer does no buffering except as required
// by the cipher's block size, so there is no need for a Flush method.
func NewECBEncrypter(c Cipher, w io.Writer) io.Writer {
x := new(ecbEncrypter);
x.c = c;
x.w = w;
x.blockSize = c.BlockSize();
// Create a buffer that is an integral number of blocks.
x.buf = make([]byte, 8192/x.blockSize * x.blockSize);
return x;
}