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