github.com/emmansun/gmsm@v0.29.1/zuc/eea.go (about) 1 package zuc 2 3 import ( 4 "crypto/cipher" 5 "encoding/binary" 6 7 "github.com/emmansun/gmsm/internal/alias" 8 "github.com/emmansun/gmsm/internal/subtle" 9 ) 10 11 const RoundWords = 32 12 13 type eea struct { 14 zucState32 15 x [4]byte // remaining bytes buffer 16 xLen int // number of remaining bytes 17 } 18 19 // NewCipher create a stream cipher based on key and iv aguments. 20 func NewCipher(key, iv []byte) (cipher.Stream, error) { 21 s, err := newZUCState(key, iv) 22 if err != nil { 23 return nil, err 24 } 25 c := new(eea) 26 c.zucState32 = *s 27 return c, nil 28 } 29 30 // NewEEACipher create a stream cipher based on key, count, bearer and direction arguments according specification. 31 func NewEEACipher(key []byte, count, bearer, direction uint32) (cipher.Stream, error) { 32 iv := make([]byte, 16) 33 binary.BigEndian.PutUint32(iv, count) 34 copy(iv[8:12], iv[:4]) 35 iv[4] = byte(((bearer << 1) | (direction & 1)) << 2) 36 iv[12] = iv[4] 37 s, err := newZUCState(key, iv) 38 if err != nil { 39 return nil, err 40 } 41 c := new(eea) 42 c.zucState32 = *s 43 return c, nil 44 } 45 46 func genKeyStreamRev32Generic(keyStream []byte, pState *zucState32) { 47 for len(keyStream) >= 4 { 48 z := genKeyword(pState) 49 binary.BigEndian.PutUint32(keyStream, z) 50 keyStream = keyStream[4:] 51 } 52 } 53 54 func (c *eea) XORKeyStream(dst, src []byte) { 55 if len(dst) < len(src) { 56 panic("zuc: output smaller than input") 57 } 58 if alias.InexactOverlap(dst[:len(src)], src) { 59 panic("zuc: invalid buffer overlap") 60 } 61 if c.xLen > 0 { 62 // handle remaining key bytes 63 n := subtle.XORBytes(dst, src, c.x[:c.xLen]) 64 c.xLen -= n 65 dst = dst[n:] 66 src = src[n:] 67 if c.xLen > 0 { 68 copy(c.x[:], c.x[n:c.xLen+n]) 69 return 70 } 71 } 72 words := (len(src) + 3) / 4 73 rounds := words / RoundWords 74 var keyBytes [RoundWords * 4]byte 75 for i := 0; i < rounds; i++ { 76 genKeyStreamRev32(keyBytes[:], &c.zucState32) 77 subtle.XORBytes(dst, src, keyBytes[:]) 78 dst = dst[RoundWords*4:] 79 src = src[RoundWords*4:] 80 } 81 if rounds*RoundWords < words { 82 byteLen := 4 * (words - rounds*RoundWords) 83 genKeyStreamRev32(keyBytes[:byteLen], &c.zucState32) 84 n := subtle.XORBytes(dst, src, keyBytes[:]) 85 // save remaining key bytes 86 c.xLen = byteLen - n 87 if c.xLen > 0 { 88 copy(c.x[:], keyBytes[n:byteLen]) 89 } 90 } 91 }