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