github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/bsaes/internal/modes/ctr.go (about)

     1  // Copyright (c) 2017 Yawning Angel <yawning at schwanenlied dot me>
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining
     4  // a copy of this software and associated documentation files (the
     5  // "Software"), to deal in the Software without restriction, including
     6  // without limitation the rights to use, copy, modify, merge, publish,
     7  // distribute, sublicense, and/or sell copies of the Software, and to
     8  // permit persons to whom the Software is furnished to do so, subject to
     9  // the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be
    12  // included in all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    15  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    16  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    17  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
    18  // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    19  // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    20  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    21  // SOFTWARE.
    22  
    23  package modes
    24  
    25  import (
    26  	"crypto/cipher"
    27  	"runtime"
    28  )
    29  
    30  func (m *BlockModesImpl) NewCTR(iv []byte) cipher.Stream {
    31  	ecb := m.b.(bulkECBAble)
    32  	if len(iv) != ecb.BlockSize() {
    33  		panic("bsaes/NewCTR: iv size does not match block size")
    34  	}
    35  
    36  	return newCTRImpl(ecb, iv)
    37  }
    38  
    39  type ctrImpl struct {
    40  	ecb bulkECBAble
    41  	ctr [blockSize]byte
    42  	buf []byte
    43  	idx int
    44  
    45  	stride int
    46  }
    47  
    48  func (c *ctrImpl) Reset() {
    49  	for i := range c.buf {
    50  		c.buf[i] = 0
    51  	}
    52  }
    53  
    54  func (c *ctrImpl) XORKeyStream(dst, src []byte) {
    55  	for len(src) > 0 {
    56  		if c.idx >= len(c.buf) {
    57  			c.generateKeyStream()
    58  			c.idx = 0
    59  		}
    60  
    61  		n := len(c.buf) - c.idx
    62  		if sLen := len(src); sLen < n {
    63  			n = sLen
    64  		}
    65  		for i, v := range src[:n] {
    66  			dst[i] = v ^ c.buf[c.idx+i]
    67  		}
    68  
    69  		dst, src = dst[n:], src[n:]
    70  		c.idx += n
    71  	}
    72  }
    73  
    74  func (c *ctrImpl) generateKeyStream() {
    75  	for i := 0; i < c.stride; i++ {
    76  		copy(c.buf[i*blockSize:], c.ctr[:])
    77  
    78  		// Increment counter.
    79  		for j := blockSize; j > 0; j-- {
    80  			c.ctr[j-1]++
    81  			if c.ctr[j-1] != 0 {
    82  				break
    83  			}
    84  		}
    85  	}
    86  	c.ecb.BulkEncrypt(c.buf, c.buf)
    87  }
    88  
    89  func newCTRImpl(ecb bulkECBAble, iv []byte) cipher.Stream {
    90  	c := new(ctrImpl)
    91  	c.ecb = ecb
    92  	c.stride = ecb.Stride()
    93  	copy(c.ctr[:], iv)
    94  	c.buf = make([]byte, c.stride*blockSize)
    95  	c.idx = len(c.buf)
    96  
    97  	runtime.SetFinalizer(c, (*ctrImpl).Reset)
    98  
    99  	return c
   100  }