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  }