zuc

package
v0.29.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 13, 2024 License: MIT Imports: 8 Imported by: 4

README

Reference

  • Information security technology—ZUC stream cipher algorithm—Part 1: Algorithm description 《GB/T 33133.1-2016 信息安全技术 祖冲之序列密码算法 第1部分:算法描述》
  • Information security technology—ZUC stream cipher algorithm—Part 2: Confidentiality algorithm 《GB/T 33133.2-2021 信息安全技术 祖冲之序列密码算法 第2部分:保密性算法》
  • Information security technology—ZUC stream cipher algorithm—Part 3: Integrity algorithm 《GB/T 33133.3-2021 信息安全技术 祖冲之序列密码算法 第3部分:完整性算法》

您可以从国家标准全文公开系统在线阅读这些标准。

ZUC original performance:

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/zuc
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkEncrypt1K-6   	   30052	     39131 ns/op	  26.04 MB/s
BenchmarkEncrypt8K-6   	    3853	    310722 ns/op	  26.35 MB/s

Performance after delay mod & lfsr array copy:

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/zuc
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkEncrypt1K-6   	   41754	     26916 ns/op	  37.86 MB/s
BenchmarkEncrypt8K-6   	    5290	    215252 ns/op	  38.03 MB/s

Performance after delay mod & lfsr array copy & merge sbox0/sbox1 (sbox size from 0.5k to 128k, so i do not commit it):

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/zuc
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkEncrypt1K-6   	   49195	     23710 ns/op	  42.98 MB/s
BenchmarkEncrypt8K-6   	    6000	    191255 ns/op	  42.81 MB/s
func (s *zucState32) f32(x0, x1, x2 uint32) uint32 {
	w := s.r1 ^ x0 + s.r2
	w1 := s.r1 + x1
	w2 := s.r2 ^ x2
	u := l1((w1 << 16) | (w2 >> 16))
	v := l2((w2 << 16) | (w1 >> 16))
	s.r1 = uint32(bigSbox[u>>16])<<16 | uint32(bigSbox[u&0xFFFF])
	s.r2 = uint32(bigSbox[v>>16])<<16 | uint32(bigSbox[v&0xFFFF])
	return w
}

// bigSbox is generated by 
	for i := 0; i < 256; i++ {
		for j := 0; j < 256; j++ {
			if (j > 0 || i > 0) && j%16 == 0 {
				fmt.Println()
			}
			fmt.Printf("0x%04x,", uint16(sbox0[i])<<8|uint16(sbox1[j]))
		}
	}
	fmt.Println()

EEA Performance with AMD64 SIMD & AESNI:

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/zuc
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkEncrypt1K-6   	  409755	      2802 ns/op	 363.62 MB/s
BenchmarkEncrypt8K-6   	   54120	     22413 ns/op	 365.28 MB/s

EIA Performance with AMD64 SIMD & AESNI & CLMUL:

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/zuc
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkHash1K-6   	  317750	      3833 ns/op	 267.13 MB/s
BenchmarkHash8K-6   	   40460	     28921 ns/op	 283.26 MB/s
BenchmarkHash1K_Tag64-6   	  302163	      3979 ns/op	 257.34 MB/s
BenchmarkHash8K_Tag64-6   	   39210	     30859 ns/op	 265.46 MB/s
BenchmarkHash1K_Tag128-6   	  279069	      4134 ns/op	 247.70 MB/s
BenchmarkHash8K_Tag128-6   	   38238	     31395 ns/op	 260.93 MB/s

Documentation

Overview

Package zuc implements ShangMi(SM) zuc stream cipher and integrity algorithm.

Index

Examples

Constants

View Source
const (
	IVSize128 = 16
	IVSize256 = 23
)
View Source
const (
	// number of words in a round
	RoundWords = 32
	// number of bytes in a word
	WordSize = 4
	WordMask = WordSize - 1
	// number of bytes in a round
	RoundBytes = RoundWords * WordSize
)

Variables

This section is empty.

Functions

func NewCipher

func NewCipher(key, iv []byte) (cipher.SeekableStream, error)

NewCipher create a stream cipher based on key and iv aguments. The key must be 16 bytes long and iv must be 16 bytes long for zuc 128; or the key must be 32 bytes long and iv must be 23 bytes long for zuc 256; otherwise, an error will be returned.

