Files
2026-05-27 23:03:00 +08:00

163 lines
4.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Summary
xdx (Golang) Crypto Library
Author: xdx
Package gcl is the xdx (Golang) Crypto Library of GOLANG(Go语言版的密码函数库)
包说明:
- identifier (GM/T 0006 密码标识常量定义)
- rsa - pkcs #1 v1.5 签名、SDF_XX_RSA接口实现 - Wrapping of crypto/rsa
- sm/sm1
- sm/sm2
- sm/sm3
- sm/sm4 包括CTR and GCM模式, sm4_mac
- pbkd P5,口令派生密钥规范
- grand 随机数
- drgb(确定性随机数发生器,软件实现的伪随机数生成器,密标草案稿,包括sm3_rng和sm4_ctr两个发生器)
- statistics - deprecated, use xdx.jelly/rts instead。
- MAC - 包括cbcmac, hmac_sm3 - hmac建议直接用hmac.New
- utils
- p7 padding (p5 padding is a special case of p7,utils/padding)
- tpc - SM2和SM9的协同签名(for HooFoo)
- x 新功能开发, 开发完成会放到gcl包下(不保证接口不变)
- 合并签名(x/seal/concentration)
# HOWTO
- gcl文件夹需放在GOPATH/xdx.jelly/文件夹下
- 需要golang.org/x/sys包
# Endian
SM2和SM9可以设置按0018中序列化时,ULONG转换的大小端序。比如10进制数256:
- 大端:256 => 00 00 01 00
- 小端:256 => 00 01 00 00
默认是大端序。若要指定端序,使用下面的函数(只需执行一次)
```go
// 设置SM2SM9转换端序
sm.SetToBigEndian()
sm.SetToLittleEndian()
```
```go
// 设置SM2转换端序
sm2.SetToBigEndian()
sm2.SetToLittleEndian()
```
```go
// 设置SM9转换端序
sm9.SetToBigEndian()
sm9.SetToLittleEndian()
```
注:反序列化Unmarshal的时候,默认忽略输入的bits的大小端序,不做严格检查。
# 函数调用约定
## 若返回错误,则保证输入不变,输出无意义。
```
out, err = fn(param)
```
若err != nil, 则param不变,out可能为nil,空Slice,零值或其他无意义数据。
如果函数调用可能发生错误,则下面这样调用发生错误时原输入值会丢失。
```
a, err = fn(a)
```
## 输入随机数
函数需要输入随机数的地方均可用nil代替,则函数内部使用grand的随机数发生器。
## 避免堆上分配空间
SM4的加解密,可以提前栈上分配好内存空间,传入函数调用。
例如
```
func EncryptECB(dst, key, src []byte) ([]byte, error)
```
dst和src要么完全重叠,要么不重叠
dst可以有三种情况
- nil, 内部分配空间,必须接收函数返回
- len(dst) >= len(src), 结果写入dst[:len(src)]并返回
- len(dst) < len(src), 分两种情况:
- cap(dst) >= len(src), 则不会发生内存重分配, 返回dst[:len(src)]
- cap(dst) < len(src), 内存重分配, 返回dst[:len(src)], 注意这时输入的dst和返回值是指向不同的内存地址。
应尽量避免内存重分配。涉及内存分配和拷贝
示例
```
data := [128]byte // set enough length on stack
src := data[:64]
// first case
dst, err := EncryptECB(nil, key, src) // dst is allocate in EncryptECB
if (err != nil){
// error handle
}
// second case
// 原地加密,src中现在存的是密文。
_, err := EncryptECB(src, key, src)
if (err != nil){
// error handle
// 若出错,src中内容不变,为明文
}
dst := data[96:]
dst, err = EncryptECB(dst, key, src) // len(dst)不够,且cap(dst) < len(src), 重分配内存。
if (err != nil){
// error handle
}
```
**最后,如果还是不知道dst应该输入什么,那就输入nil**
- 输入参数应该尽量保证不变(除说明外)。但有几个例外:
```
func CBCEncrypt(dst, iv, key, src []byte) ([]byte, error)
```
CBC模式会改变iv的值,作为下一次调用的输入。
- SM4的相关加解密函数如果确保输入数据长度都是正确的,那么可以不检查返回error
- SM4可以使用与go标准库一样的步骤。进行其他modes的加解密。
```
block, err := NewCipher(key)
decrypter := cipher.NewCBCDecrypter(block, iv)
decrypter.CryptBlocks(out, in)
```
# Marshal & Unmarshal
- gcl/util/encoding/{UtilMarshaler,UtilUnmarshaler}接口实现gmt0018的数据格式和类型的序列化。(增加输入缓存区和返回销毁字节数)
- x.MarshalBinary/x.UnmarshalBinary-弃用,使用上一条代替。
- x.MarshalSDF/x.UnmarshalSDF实现和SDF数据结构的相互转换。
- x.MarshalASN1/x.UnmarshalANS1 (TODO), 实现`SM{2,9}算法使用规范`的ANS.1编解码转换。
# Benchmark
## SM2 on amd64
- sign: 40000
- Verify: 13500
## SM3 on amd64
- AVX2: ~400MBps
## SM4 on amd64
- ECB: 250MBps(SM4-AESNI)
- GCM: (TODO: use SM4-AESNI and PCLMULQDQ)
## SM9 on amd64
- sign: 1500
# RoadMap
- 按sm2/sm9使用规范的ASN.1序列化和反序列化。