1// Copyright 2010 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// CFB (Cipher Feedback) Mode.
6
7package cipher
8
9import (
10	"crypto/internal/alias"
11	"crypto/subtle"
12)
13
14type cfb struct {
15	b       Block
16	next    []byte
17	out     []byte
18	outUsed int
19
20	decrypt bool
21}
22
23func (x *cfb) XORKeyStream(dst, src []byte) {
24	if len(dst) < len(src) {
25		panic("crypto/cipher: output smaller than input")
26	}
27	if alias.InexactOverlap(dst[:len(src)], src) {
28		panic("crypto/cipher: invalid buffer overlap")
29	}
30	for len(src) > 0 {
31		if x.outUsed == len(x.out) {
32			x.b.Encrypt(x.out, x.next)
33			x.outUsed = 0
34		}
35
36		if x.decrypt {
37			// We can precompute a larger segment of the
38			// keystream on decryption. This will allow
39			// larger batches for xor, and we should be
40			// able to match CTR/OFB performance.
41			copy(x.next[x.outUsed:], src)
42		}
43		n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
44		if !x.decrypt {
45			copy(x.next[x.outUsed:], dst)
46		}
47		dst = dst[n:]
48		src = src[n:]
49		x.outUsed += n
50	}
51}
52
53// NewCFBEncrypter returns a [Stream] which encrypts with cipher feedback mode,
54// using the given [Block]. The iv must be the same length as the [Block]'s block
55// size.
56func NewCFBEncrypter(block Block, iv []byte) Stream {
57	return newCFB(block, iv, false)
58}
59
60// NewCFBDecrypter returns a [Stream] which decrypts with cipher feedback mode,
61// using the given [Block]. The iv must be the same length as the [Block]'s block
62// size.
63func NewCFBDecrypter(block Block, iv []byte) Stream {
64	return newCFB(block, iv, true)
65}
66
67func newCFB(block Block, iv []byte, decrypt bool) Stream {
68	blockSize := block.BlockSize()
69	if len(iv) != blockSize {
70		// stack trace will indicate whether it was de or encryption
71		panic("cipher.newCFB: IV length must equal block size")
72	}
73	x := &cfb{
74		b:       block,
75		out:     make([]byte, blockSize),
76		next:    make([]byte, blockSize),
77		outUsed: blockSize,
78		decrypt: decrypt,
79	}
80	copy(x.next, iv)
81
82	return x
83}
84