// 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/alias" "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 alias.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:] } }