1// Copyright 2016 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// +build ignore 6 7package aes 8 9import ( 10 "crypto/cipher" 11 "crypto/internal/subtle" 12 "encoding/binary" 13) 14 15// Assert that aesCipherAsm implements the ctrAble interface. 16var _ ctrAble = (*aesCipherAsm)(nil) 17 18// xorBytes xors the contents of a and b and places the resulting values into 19// dst. If a and b are not the same length then the number of bytes processed 20// will be equal to the length of shorter of the two. Returns the number 21// of bytes processed. 22//go:noescape 23func xorBytes(dst, a, b []byte) int 24 25// streamBufferSize is the number of bytes of encrypted counter values to cache. 26const streamBufferSize = 32 * BlockSize 27 28type aesctr struct { 29 block *aesCipherAsm // block cipher 30 ctr [2]uint64 // next value of the counter (big endian) 31 buffer []byte // buffer for the encrypted counter values 32 storage [streamBufferSize]byte // array backing buffer slice 33} 34 35// NewCTR returns a Stream which encrypts/decrypts using the AES block 36// cipher in counter mode. The length of iv must be the same as BlockSize. 37func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream { 38 if len(iv) != BlockSize { 39 panic("cipher.NewCTR: IV length must equal block size") 40 } 41 var ac aesctr 42 ac.block = c 43 ac.ctr[0] = binary.BigEndian.Uint64(iv[0:]) // high bits 44 ac.ctr[1] = binary.BigEndian.Uint64(iv[8:]) // low bits 45 ac.buffer = ac.storage[:0] 46 return &ac 47} 48 49func (c *aesctr) refill() { 50 // Fill up the buffer with an incrementing count. 51 c.buffer = c.storage[:streamBufferSize] 52 c0, c1 := c.ctr[0], c.ctr[1] 53 for i := 0; i < streamBufferSize; i += 16 { 54 binary.BigEndian.PutUint64(c.buffer[i+0:], c0) 55 binary.BigEndian.PutUint64(c.buffer[i+8:], c1) 56 57 // Increment in big endian: c0 is high, c1 is low. 58 c1++ 59 if c1 == 0 { 60 // add carry 61 c0++ 62 } 63 } 64 c.ctr[0], c.ctr[1] = c0, c1 65 // Encrypt the buffer using AES in ECB mode. 66 cryptBlocks(c.block.function, &c.block.key[0], &c.buffer[0], &c.buffer[0], streamBufferSize) 67} 68 69func (c *aesctr) XORKeyStream(dst, src []byte) { 70 if len(dst) < len(src) { 71 panic("crypto/cipher: output smaller than input") 72 } 73 if subtle.InexactOverlap(dst[:len(src)], src) { 74 panic("crypto/cipher: invalid buffer overlap") 75 } 76 for len(src) > 0 { 77 if len(c.buffer) == 0 { 78 c.refill() 79 } 80 n := xorBytes(dst, src, c.buffer) 81 c.buffer = c.buffer[n:] 82 src = src[n:] 83 dst = dst[n:] 84 } 85} 86