ofb.mx raw

   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