Example
package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	// Load your secret key from a safe place and reuse it across multiple
	// NewCipher calls. (Obviously don't use this example key for anything
	// real.) If you want to convert a passphrase to a key, use a suitable
	// package like bcrypt or scrypt.
	key, _ := hex.DecodeString("6368616e676520746869732070617373")
	plaintext := []byte("some plaintext")

	const ivSize = zuc.IVSize128
	// The IV needs to be unique, but not secure. Therefore it's common to
	// include it at the beginning of the ciphertext.
	ciphertext := make([]byte, ivSize+len(plaintext))
	iv := ciphertext[:ivSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	stream, err := zuc.NewCipher(key, iv)
	if err != nil {
		panic(err)
	}
	stream.XORKeyStream(ciphertext[ivSize:], plaintext)

	// It's important to remember that ciphertexts must be authenticated
	// (i.e. by using crypto/hmac) as well as being encrypted in order to
	// be secure.

	// Stream cipher is the same for both encryption and decryption, so we can
	// also decrypt that ciphertext with NewCTR.

	plaintext2 := make([]byte, len(plaintext))
	stream, err = zuc.NewCipher(key, iv)
	if err != nil {
		panic(err)
	}
	stream.XORKeyStream(plaintext2, ciphertext[ivSize:])

	fmt.Printf("%s\n", plaintext2)
}
Output:

some plaintext
Example (Zuc256)
package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	// Load your secret key from a safe place and reuse it across multiple
	// NewCipher calls. (Obviously don't use this example key for anything
	// real.) If you want to convert a passphrase to a key, use a suitable
	// package like bcrypt or scrypt.
	key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")
	plaintext := []byte("some plaintext")

	const ivSize = zuc.IVSize256
	// The IV needs to be unique, but not secure. Therefore it's common to
	// include it at the beginning of the ciphertext.
	ciphertext := make([]byte, ivSize+len(plaintext))
	iv := ciphertext[:ivSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	stream, err := zuc.NewCipher(key, iv)
	if err != nil {
		panic(err)
	}
	stream.XORKeyStream(ciphertext[ivSize:], plaintext)

	// It's important to remember that ciphertexts must be authenticated
	// (i.e. by using crypto/hmac) as well as being encrypted in order to
	// be secure.

	// Stream cipher is the same for both encryption and decryption, so we can
	// also decrypt that ciphertext with NewCTR.

	plaintext2 := make([]byte, len(plaintext))
	stream, err = zuc.NewCipher(key, iv)
	if err != nil {
		panic(err)
	}
	stream.XORKeyStream(plaintext2, ciphertext[ivSize:])

	fmt.Printf("%s\n", plaintext2)
}
Output:

some plaintext

func NewEEACipher

func NewEEACipher(key []byte, count, bearer, direction uint32) (cipher.SeekableStream, error)

NewEEACipher create a stream cipher based on key, count, bearer and direction arguments according specification. The key must be 16 bytes long and iv must be 16 bytes long, otherwise, an error will be returned. The count is the 32-bit counter value, the bearer is the 5-bit bearer identity and the direction is the 1-bit transmission direction flag.

Types

type ZUC128Mac

type ZUC128Mac struct {
	// contains filtered or unexported fields
}

func NewEIAHash

func NewEIAHash(key []byte, count, bearer, direction uint32) (*ZUC128Mac, error)

NewEIAHash create hash for zuc-128 eia, with arguments key, count, bearer and direction The key must be 16 bytes long and iv must be 16 bytes long, otherwise, an error will be returned. The count is the 32-bit counter value, the bearer is the 5-bit bearer identity and the direction is the 1-bit transmission direction flag.

func NewHash

func NewHash(key, iv []byte) (*ZUC128Mac, error)

NewHash create hash for zuc-128 eia, with arguments key and iv. Both key/iv size are 16 in bytes.

Example
package main

import (
	"encoding/hex"
	"fmt"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	// Load your secret key from a safe place and reuse it across multiple
	// NewCipher calls. (Obviously don't use this example key for anything
	// real.) If you want to convert a passphrase to a key, use a suitable
	// package like bcrypt or scrypt.
	key, _ := hex.DecodeString("6368616e676520746869732070617373")

	// iv should be generated randomly
	iv, _ := hex.DecodeString("6368616e676520746869732070617373")

	h, err := zuc.NewHash(key, iv)
	if err != nil {
		panic(err)
	}
	h.Write([]byte("hello world\n"))
	fmt.Printf("%x", h.Sum(nil))
}
Output:

c43cd26a

func (*ZUC128Mac) BlockSize

func (m *ZUC128Mac) BlockSize() int

func (*ZUC128Mac) Finish

func (m *ZUC128Mac) Finish(p []byte, nbits int) []byte

Finish this function hash nbits data in p and return mac value, after this function call, the hash state will be reset. In general, we will use byte level function, this is just for test/verify. nbits: number of bits to hash in p.

Example
package main

import (
	"fmt"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	key := make([]byte, 16)
	iv := make([]byte, 16)
	h, err := zuc.NewHash(key, iv)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%x", h.Finish([]byte{0}, 1))
}
Output:

