| | |
| | |
| | |
| |
|
| | |
| |
|
| | |
| | |
| | |
| |
|
| | |
| |
|
| | package cipher |
| |
|
| | import ( |
| | "bytes" |
| | "crypto/internal/fips140/aes" |
| | "crypto/internal/fips140/alias" |
| | "crypto/internal/fips140only" |
| | "crypto/subtle" |
| | ) |
| |
|
| | type ctr struct { |
| | b Block |
| | ctr []byte |
| | out []byte |
| | outUsed int |
| | } |
| |
|
| | const streamBufferSize = 512 |
| |
|
| | |
| | |
| | |
| | type ctrAble interface { |
| | NewCTR(iv []byte) Stream |
| | } |
| |
|
| | |
| | |
| | func NewCTR(block Block, iv []byte) Stream { |
| | if block, ok := block.(*aes.Block); ok { |
| | return aesCtrWrapper{aes.NewCTR(block, iv)} |
| | } |
| | if fips140only.Enforced() { |
| | panic("crypto/cipher: use of CTR with non-AES ciphers is not allowed in FIPS 140-only mode") |
| | } |
| | if ctr, ok := block.(ctrAble); ok { |
| | return ctr.NewCTR(iv) |
| | } |
| | if len(iv) != block.BlockSize() { |
| | panic("cipher.NewCTR: IV length must equal block size") |
| | } |
| | bufSize := streamBufferSize |
| | if bufSize < block.BlockSize() { |
| | bufSize = block.BlockSize() |
| | } |
| | return &ctr{ |
| | b: block, |
| | ctr: bytes.Clone(iv), |
| | out: make([]byte, 0, bufSize), |
| | outUsed: 0, |
| | } |
| | } |
| |
|
| | |
| | type aesCtrWrapper struct { |
| | c *aes.CTR |
| | } |
| |
|
| | func (x aesCtrWrapper) XORKeyStream(dst, src []byte) { |
| | x.c.XORKeyStream(dst, src) |
| | } |
| |
|
| | func (x *ctr) refill() { |
| | remain := len(x.out) - x.outUsed |
| | copy(x.out, x.out[x.outUsed:]) |
| | x.out = x.out[:cap(x.out)] |
| | bs := x.b.BlockSize() |
| | for remain <= len(x.out)-bs { |
| | x.b.Encrypt(x.out[remain:], x.ctr) |
| | remain += bs |
| |
|
| | |
| | for i := len(x.ctr) - 1; i >= 0; i-- { |
| | x.ctr[i]++ |
| | if x.ctr[i] != 0 { |
| | break |
| | } |
| | } |
| | } |
| | x.out = x.out[:remain] |
| | x.outUsed = 0 |
| | } |
| |
|
| | func (x *ctr) XORKeyStream(dst, src []byte) { |
| | if len(dst) < len(src) { |
| | panic("crypto/cipher: output smaller than input") |
| | } |
| | if alias.InexactOverlap(dst[:len(src)], src) { |
| | panic("crypto/cipher: invalid buffer overlap") |
| | } |
| | if _, ok := x.b.(*aes.Block); ok { |
| | panic("crypto/cipher: internal error: generic CTR used with AES") |
| | } |
| | for len(src) > 0 { |
| | if x.outUsed >= len(x.out)-x.b.BlockSize() { |
| | x.refill() |
| | } |
| | n := subtle.XORBytes(dst, src, x.out[x.outUsed:]) |
| | dst = dst[n:] |
| | src = src[n:] |
| | x.outUsed += n |
| | } |
| | } |
| |
|