mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 12:16:20 +08:00
zuc: seekable stream refactoring and fix bug #277
This commit is contained in:
parent
da9f9c1748
commit
895c0db489
48
zuc/eea.go
48
zuc/eea.go
@ -7,11 +7,15 @@ import (
|
|||||||
"github.com/emmansun/gmsm/internal/subtle"
|
"github.com/emmansun/gmsm/internal/subtle"
|
||||||
)
|
)
|
||||||
|
|
||||||
const RoundWords = 32
|
const (
|
||||||
|
RoundWords = 32
|
||||||
|
WordSize = 4
|
||||||
|
RoundBytes = RoundWords * WordSize
|
||||||
|
)
|
||||||
|
|
||||||
type eea struct {
|
type eea struct {
|
||||||
zucState32
|
zucState32
|
||||||
x [4]byte // remaining bytes buffer
|
x [WordSize]byte // remaining bytes buffer
|
||||||
xLen int // number of remaining bytes
|
xLen int // number of remaining bytes
|
||||||
initState zucState32
|
initState zucState32
|
||||||
used uint64
|
used uint64
|
||||||
@ -47,10 +51,10 @@ func NewEEACipher(key []byte, count, bearer, direction uint32) (cipher.SeekableS
|
|||||||
}
|
}
|
||||||
|
|
||||||
func genKeyStreamRev32Generic(keyStream []byte, pState *zucState32) {
|
func genKeyStreamRev32Generic(keyStream []byte, pState *zucState32) {
|
||||||
for len(keyStream) >= 4 {
|
for len(keyStream) >= WordSize {
|
||||||
z := genKeyword(pState)
|
z := genKeyword(pState)
|
||||||
byteorder.BEPutUint32(keyStream, z)
|
byteorder.BEPutUint32(keyStream, z)
|
||||||
keyStream = keyStream[4:]
|
keyStream = keyStream[WordSize:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,17 +78,17 @@ func (c *eea) XORKeyStream(dst, src []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
words := (len(src) + 3) / 4
|
words := (len(src) + WordSize - 1) / WordSize
|
||||||
rounds := words / RoundWords
|
rounds := words / RoundWords
|
||||||
var keyBytes [RoundWords * 4]byte
|
var keyBytes [RoundBytes]byte
|
||||||
for i := 0; i < rounds; i++ {
|
for i := 0; i < rounds; i++ {
|
||||||
genKeyStreamRev32(keyBytes[:], &c.zucState32)
|
genKeyStreamRev32(keyBytes[:], &c.zucState32)
|
||||||
subtle.XORBytes(dst, src, keyBytes[:])
|
subtle.XORBytes(dst, src, keyBytes[:])
|
||||||
dst = dst[RoundWords*4:]
|
dst = dst[RoundBytes:]
|
||||||
src = src[RoundWords*4:]
|
src = src[RoundBytes:]
|
||||||
}
|
}
|
||||||
if rounds*RoundWords < words {
|
if processedWords := rounds * RoundWords; processedWords < words {
|
||||||
byteLen := 4 * (words - rounds*RoundWords)
|
byteLen := WordSize * (words - processedWords)
|
||||||
genKeyStreamRev32(keyBytes[:byteLen], &c.zucState32)
|
genKeyStreamRev32(keyBytes[:byteLen], &c.zucState32)
|
||||||
n := subtle.XORBytes(dst, src, keyBytes[:])
|
n := subtle.XORBytes(dst, src, keyBytes[:])
|
||||||
// save remaining key bytes
|
// save remaining key bytes
|
||||||
@ -110,6 +114,7 @@ func (c *eea) XORKeyStreamAt(dst, src []byte, offset uint64) {
|
|||||||
panic("zuc: invalid buffer overlap")
|
panic("zuc: invalid buffer overlap")
|
||||||
}
|
}
|
||||||
if offset < c.used {
|
if offset < c.used {
|
||||||
|
// reset the state to the initial state
|
||||||
c.reset()
|
c.reset()
|
||||||
} else if offset == c.used {
|
} else if offset == c.used {
|
||||||
c.XORKeyStream(dst, src)
|
c.XORKeyStream(dst, src)
|
||||||
@ -126,27 +131,24 @@ func (c *eea) XORKeyStreamAt(dst, src []byte, offset uint64) {
|
|||||||
|
|
||||||
// forward the state to the offset
|
// forward the state to the offset
|
||||||
// this part can be optimized by a little bit
|
// this part can be optimized by a little bit
|
||||||
stepLen := uint64(RoundWords * 4)
|
stepLen := uint64(RoundBytes)
|
||||||
var keys [RoundWords]uint32
|
var keys [RoundWords]uint32
|
||||||
for ; diff >= uint64(stepLen); diff -= stepLen {
|
for ; diff >= uint64(stepLen); diff -= stepLen {
|
||||||
genKeyStream(keys[:], &c.zucState32)
|
genKeyStream(keys[:], &c.zucState32)
|
||||||
c.used += stepLen
|
c.used += stepLen
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle remaining key bytes
|
|
||||||
if diff > 0 {
|
if diff > 0 {
|
||||||
limit := (diff + 3) / 4
|
limit := (diff + WordSize - 1) / WordSize
|
||||||
remaining := int(diff % 4)
|
|
||||||
genKeyStream(keys[:limit], &c.zucState32)
|
genKeyStream(keys[:limit], &c.zucState32)
|
||||||
c.used += limit * 4
|
partiallyUsed := int(diff % WordSize)
|
||||||
if remaining > 0 {
|
c.used += limit * WordSize
|
||||||
var keyBytes [4]byte
|
if partiallyUsed > 0 {
|
||||||
c.used -= 4
|
// save remaining key bytes (less than 4 bytes)
|
||||||
c.xLen = 4 - remaining
|
c.xLen = WordSize - partiallyUsed
|
||||||
if c.xLen > 0 {
|
c.used -= uint64(c.xLen)
|
||||||
byteorder.BEPutUint32(keyBytes[:], keys[limit-1])
|
byteorder.BEPutUint32(c.x[:], keys[limit-1])
|
||||||
copy(c.x[:], keyBytes[remaining:])
|
copy(c.x[:], c.x[partiallyUsed:])
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.XORKeyStream(dst, src)
|
c.XORKeyStream(dst, src)
|
||||||
|
@ -103,6 +103,15 @@ func TestXORStreamAt(t *testing.T) {
|
|||||||
t.Errorf("expected=%x, result=%x\n", dst1[:32], dst2[:32])
|
t.Errorf("expected=%x, result=%x\n", dst1[:32], dst2[:32])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test jump forward
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
c.XORKeyStreamAt(dst2[i:16], src2[i:16], uint64(i))
|
||||||
|
c.XORKeyStreamAt(dst2[32:64], src2[32:64], 32)
|
||||||
|
if !bytes.Equal(dst2[32:64], dst1[32:64]) {
|
||||||
|
t.Errorf("expected=%x, result=%x\n", dst1[32:64], dst2[32:64])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// test offset - used > 128 bytes case
|
// test offset - used > 128 bytes case
|
||||||
c.XORKeyStreamAt(dst2[:16], src2[:16], 0)
|
c.XORKeyStreamAt(dst2[:16], src2[:16], 0)
|
||||||
offset := 700
|
offset := 700
|
||||||
|
Loading…
x
Reference in New Issue
Block a user