github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/crypto/cipher/ctr.go (about) 1 // Copyright 2009 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 // Counter (CTR) mode. 6 7 // CTR converts a block cipher into a stream cipher by 8 // repeatedly encrypting an incrementing counter and 9 // xoring the resulting stream of data with the input. 10 11 // See NIST SP 800-38A, pp 13-15 12 13 package cipher 14 15 import "crypto/internal/subtle" 16 17 type ctr struct { 18 b Block 19 ctr []byte 20 out []byte 21 outUsed int 22 } 23 24 const streamBufferSize = 512 25 26 // ctrAble is an interface implemented by ciphers that have a specific optimized 27 // implementation of CTR, like crypto/aes. NewCTR will check for this interface 28 // and return the specific Stream if found. 29 type ctrAble interface { 30 NewCTR(iv []byte) Stream 31 } 32 33 // NewCTR returns a Stream which encrypts/decrypts using the given Block in 34 // counter mode. The length of iv must be the same as the Block's block size. 35 func NewCTR(block Block, iv []byte) Stream { 36 if ctr, ok := block.(ctrAble); ok { 37 return ctr.NewCTR(iv) 38 } 39 if len(iv) != block.BlockSize() { 40 panic("cipher.NewCTR: IV length must equal block size") 41 } 42 bufSize := streamBufferSize 43 if bufSize < block.BlockSize() { 44 bufSize = block.BlockSize() 45 } 46 return &ctr{ 47 b: block, 48 ctr: dup(iv), 49 out: make([]byte, 0, bufSize), 50 outUsed: 0, 51 } 52 } 53 54 func (x *ctr) refill() { 55 remain := len(x.out) - x.outUsed 56 copy(x.out, x.out[x.outUsed:]) 57 x.out = x.out[:cap(x.out)] 58 bs := x.b.BlockSize() 59 for remain <= len(x.out)-bs { 60 x.b.Encrypt(x.out[remain:], x.ctr) 61 remain += bs 62 63 // Increment counter 64 for i := len(x.ctr) - 1; i >= 0; i-- { 65 x.ctr[i]++ 66 if x.ctr[i] != 0 { 67 break 68 } 69 } 70 } 71 x.out = x.out[:remain] 72 x.outUsed = 0 73 } 74 75 func (x *ctr) XORKeyStream(dst, src []byte) { 76 if len(dst) < len(src) { 77 panic("crypto/cipher: output smaller than input") 78 } 79 if subtle.InexactOverlap(dst[:len(src)], src) { 80 panic("crypto/cipher: invalid buffer overlap") 81 } 82 for len(src) > 0 { 83 if x.outUsed >= len(x.out)-x.b.BlockSize() { 84 x.refill() 85 } 86 n := xorBytes(dst, src, x.out[x.outUsed:]) 87 dst = dst[n:] 88 src = src[n:] 89 x.outUsed += n 90 } 91 }