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