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