Eric Roshan Eisner avatar Eric Roshan Eisner committed 18d49b5 Draft

add stream cipher support

Comments (0)

Files changed (3)

 	for i := 0; i < d.blocksize; i += 8 {
 		writeLane(d.buf[i:i+8], d.state[i/8])
 	}
-	d.n = 0
 }
 
 // Write uses d.buf to buffer calls to d.absorb from arbitrary sized inputs.
 	return append(in, d.buf[:d.size]...)
 }
 
-// TODO: func (d *keccak) Stream() io.Reader
-
 func readLane(b []byte) uint64 {
 	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
 }
+package sha3
+
+import (
+	"crypto/cipher"
+)
+
+func NewCipher(key []byte) cipher.Stream {
+	c := newSHA3(256)
+	c.Write(key)
+	c.pad()
+	c.n = c.blocksize
+	return c
+}
+
+func (c *keccak) XORKeyStream(dst, src []byte) {
+	if len(dst) != len(src) {
+		panic("XORKeyStream: dst and src are different lengths")
+	}
+	// using buf[n:blocksize] to store unread data, buffer calls to
+	// squeeze. (0 < n <= blocksize when reading)
+	if c.n < c.blocksize {
+		if len(dst) < c.blocksize-c.n {
+			c.n += xor(dst, src, c.buf[c.n:])
+			return
+		} else {
+			n := xor(dst, src, c.buf[c.n:c.blocksize])
+			dst = dst[n:]
+			src = src[n:]
+			c.n = c.blocksize
+		}
+	}
+
+	for len(dst) >= c.blocksize {
+		c.squeeze()
+		n := xor(dst, src, c.buf[:c.blocksize])
+		dst = dst[n:]
+		src = src[n:]
+	}
+
+	if len(dst) > 0 {
+		c.squeeze()
+		c.n = xor(dst, src, c.buf[:c.blocksize])
+	}
+}
+
+func xor(dst, x, y []byte) (n int) {
+	for ; n < len(x) && n < len(y); n++ {
+		dst[n] = x[n] ^ y[n]
+	}
+	return
+}
+package sha3
+
+import "testing"
+
+func TestStreamRoundtrip(t *testing.T) {
+	key := []byte("key")
+	b := make([]byte, 41<<10)
+	enc := NewCipher(key)
+	for i := 0; i < len(b); i += 41 {
+		enc.XORKeyStream(b[i:i+41], b[i:i+41])
+	}
+
+	allZero := true
+	for _, c := range b {
+		if c != 0 {
+			allZero = false
+			break
+		}
+	}
+	if allZero {
+		t.Fatalf("Nothing got ciphered.")
+	}
+
+	dec := NewCipher(key)
+	dec.XORKeyStream(b, b)
+
+	for i, c := range b {
+		if c != 0 {
+			t.Fatalf("Cipher roundtrip mismatch at byte %d", i)
+		}
+	}
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.