c8a9595e
Example (Mixed)
package main

import (
	"encoding/hex"
	"fmt"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	key := []byte{
		0xc9, 0xe6, 0xce, 0xc4, 0x60, 0x7c, 0x72, 0xdb,
		0x00, 0x0a, 0xef, 0xa8, 0x83, 0x85, 0xab, 0x0a,
	}

	// iv should be generated randomly
	iv, _ := hex.DecodeString("a94059da50000000294059da50008000")

	h, err := zuc.NewHash(key, iv)
	if err != nil {
		panic(err)
	}

	in, _ := hex.DecodeString("983b41d47d780c9e1ad11d7eb70391b1de0b35da2dc62f83e7b78d6306ca0ea07e941b7be91348f9fcb170e2217fecd97f9f68adb16e5d7d21e569d280ed775cebde3f4093c53881")
	h.Write(in)
	fmt.Printf("%x", h.Finish([]byte{0}, 1))
}
Output:

fae8ff0b

func (*ZUC128Mac) Reset

func (m *ZUC128Mac) Reset()

Reset resets the Hash to its initial state.

func (*ZUC128Mac) Size

func (m *ZUC128Mac) Size() int

func (*ZUC128Mac) Sum

func (m *ZUC128Mac) Sum(in []byte) []byte

Sum appends the current hash to in and returns the resulting slice. It does not change the underlying hash state.

func (*ZUC128Mac) Write

func (m *ZUC128Mac) Write(p []byte) (nn int, err error)

type ZUC256Mac

type ZUC256Mac struct {
	// contains filtered or unexported fields
}

func NewHash256

func NewHash256(key, iv []byte, tagSize int) (*ZUC256Mac, error)

NewHash256 create hash for zuc-256 eia, with arguments key, iv and tagSize. Key size is 32 in bytes, iv size is 23 in bytes, tagSize supports 4/8/16 in bytes. The larger the tag size, the worse the performance.

Example (TagSize16)
package main

import (
	"encoding/hex"
	"fmt"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	// Load your secret key from a safe place and reuse it across multiple
	// NewCipher calls. (Obviously don't use this example key for anything
	// real.) If you want to convert a passphrase to a key, use a suitable
	// package like bcrypt or scrypt.
	key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")

	// iv should be generated randomly
	iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520")

	h, err := zuc.NewHash256(key, iv, 16)
	if err != nil {
		panic(err)
	}
	h.Write([]byte("hello world\n"))
	fmt.Printf("%x", h.Sum(nil))
}
Output:

fd8d10ea65b6369cccc07d50b4657d84
Example (TagSize4)
package main

import (
	"encoding/hex"
	"fmt"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	// Load your secret key from a safe place and reuse it across multiple
	// NewCipher calls. (Obviously don't use this example key for anything
	// real.) If you want to convert a passphrase to a key, use a suitable
	// package like bcrypt or scrypt.
	key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")

	// iv should be generated randomly
	iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520")

	h, err := zuc.NewHash256(key, iv, 4)
	if err != nil {
		panic(err)
	}
	h.Write([]byte("hello world\n"))
	fmt.Printf("%x", h.Sum(nil))
}
Output:

b76f96ed
Example (TagSize8)
package main

import (
	"encoding/hex"
	"fmt"

	"github.com/emmansun/gmsm/zuc"
)

func main() {
	// Load your secret key from a safe place and reuse it across multiple
	// NewCipher calls. (Obviously don't use this example key for anything
	// real.) If you want to convert a passphrase to a key, use a suitable
	// package like bcrypt or scrypt.
	key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")

	// iv should be generated randomly
	iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520")

	h, err := zuc.NewHash256(key, iv, 8)
	if err != nil {
		panic(err)
	}
	h.Write([]byte("hello world\n"))
	fmt.Printf("%x", h.Sum(nil))
}
Output:

f28aea6c9db3dc69

func (*ZUC256Mac) BlockSize

func (m *ZUC256Mac) BlockSize() int

func (*ZUC256Mac) Finish

func (m *ZUC256Mac) Finish(p []byte, nbits int) []byte

Finish this function hash nbits data in p and return mac value In general, we will use byte level function, this is just for test/verify.

func (*ZUC256Mac) Reset

func (m *ZUC256Mac) Reset()

Reset resets the Hash to its initial state.

func (*ZUC256Mac) Size

func (m *ZUC256Mac) Size() int

func (*ZUC256Mac) Sum

func (m *ZUC256Mac) Sum(in []byte) []byte

Sum appends the current hash to in and returns the resulting slice. It does not change the underlying hash state.

func (*ZUC256Mac) Write

func (m *ZUC256Mac) Write(p []byte) (nn int, err error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL