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

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