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