Skip to content

Commit

Permalink
added crypto.NewReader/NewWriter to support stream (en|de)cryption.
Browse files Browse the repository at this point in the history
  • Loading branch information
OneOfOne committed Aug 27, 2014
1 parent 9bcae73 commit 5f1a0d3
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
53 changes: 53 additions & 0 deletions crypto/crypto_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package crypto

import (
"bytes"
"crypto/des"
"io/ioutil"
"testing"
)

var (
iv = GenerateAesIV()
key = GenerateKey(192, []byte(`I'm Jack's Wasted Life`))
msg = []byte(`I'm Jack's Complete Lack Of Surprise.`)
)

func TestAes(t *testing.T) {
b := &bytes.Buffer{}
enc, err := NewAesWriter(b, iv, key)
if err != nil {
t.Error(err)
return
}
enc.Write(msg)
emsg := b.Bytes()
dec, err := NewAesReader(b, iv, key)
if err != nil {
t.Error(err)
return
}

dmsg, _ := ioutil.ReadAll(dec)
t.Logf("\niv (%2d): %x\nkey (%2d): %x\nenc (%d): %x\ndec (%d): %s\n", len(iv), iv, len(key), key, len(emsg), emsg, len(dmsg), dmsg)
}

func BenchmarkAes(b *testing.B) {
buf := &bytes.Buffer{}
enc, _ := NewAesWriter(buf, iv, key)
dec, _ := NewAesReader(buf, iv, key)
for i := 0; i < b.N; i++ {
enc.Write(msg)
ioutil.ReadAll(dec)
}
}

func BenchmarkTripleDes(b *testing.B) {
buf := &bytes.Buffer{}
enc, _ := NewWriter(buf, iv[:8], key, des.NewTripleDESCipher)
dec, _ := NewReader(buf, iv[:8], key, des.NewTripleDESCipher)
for i := 0; i < b.N; i++ {
enc.Write(msg)
ioutil.ReadAll(dec)
}
}
48 changes: 48 additions & 0 deletions crypto/misc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package crypto

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
)

type CryptoInitilizer func(key []byte) (cipher.Block, error)

// ZeroSlice sets all the bytes in a slice to 0, should be used on keys and IVs.
func ZeroSlice(p []byte) {
for i := range p {
p[i] = 0
}
}

// GenerateIV generates an IV for the given blocksize
func GenerateIV(blockSize int) (p []byte) {
p = make([]byte, blockSize)
if _, err := rand.Read(p); err != nil {
panic(err)
}
return
}

// GenerateAesIV generates an IV with AES's BlockSize
func GenerateAesIV() []byte {
return GenerateIV(aes.BlockSize)
}

// GenerateKey generates a hashed key based on the number of bits
func GenerateKey(bits int, key []byte) []byte {
if bits%64 != 0 || bits < 128 {
panic("bits % 64 != 0 || bits < 128")
}
n := bits / 8
p := make([]byte, n+(n%32))

for i := 0; i < n; i += 32 { // future proof in case we need a key larger than 256 bits
tmp := append(p, key...)
h := sha256.Sum256(tmp)
copy(p[i:], h[:])
ZeroSlice(tmp)
}
return p[:n:n]
}
40 changes: 40 additions & 0 deletions crypto/reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package crypto

import (
"crypto/aes"
"crypto/cipher"
"io"
)

type reader struct {
dec cipher.Stream
r io.Reader
}

// NewReader returns a new Reader with the specific crypto Algroithm
// Note that it uses CFB mode for streams.
func NewReader(r io.Reader, iv, key []byte, init CryptoInitilizer) (io.Reader, error) {
c, err := init(key)
if err != nil {
return nil, err
}
rd := &reader{
dec: cipher.NewCFBDecrypter(c, iv),
r: r,
}
return rd, nil
}

func (r *reader) Read(p []byte) (n int, err error) {
in := make([]byte, len(p))
if n, err = r.r.Read(in); err != nil {
return
}
r.dec.XORKeyStream(p, in)
return
}

// NewAesReader an alias for NewReader(r, iv, key, aes.NewCipher)
func NewAesReader(r io.Reader, iv, key []byte) (io.Reader, error) {
return NewReader(r, iv, key, aes.NewCipher)
}
37 changes: 37 additions & 0 deletions crypto/writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package crypto

import (
"crypto/aes"
"crypto/cipher"
"io"
)

type writer struct {
enc cipher.Stream
w io.Writer
}

// NewReader returns a new Reader with the specific crypto Algroithm
// Note that it uses CFB mode for streams.
func NewWriter(w io.Writer, iv, key []byte, init CryptoInitilizer) (io.Writer, error) {
c, err := init(key)
if err != nil {
return nil, err
}
wr := &writer{
enc: cipher.NewCFBEncrypter(c, iv),
w: w,
}
return wr, nil
}

func (w *writer) Write(p []byte) (n int, err error) {
out := make([]byte, len(p))
w.enc.XORKeyStream(out, p)
return w.w.Write(out)
}

// NewAesWriter alias for NewWriter(w, iv, key, aes.NewCipher)
func NewAesWriter(w io.Writer, iv, key []byte) (io.Writer, error) {
return NewWriter(w, iv, key, aes.NewCipher)
}

0 comments on commit 5f1a0d3

Please sign in to comment.