--- /dev/null
+// Copyright 2016 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.
+
+package aes
+
+import (
+ "crypto/cipher"
+ "unsafe"
+)
+
+// Assert that aesCipherAsm implements the ctrAble interface.
+var _ ctrAble = (*aesCipherAsm)(nil)
+
+// xorBytes xors the contents of a and b and places the resulting values into
+// dst. If a and b are not the same length then the number of bytes processed
+// will be equal to the length of shorter of the two. Returns the number
+// of bytes processed.
+//go:noescape
+func xorBytes(dst, a, b []byte) int
+
+// streamBufferSize is the number of bytes of encrypted counter values to cache.
+const streamBufferSize = 32 * BlockSize
+
+type aesctr struct {
+ block *aesCipherAsm // block cipher
+ ctr [2]uint64 // next value of the counter (big endian)
+ buffer []byte // buffer for the encrypted counter values
+ storage [streamBufferSize]byte // array backing buffer slice
+}
+
+// NewCTR returns a Stream which encrypts/decrypts using the AES block
+// cipher in counter mode. The length of iv must be the same as BlockSize.
+func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream {
+ if len(iv) != BlockSize {
+ panic("cipher.NewCTR: IV length must equal block size")
+ }
+ var ac aesctr
+ ac.block = c
+ ac.ctr[0] = *(*uint64)(unsafe.Pointer((&iv[0]))) // high bits
+ ac.ctr[1] = *(*uint64)(unsafe.Pointer((&iv[8]))) // low bits
+ ac.buffer = ac.storage[:0]
+ return &ac
+}
+
+func (c *aesctr) refill() {
+ // Fill up the buffer with an incrementing count.
+ c.buffer = c.storage[:streamBufferSize]
+ c0, c1 := c.ctr[0], c.ctr[1]
+ for i := 0; i < streamBufferSize; i += BlockSize {
+ b0 := (*uint64)(unsafe.Pointer(&c.buffer[i]))
+ b1 := (*uint64)(unsafe.Pointer(&c.buffer[i+BlockSize/2]))
+ *b0, *b1 = c0, c1
+ // Increment in big endian: c0 is high, c1 is low.
+ c1++
+ if c1 == 0 {
+ // add carry
+ c0++
+ }
+ }
+ c.ctr[0], c.ctr[1] = c0, c1
+ // Encrypt the buffer using AES in ECB mode.
+ cryptBlocks(c.block.function, &c.block.key[0], &c.buffer[0], &c.buffer[0], streamBufferSize)
+}
+
+func (c *aesctr) XORKeyStream(dst, src []byte) {
+ for len(src) > 0 {
+ if len(c.buffer) == 0 {
+ c.refill()
+ }
+ n := xorBytes(dst, src, c.buffer)
+ c.buffer = c.buffer[n:]
+ src = src[n:]
+ dst = dst[n:]
+ }
+}
func (*testBlock) NewCBCDecrypter([]byte) cipher.BlockMode {
return &testBlockMode{}
}
+func (*testBlock) NewCTR([]byte) cipher.Stream {
+ return &testStream{}
+}
// testAEAD implements the cipher.AEAD interface.
type testAEAD struct{}
t.Fatalf("cipher.NewCBCDecrypter did not use cbcDecAble interface")
}
}
+
+// testStream implements the cipher.Stream interface.
+type testStream struct{}
+
+func (*testStream) XORKeyStream(a, b []byte) {}
+func (*testStream) InAESPackage() bool { return true }
+
+// Test the ctrAble interface is detected correctly by the cipher package.
+func TestCTRAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(ctrAble); !ok {
+ t.Fatalf("testBlock does not implement the ctrAble interface")
+ }
+ s := cipher.NewCTR(b, []byte{})
+ if _, ok := s.(testInterface); !ok {
+ t.Fatalf("cipher.NewCTR did not use ctrAble interface")
+ }
+}
const streamBufferSize = 512
+// ctrAble is an interface implemented by ciphers that have a specific optimized
+// implementation of CTR, like crypto/aes. NewCTR will check for this interface
+// and return the specific Stream if found.
+type ctrAble interface {
+ NewCTR(iv []byte) Stream
+}
+
// NewCTR returns a Stream which encrypts/decrypts using the given Block in
// counter mode. The length of iv must be the same as the Block's block size.
func NewCTR(block Block, iv []byte) Stream {
+ if ctr, ok := block.(ctrAble); ok {
+ return ctr.NewCTR(iv)
+ }
if len(iv) != block.BlockSize() {
panic("cipher.NewCTR: IV length must equal block size")
}