Source file src/crypto/cipher/ofb.go

     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:  make([]byte, blockSize),
    47  		out:     make([]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  

View as plain text