-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathrandctr.go
75 lines (68 loc) · 1.8 KB
/
randctr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package enigma
import (
"crypto/cipher"
)
// randCTR is a CTR block mode implementation that supports
// random access. It delegates to the true golang's CTR
// while adding a few features to it.
//
// Delegating to golang's implementation is a consideration
// for performance, as golang's standard library has done
// some optimization upon it.
//
// XXX: this implementation relies strongly on the internal
// implementation of crypto/cipher's CTR, which interprets
// the block as a very-large integer and increments the
// cipher block's counter. We will either continue on using
// the cipher or recreates a key stream block by tweaking.
type randCTR struct {
b cipher.Block
iv []byte
offset uint64
inner cipher.Stream
}
func newRandCTR(block cipher.Block, iv []byte) *randCTR {
return &randCTR{
b: block,
iv: iv,
offset: 0,
inner: cipher.NewCTR(block, iv),
}
}
func (ctr *randCTR) recreate() *randCTR {
return newRandCTR(ctr.b, ctr.iv)
}
func (ctr *randCTR) XORKeyStream(dst, src []byte) {
ctr.inner.XORKeyStream(dst, src)
ctr.offset += uint64(len(src))
}
func (ctr *randCTR) Tell() uint64 {
return ctr.offset
}
func (ctr *randCTR) Seek(offset uint64) {
if offset == ctr.offset {
return
}
blockSize := ctr.b.BlockSize()
blockSkip := offset % uint64(blockSize)
blockCtr := offset / uint64(blockSize)
newIV := make([]byte, blockSize)
carrier := uint64(0)
remaining := blockCtr
for i := blockSize; i > 0; i-- {
current := remaining & uint64(0x0ff)
remaining >>= 8
next := uint64(uint8(ctr.iv[i-1])) + current + carrier
if next > uint64(0x0ff) {
carrier = 1
} else {
carrier = 0
}
newIV[i-1] = byte(next)
}
newCtr := cipher.NewCTR(ctr.b, newIV)
temp := make([]byte, int(blockSkip))
newCtr.XORKeyStream(temp, temp)
ctr.offset = offset
ctr.inner = newCtr
}