Skip to content

Commit

Permalink
This feature allow ctr-aes support parallel XORKeyStream
Browse files Browse the repository at this point in the history
  • Loading branch information
izouxv committed Oct 2, 2023
1 parent deb8e29 commit 5954056
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 8 deletions.
71 changes: 63 additions & 8 deletions src/crypto/cipher/ctr.go
Expand Up @@ -19,10 +19,11 @@ import (
)

type ctr struct {
b Block
ctr []byte
out []byte
outUsed int
b Block
ctr []byte
out []byte
outUsed int
offsetPos int
}

const streamBufferSize = 512
Expand All @@ -36,7 +37,12 @@ type ctrAble interface {

// NewCTR returns a Stream which encrypts/decrypts using the given Block in
// counter mode. The length of iv must be the same as the Block's block size.

func NewCTR(block Block, iv []byte) Stream {
return NewCTRWithOffset(block, iv, 0)
}

func NewCTRWithOffset(block Block, iv []byte, offsetPos int) Stream {
if ctr, ok := block.(ctrAble); ok {
return ctr.NewCTR(iv)
}
Expand All @@ -48,13 +54,56 @@ func NewCTR(block Block, iv []byte) Stream {
bufSize = block.BlockSize()
}
return &ctr{
b: block,
ctr: bytes.Clone(iv),
out: make([]byte, 0, bufSize),
outUsed: 0,
offsetPos: offsetPos,
b: block,
ctr: IncreaseCtr(offsetPos, block.BlockSize(), iv),
out: make([]byte, 0, bufSize),
outUsed: 0,
}
}

func IncreaseCtr(offsetPos, BlockSize int, iv []byte) []byte {

iv = bytes.Clone(iv)

if len(iv) == 0 || offsetPos <= 0 || BlockSize <= 0 {
return iv
}


needAdd := offsetPos / BlockSize
index := 0

for {
add := needAdd & 0xff

tmpIv := iv[:len(iv)-index]
for i := len(tmpIv) - 1; i >= 0; i-- {
if i == len(tmpIv)-1 && int(tmpIv[i])+add > 255 {
tmpIv[i] = byte((int(tmpIv[i]) + add) % 256)
add = 1
continue
}
tmpIv[i] += byte(add)
if tmpIv[i] != 0 {
break
}
}

index++
if index >= len(iv) {
break
}

needAdd >>= 8
if needAdd <= 0 {
break
}
}

return iv
}

func (x *ctr) refill() {
remain := len(x.out) - x.outUsed
copy(x.out, x.out[x.outUsed:])
Expand All @@ -74,6 +123,12 @@ func (x *ctr) refill() {
}
x.out = x.out[:remain]
x.outUsed = 0

if x.offsetPos > 0 {
offset := x.offsetPos % x.b.BlockSize()
x.out = x.out[offset:]
x.offsetPos = 0
}
}

func (x *ctr) XORKeyStream(dst, src []byte) {
Expand Down
37 changes: 37 additions & 0 deletions src/crypto/cipher/ctr_aes_test.go
Expand Up @@ -100,3 +100,40 @@ func TestCTR_AES(t *testing.T) {
}
}
}

func TestCTRWithOffset_AES(t *testing.T) {
for _, tt := range ctrAESTests {
test := tt.name

c, err := aes.NewCipher(tt.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
continue
}

for j := 0; j <= 5; j += 5 {
in := tt.in[j : len(tt.in)-j]
ctr := cipher.NewCTRWithOffset(c, tt.iv, j)
encrypted := make([]byte, len(in))
ctr.XORKeyStream(encrypted, in)
if out := tt.out[j : len(in)+j]; !bytes.Equal(out, encrypted) {
t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
}
}

for j := 0; j <= 7; j += 7 {
in := tt.out[j : len(tt.out)-j]
ctr := cipher.NewCTRWithOffset(c, tt.iv, j)
plain := make([]byte, len(in))
ctr.XORKeyStream(plain, in)
if out := tt.in[j : len(in)+j]; !bytes.Equal(out, plain) {
t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
}
}

if t.Failed() {
break
}
}

}
46 changes: 46 additions & 0 deletions src/crypto/cipher/ctr_test.go
Expand Up @@ -53,3 +53,49 @@ func TestCTR(t *testing.T) {
}
}
}

var ctrAESIncreaseTests = []struct {
iv []byte
offset int
ivWant []byte
}{
{
[]byte{0, 0},
(100 * 256 * 256 * 256) * 16,
[]byte{0, 0},
},
{
[]byte{0, 0, 0, 0, 100},
156 * 16,
[]byte{0, 0, 0, 1, 0},
},
{
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
100 * 16,
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100},
},
{
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
(100*256 + 100) * 16,
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100},
},
{
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
(100 * 256 * 256 * 256) * 16,
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0},
},
{
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
(100 * 256 * 256 * 256) * 16,
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0},
},
}

func TestIncreaseCtr(t *testing.T) {
for _, item := range ctrAESIncreaseTests {
ivNext := cipher.IncreaseCtr(item.offset, 16, item.iv)
if !bytes.Equal(ivNext, item.ivWant) {
t.Errorf("for iv %d\noffset %x\nwant %x", item.iv, item.offset, item.ivWant)
}
}
}

0 comments on commit 5954056

Please sign in to comment.