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