summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/block/ecb.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/block/ecb.go')
-rw-r--r--libgo/go/crypto/block/ecb.go270
1 files changed, 270 insertions, 0 deletions
diff --git a/libgo/go/crypto/block/ecb.go b/libgo/go/crypto/block/ecb.go
new file mode 100644
index 000000000..cf09f7cb3
--- /dev/null
+++ b/libgo/go/crypto/block/ecb.go
@@ -0,0 +1,270 @@
+// 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]
+ copy(x.buf, p)
+ 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) {
+ copy(x.buf, x.plain)
+ 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
+}