github.com/emmansun/gmsm@v0.29.1/zuc/eia.go (about)

     1  package zuc
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  )
     7  
     8  const (
     9  	chunk = 16
    10  )
    11  
    12  type ZUC128Mac struct {
    13  	zucState32             // current zuc state
    14  	k0         [8]uint32   // keywords
    15  	t          uint32      // tag
    16  	x          [chunk]byte //buffer
    17  	nx         int         // remaining data in x
    18  	len        uint64      // total data length
    19  	tagSize    int         // tag size
    20  	initState  zucState32  // initial state for reset
    21  }
    22  
    23  // NewHash create hash for zuc-128 eia, with arguments key and iv.
    24  // Both key/iv size are 16 in bytes.
    25  func NewHash(key, iv []byte) (*ZUC128Mac, error) {
    26  	k := len(key)
    27  	ivLen := len(iv)
    28  	mac := &ZUC128Mac{}
    29  	mac.tagSize = 4
    30  
    31  	switch k {
    32  	default:
    33  		return nil, fmt.Errorf("zuc: invalid key size %d, expect 16 in bytes", k)
    34  	case 16: // ZUC-128
    35  		if ivLen != IVSize128 {
    36  			return nil, fmt.Errorf("zuc: invalid iv size %d, expect %d in bytes", ivLen, IVSize128)
    37  		}
    38  		mac.loadKeyIV16(key, iv)
    39  	}
    40  
    41  	// initialization
    42  	for i := 0; i < 32; i++ {
    43  		mac.bitReorganization()
    44  		w := mac.f32()
    45  		mac.enterInitMode(w >> 1)
    46  	}
    47  
    48  	// work state
    49  	mac.bitReorganization()
    50  	mac.f32()
    51  	mac.enterWorkMode()
    52  
    53  	mac.initState.r1 = mac.r1
    54  	mac.initState.r2 = mac.r2
    55  
    56  	copy(mac.initState.lfsr[:], mac.lfsr[:])
    57  	mac.Reset()
    58  	return mac, nil
    59  }
    60  
    61  func genIV4EIA(count, bearer, direction uint32) []byte {
    62  	iv := make([]byte, 16)
    63  	binary.BigEndian.PutUint32(iv, count)
    64  	copy(iv[9:12], iv[1:4])
    65  	iv[4] = byte(bearer << 3)
    66  	iv[12] = iv[4]
    67  	iv[8] = iv[0] ^ byte(direction<<7)
    68  	iv[14] = byte(direction << 7)
    69  	return iv
    70  }
    71  
    72  // NewEIAHash create hash for zuc-128 eia, with arguments key, count, bearer and direction
    73  func NewEIAHash(key []byte, count, bearer, direction uint32) (*ZUC128Mac, error) {
    74  	return NewHash(key, genIV4EIA(count, bearer, direction))
    75  }
    76  
    77  func (m *ZUC128Mac) Size() int {
    78  	return m.tagSize
    79  }
    80  
    81  func (m *ZUC128Mac) BlockSize() int {
    82  	return chunk
    83  }
    84  
    85  // Reset resets the Hash to its initial state.
    86  func (m *ZUC128Mac) Reset() {
    87  	m.t = 0
    88  	m.nx = 0
    89  	m.len = 0
    90  	m.r1 = m.initState.r1
    91  	m.r2 = m.initState.r2
    92  	copy(m.lfsr[:], m.initState.lfsr[:])
    93  	m.genKeywords(m.k0[:len(m.k0)/2])
    94  }
    95  
    96  func blockGeneric(m *ZUC128Mac, p []byte) {
    97  	// use 64 bits to shift left 2 keywords
    98  	var k64, t64 uint64
    99  	t64 = uint64(m.t) << 32
   100  	for len(p) >= chunk {
   101  		// generate next 4 keywords
   102  		m.genKeywords(m.k0[4:])
   103  		k64 = uint64(m.k0[0])<<32 | uint64(m.k0[1])
   104  		// process first 32 bits
   105  		w := binary.BigEndian.Uint32(p[0:4])
   106  		for j := 0; j < 32; j++ {
   107  			// t64 ^= (w >> 31) ? k64 : 0
   108  			t64 ^= ^(uint64(w>>31) - 1) & k64
   109  			w <<= 1
   110  			k64 <<= 1
   111  		}
   112  		// process second 32 bits
   113  		k64 = uint64(m.k0[1])<<32 | uint64(m.k0[2])
   114  		w = binary.BigEndian.Uint32(p[4:8])
   115  		for j := 0; j < 32; j++ {
   116  			t64 ^= ^(uint64(w>>31) - 1) & k64
   117  			w <<= 1
   118  			k64 <<= 1
   119  		}
   120  		// process third 32 bits
   121  		k64 = uint64(m.k0[2])<<32 | uint64(m.k0[3])
   122  		w = binary.BigEndian.Uint32(p[8:12])
   123  		for j := 0; j < 32; j++ {
   124  			t64 ^= ^(uint64(w>>31) - 1) & k64
   125  			w <<= 1
   126  			k64 <<= 1
   127  		}
   128  		// process fourth 32 bits
   129  		k64 = uint64(m.k0[3])<<32 | uint64(m.k0[4])
   130  		w = binary.BigEndian.Uint32(p[12:16])
   131  		for j := 0; j < 32; j++ {
   132  			t64 ^= ^(uint64(w>>31) - 1) & k64
   133  			w <<= 1
   134  			k64 <<= 1
   135  		}
   136  		// Move the new keywords to the first 4
   137  		copy(m.k0[:4], m.k0[4:])
   138  		p = p[chunk:]
   139  	}
   140  	m.t = uint32(t64 >> 32)
   141  }
   142  
   143  func (m *ZUC128Mac) Write(p []byte) (nn int, err error) {
   144  	nn = len(p)
   145  	m.len += uint64(nn)
   146  	if m.nx > 0 {
   147  		n := copy(m.x[m.nx:], p)
   148  		m.nx += n
   149  		if m.nx == chunk {
   150  			block(m, m.x[:])
   151  			m.nx = 0
   152  		}
   153  		p = p[n:]
   154  	}
   155  	if len(p) >= chunk {
   156  		n := len(p) &^ (chunk - 1)
   157  		block(m, p[:n])
   158  		p = p[n:]
   159  	}
   160  	if len(p) > 0 {
   161  		m.nx = copy(m.x[:], p)
   162  	}
   163  	return
   164  }
   165  
   166  func (m *ZUC128Mac) checkSum(additionalBits int, b byte) [4]byte {
   167  	if m.nx >= chunk {
   168  		panic("m.nx >= chunk")
   169  	}
   170  	kIdx := 0
   171  	if m.nx > 0 || additionalBits > 0 {
   172  		var k64, t64 uint64
   173  		t64 = uint64(m.t) << 32
   174  		m.x[m.nx] = b
   175  		// total bits to handle
   176  		nRemainBits := 8*m.nx + additionalBits
   177  		if nRemainBits > 2*32 {
   178  			// generate next 2 keywords
   179  			m.genKeywords(m.k0[4:6])
   180  		}
   181  		// nwords <= 4
   182  		nwords := (nRemainBits + 31) / 32
   183  		// process 32 bits at a time for first complete words
   184  		for i := 0; i < nwords-1; i++ {
   185  			k64 = uint64(m.k0[i])<<32 | uint64(m.k0[i+1])
   186  			w := binary.BigEndian.Uint32(m.x[i*4:])
   187  			for j := 0; j < 32; j++ {
   188  				t64 ^= ^(uint64(w>>31) - 1) & k64
   189  				w <<= 1
   190  				k64 <<= 1
   191  			}
   192  		}
   193  		nRemainBits -= (nwords - 1) * 32
   194  		// current key word index, 0 <= kIdx <= 3
   195  		kIdx = nwords - 1
   196  		// process remaining bits less than 32
   197  		if nRemainBits > 0 {
   198  			k64 = uint64(m.k0[kIdx])<<32 | uint64(m.k0[kIdx+1])
   199  			w := binary.BigEndian.Uint32(m.x[(nwords-1)*4:])
   200  			for j := 0; j < nRemainBits; j++ {
   201  				t64 ^= ^(uint64(w>>31) - 1) & k64
   202  				w <<= 1
   203  				k64 <<= 1
   204  			}
   205  			// Reset for fianal computation
   206  			m.k0[kIdx] = uint32(k64 >> 32) // key[LENGTH]
   207  			m.k0[kIdx+1] = m.k0[kIdx+2]    // Last key word
   208  		}
   209  		m.t = uint32(t64 >> 32)
   210  	}
   211  	m.t ^= m.k0[kIdx]
   212  	m.t ^= m.k0[kIdx+1]
   213  
   214  	var digest [4]byte
   215  	binary.BigEndian.PutUint32(digest[:], m.t)
   216  	return digest
   217  }
   218  
   219  // Finish this function hash nbits data in p and return mac value, after this function call, 
   220  // the hash state will be reset.
   221  // In general, we will use byte level function, this is just for test/verify.
   222  // nbits: number of bits to hash in p.
   223  func (m *ZUC128Mac) Finish(p []byte, nbits int) []byte {
   224  	if len(p) < (nbits+7)/8 {
   225  		panic("invalid p length")
   226  	}
   227  	nbytes := nbits / 8
   228  	nRemainBits := nbits - nbytes*8
   229  	if nbytes > 0 {
   230  		m.Write(p[:nbytes])
   231  	}
   232  	var b byte
   233  	if nRemainBits > 0 {
   234  		b = p[nbytes]
   235  	}
   236  	digest := m.checkSum(nRemainBits, b)
   237  	m.Reset()
   238  	return digest[:]
   239  }
   240  
   241  // Sum appends the current hash to in and returns the resulting slice.
   242  // It does not change the underlying hash state.
   243  func (m *ZUC128Mac) Sum(in []byte) []byte {
   244  	// Make a copy of d so that caller can keep writing and summing.
   245  	d0 := *m
   246  	hash := d0.checkSum(0, 0)
   247  	return append(in, hash[:]...)
   248  }