zuc

package
v0.27.4 Latest Latest
Warning

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

Go to latest
Published: Jun 28, 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 RoundWords = 32

Variables

This section is empty.

Functions

func NewCipher

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

NewCipher create a stream cipher based on key and iv aguments.

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.Stream, error)

NewEEACipher create a stream cipher based on key, count, bearer and direction arguments according specification.

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

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 In general, we will use byte level function, this is just for test/verify.

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)

func (*ZUC128Mac) XORKeyStream

func (c *ZUC128Mac) XORKeyStream(dst, src []byte)

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)

func (*ZUC256Mac) XORKeyStream

func (c *ZUC256Mac) XORKeyStream(dst, src []byte)

Jump to

Keyboard shortcuts

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