1 // Copyright 2011 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 // OFB (Output Feedback) Mode.
6 7 package cipher
8 9 import (
10 "crypto/internal/fips140/alias"
11 "crypto/internal/fips140only"
12 "crypto/subtle"
13 )
14 15 type ofb struct {
16 b Block
17 cipher []byte
18 out []byte
19 outUsed int
20 }
21 22 // NewOFB returns a [Stream] that encrypts or decrypts using the block cipher b
23 // in output feedback mode. The initialization vector iv's length must be equal
24 // to b's block size.
25 //
26 // Deprecated: OFB mode is not authenticated, which generally enables active
27 // attacks to manipulate and recover the plaintext. It is recommended that
28 // applications use [AEAD] modes instead. The standard library implementation of
29 // OFB is also unoptimized and not validated as part of the FIPS 140-3 module.
30 // If an unauthenticated [Stream] mode is required, use [NewCTR] instead.
31 func NewOFB(b Block, iv []byte) Stream {
32 if fips140only.Enabled {
33 panic("crypto/cipher: use of OFB is not allowed in FIPS 140-only mode")
34 }
35 36 blockSize := b.BlockSize()
37 if len(iv) != blockSize {
38 panic("cipher.NewOFB: IV length must equal block size")
39 }
40 bufSize := streamBufferSize
41 if bufSize < blockSize {
42 bufSize = blockSize
43 }
44 x := &ofb{
45 b: b,
46 cipher: []byte{:blockSize},
47 out: []byte{:0:bufSize},
48 outUsed: 0,
49 }
50 51 copy(x.cipher, iv)
52 return x
53 }
54 55 func (x *ofb) refill() {
56 bs := x.b.BlockSize()
57 remain := len(x.out) - x.outUsed
58 if remain > x.outUsed {
59 return
60 }
61 copy(x.out, x.out[x.outUsed:])
62 x.out = x.out[:cap(x.out)]
63 for remain < len(x.out)-bs {
64 x.b.Encrypt(x.cipher, x.cipher)
65 copy(x.out[remain:], x.cipher)
66 remain += bs
67 }
68 x.out = x.out[:remain]
69 x.outUsed = 0
70 }
71 72 func (x *ofb) XORKeyStream(dst, src []byte) {
73 if len(dst) < len(src) {
74 panic("crypto/cipher: output smaller than input")
75 }
76 if alias.InexactOverlap(dst[:len(src)], src) {
77 panic("crypto/cipher: invalid buffer overlap")
78 }
79 for len(src) > 0 {
80 if x.outUsed >= len(x.out)-x.b.BlockSize() {
81 x.refill()
82 }
83 n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
84 dst = dst[n:]
85 src = src[n:]
86 x.outUsed += n
87 }
88 }
89