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//go:build !purego 6 7package aes 8 9import ( 10 "crypto/cipher" 11 "crypto/internal/alias" 12 "internal/byteorder" 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// 23//go:noescape 24func xorBytes(dst, a, b []byte) int 25 26// streamBufferSize is the number of bytes of encrypted counter values to cache. 27const streamBufferSize = 32 * BlockSize 28 29type aesctr struct { 30 block *aesCipherAsm // block cipher 31 ctr [2]uint64 // next value of the counter (big endian) 32 buffer []byte // buffer for the encrypted counter values 33 storage [streamBufferSize]byte // array backing buffer slice 34} 35 36// NewCTR returns a Stream which encrypts/decrypts using the AES block 37// cipher in counter mode. The length of iv must be the same as [BlockSize]. 38func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream { 39 if len(iv) != BlockSize { 40 panic("cipher.NewCTR: IV length must equal block size") 41 } 42 var ac aesctr 43 ac.block = c 44 ac.ctr[0] = byteorder.BeUint64(iv[0:]) // high bits 45 ac.ctr[1] = byteorder.BeUint64(iv[8:]) // low bits 46 ac.buffer = ac.storage[:0] 47 return &ac 48} 49 50func (c *aesctr) refill() { 51 // Fill up the buffer with an incrementing count. 52 c.buffer = c.storage[:streamBufferSize] 53 c0, c1 := c.ctr[0], c.ctr[1] 54 for i := 0; i < streamBufferSize; i += 16 { 55 byteorder.BePutUint64(c.buffer[i+0:], c0) 56 byteorder.BePutUint64(c.buffer[i+8:], c1) 57 58 // Increment in big endian: c0 is high, c1 is low. 59 c1++ 60 if c1 == 0 { 61 // add carry 62 c0++ 63 } 64 } 65 c.ctr[0], c.ctr[1] = c0, c1 66 // Encrypt the buffer using AES in ECB mode. 67 cryptBlocks(c.block.function, &c.block.key[0], &c.buffer[0], &c.buffer[0], streamBufferSize) 68} 69 70func (c *aesctr) XORKeyStream(dst, src []byte) { 71 if len(dst) < len(src) { 72 panic("crypto/cipher: output smaller than input") 73 } 74 if alias.InexactOverlap(dst[:len(src)], src) { 75 panic("crypto/cipher: invalid buffer overlap") 76 } 77 for len(src) > 0 { 78 if len(c.buffer) == 0 { 79 c.refill() 80 } 81 n := xorBytes(dst, src, c.buffer) 82 c.buffer = c.buffer[n:] 83 src = src[n:] 84 dst = dst[n:] 85 } 86} 87