Plan 9 from Bell Labs’s /usr/web/sources/contrib/ericvh/go-plan9/src/pkg/crypto/block/ecb.go

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


// 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:]
	} 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:];
		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:];

		// 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;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].