| // 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" |
| "crypto/internal/subtle" |
| "encoding/binary" |
| ) |
| |
| // 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] = binary.BigEndian.Uint64(iv[0:]) // high bits |
| ac.ctr[1] = binary.BigEndian.Uint64(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 += 16 { |
| binary.BigEndian.PutUint64(c.buffer[i+0:], c0) |
| binary.BigEndian.PutUint64(c.buffer[i+8:], 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) { |
| if len(dst) < len(src) { |
| panic("crypto/cipher: output smaller than input") |
| } |
| if subtle.InexactOverlap(dst[:len(src)], src) { |
| panic("crypto/cipher: invalid buffer overlap") |
| } |
| 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:] |
| } |
| } |