sm2

package
v0.0.0-...-9634917 Latest Latest
Warning

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

Go to latest
Published: Nov 20, 2020 License: Apache-2.0 Imports: 13 Imported by: 6

Documentation

Overview

Package sm2 为国密SM2算法(椭圆曲线公钥密码算法)的Go语言实现(国标编号: GB/T 32918-2016,以下简称“国标”) 国标原文在线浏览: http://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=3EE2FD47B962578070541ED468497C5B 原创代码: https://github.com/ZZMarquis/gm 注释: paul_lee0919@163.com 使用许可: Apache License 2.0

Index

Constants

View Source
const (
	// BitSize 代表曲线基础域的比特长度
	BitSize = 256
	// KeyBytes 代表秘钥的字节长度,其中加7整除8其实是“向上取整”,用以兼容基础域位数不是8的整数倍的情况。
	KeyBytes = (BitSize + 7) / 8
	// UnCompress 代表椭圆曲线上的点采用“未压缩”的形式存储,占1个字节,详见国标1-4.1.(b)的定义。
	UnCompress = 0x04
)

Variables

This section is empty.

Functions

func Decrypt

func Decrypt(priv *PrivateKey, in []byte, cipherTextType CipherTextType) ([]byte, error)

Decrypt 为SM2算法利用私钥解密(国标4-7.1)的函数: (1) 读取C1 (2) 反序列化同时校验C1点是否位于私钥曲线上 (3) 校验S点(S=[h]C1)是否为无穷远点O (4) 私钥推算倍点[d]C1 (5) 采用改造后的kdf()函数,计算并获取解密后的明文消息M'=C2^t (6) 计算u=Hash(c1x || M' || c2y)并与C3诸位比较 (7) 返回解密后的明文消息M'

func Encrypt

func Encrypt(pub *PublicKey, in []byte, cipherTextType CipherTextType) ([]byte, error)

Encrypt 为SM2加密函数: (1) 输入参数为: 公钥PB点(pub.X, pub.Y), 明文消息字节数组 in[], 密文类别标识 cipherTextType (2) 生成随机数k, k属于区间[1,N-1] (3) 利用标准包elliptic的方法CurveParams.ScalarBaseMult()生成倍点C1=kG=(c1x, c1y) (4) 由于SM2推荐曲线为素数域椭圆曲线,其余因子h=1,此时,点S=[h]PB就是公钥PB点,不可能为无穷远点O, 所以,国标4-6.1.A3被省略 (5) 利用标准包elliptic的方法CurveParams.ScalarBaseMult()生成倍点kPB=(kPBx, kPBy) (6) 调用改进后的秘钥派生函数kdf(), 生成C2

func MarshalCipher

func MarshalCipher(in []byte, cipherTextType CipherTextType) ([]byte, error)

MarshalCipher 为SM2算法密文对象序列化公共函数: (1) 将字节数组中保存的SM2密文对象截取出来 (2) 将截取出来的数据赋值给SM2密文对象的各相关属性 (3) 将SM2密文对象序列化为符合ASN.1标准DER编码规则的密文字节串 (4) SM2密文对象的具体规范请见国标(GB/T 35276-2017)

func MarshalSign

func MarshalSign(r, s *big.Int) ([]byte, error)

MarshalSign 为SM2将签名对象(r, s)序列化函数,即将签名对象序列化为符合ASN.1标准DER编码规则的字节串。

func ResponderConfirm

func ResponderConfirm(responderS2 []byte, initiatorS2 []byte) bool

ResponderConfim 为秘钥协商应答主体调用的S值校验函数(国标6.1.B10)

func Sign

func Sign(priv *PrivateKey, userID []byte, in []byte) ([]byte, error)

Sign 为封装后的SM2签名算法公共函数: (1) 输入参数为: 签名用户的私钥、ID和待签名信息 (2) 调用SignToRS函数推算签名结果(r,s) (3) 调用MarshalSign函数将签名对象序列化为符合ASN.1标准DER编码规则的字节数组

func SignToRS

func SignToRS(priv *PrivateKey, userID []byte, in []byte) (r, s *big.Int, err error)

SignToRS 为SM2签名算法的核心函数: (1) 以私钥(d倍数)为基础推算公钥点PA(XA, YA) (2) 调用预处理函数获取H值 (3) 调用标准包crypto/rand获取随机数k (国标2-6.1.A3) (4) 推算曲线点(x1, y1) = [k]G (国标2-6.1.A4) (5) 调用标准包math/big封装的加和取模函数计算r = (e + x1) mod n, 并校验r<>0, 且r+k<>n (国标2-6.1.A5) (6) 调用标准包math/big封装的取乘法逆元和取模函数计算s = ((1+d)^(-1) * (k - rd)) mod n, 并校验s <> 0 (国标2-6.1.A6) (7) 返回计算结果(r, s)

func UnmarshalCipher

func UnmarshalCipher(in []byte, cipherTextType CipherTextType) (out []byte, err error)

UnmarshalCipher 为SM2算法密文对象反序列化公共函数: (1) 将符合ASN.1标准DER编码规则的密文字节串反序列化为SM2密文对象 (2) 将SM2密文对象的各相关属性的值读出来并按规范存入字节数组 (3) SM2密文对象的具体规范请见国标(GB/T 35276-2017)

func UnmarshalSign

func UnmarshalSign(sign []byte) (r, s *big.Int, err error)

UnmarshalSign 为SM2将签名对象反序列化函数,即将符合ASN.1标准DER编码规则的字节串反序列化为SM2签名对象。

func Verify

func Verify(pub *PublicKey, userID []byte, src []byte, sign []byte) (bool, error)

Verify 为SM2封装后的签名验证函数, 输入参数为签名人的公钥、ID、原始消息和DER编码字节数组形式的签名(r, s), 反序列化签名后调用核心算法函数VerifyByRS校验签名。

func VerifyByRS

func VerifyByRS(pub *PublicKey, userID []byte, src []byte, r, s *big.Int) (bool, error)

VerifyByRS 为SM2验证签名算法的核心函数,输入参数为消息来源方公钥、用户ID、原始消息: (1) 调用math/big标准包(以下略)校验 1 <= r' < n (国标2-7.1.B1) (2) 校验 1 <= s' < n (国标2-7.1.B1) (3) 调用预处理函数,制备e' = Hash (Z||M') (国标2-7.1.B3-B4) (4) 计算 t = (r' + s') mod n, 并校验t<>0 (国标2-7.1.B5) (5) 调用elliptic标准包计算曲线上点(x1', y1') = [s']G + [t]PA, 并校验是否为无穷远点O(其实没必要) (国标2-7.1.B5) (6) 计算R = (e' + x1') mod n (7) 若 R = r' 则通过校验

Types

type CipherTextType

type CipherTextType int32

CipherTextType 是为了区分两个版本SM2国标在密文形式上的区别而创设的枚举类

const (
	//C1C2C3 代表旧标准[GM/T 0009-2012]的密文顺序
	C1C2C3 CipherTextType = 1
	//C1C3C2 代表新标准[GB/T 32918-2016]的密文顺序
	C1C3C2 CipherTextType = 2
)

type ExchangeResult

type ExchangeResult struct {
	Key []byte
	S1  []byte
	S2  []byte
}

ExchangeResult 为国标规定的最后推导出的秘钥交换协议的结果: Key 为共享秘钥,比如SM4秘钥 S1 为校验B用户ID的可选中间参数,其哈希函数输入参数的头部为0x02 S2 为校验A用户ID的可选中间参数,其哈希函数输入参数的头部为0x03

func CalculateKeyWithConfirmation

func CalculateKeyWithConfirmation(initiator bool, keyBits int, confirmationTag []byte,
	selfStaticPriv *PrivateKey, selfEphemeralPriv *PrivateKey, selfId []byte,
	otherStaticPub *PublicKey, otherEphemeralPub *PublicKey, otherId []byte) (*ExchangeResult, error)

CalculateKeyWithConfirmation 为SM2秘钥交换算法的主函数入口,其中: 1. 前部为准备函数, 基于用户ID、ENTL、基础曲线参数和公钥,准备Z值 2. 后半部按国标算法,推算关键点U,进而推算Key、S1和S2 3. 当协商发起人调用时,应当已经获得对方应答的Sb值,进而需要校验Sb == S1 4. 若不是发起人,则调用时仅需要计算得出Key、S1、Sb,无需在本函数中校验S值

type P256V1Curve

type P256V1Curve struct {
	*elliptic.CurveParams
	A *big.Int
}

P256V1Curve 代表国密SM2推荐参数定义的椭圆曲线: (1) 素数域256位椭圆曲线 (2) 曲线方程为 Y^2 = X^3 + aX + b (3) 其他参数: p, a, b, n, Gx, Gy 详见国标SM2推荐曲线参数 (4) 在GO语言标准库通用椭圆曲线参数类elliptic.CurveParams的基础上增加了参数a的属性 (5) 由于SM2推荐曲线符合a=p-3, 所以上述曲线可简化为等价曲线 Y^2 = X^3 - 3X + b (mod p), 符合美标FIPS186-3预设的曲线函数,所以,可直接适用GO语言elliptic标准库的一些公共方法。

func GetSM2P256V1

func GetSM2P256V1() P256V1Curve

GetSM2P256V1 为获取国密SM2椭圆曲线定义的函数。

type PrivateKey

type PrivateKey struct {
	D *big.Int
	PublicKey
}

PrivateKey 代表SM2算法的私钥类: (1) D代表公钥P点相对于基点G的倍数 (2) Curve 为SM2算法的椭圆曲线

func GenerateKey

func GenerateKey(rand io.Reader) (*PrivateKey, error)

GenerateKey 为国密SM2生成秘钥对的函数: (1) 利用GO语言标准包crypto/rand生成随机数rand; (2) 将SM2推荐曲线参数和随机数rand输入GO语言标准包crypto/elliptic的公钥对生成方法GenerateKey(),生成密钥对核心参数(priv, x, y); (3) 根据PublicKey类和PrivateKey类的定义生成公钥和私钥的实例,并将上述核心参数赋值给实例各相应属性以完成初始化.

func RawBytesToPrivateKey

func RawBytesToPrivateKey(bytes []byte) (*PrivateKey, error)

RawBytesToPrivateKey 将字节数组形式的原始格式数据转变为SM2私钥的方法: (1) 校验原始格式数据的字节长度(256位除以8,即32字节) (2) 利用GO语言标准包math/big的SetBytes()方法将原始格式数据转变成大端整数 (3) 赋值给PrivateKey实例的相关属性,完成私钥初始化

func (*PrivateKey) GetRawBytes

func (pri *PrivateKey) GetRawBytes() []byte

GetRawBytes 为获得字节数组格式存储的私钥的方法。

func (*PrivateKey) Public

func (pri *PrivateKey) Public() crypto.PublicKey

Public 返回私钥对应的公钥,实现crypto.Signer

func (*PrivateKey) Sign

func (pri *PrivateKey) Sign(rand io.Reader, in []byte, opts crypto.SignerOpts) ([]byte, error)

Sign 返回输入消息的签名,实现crypto.Signer接口

type PublicKey

type PublicKey struct {
	X, Y  *big.Int
	Curve P256V1Curve
}

PublicKey 代表SM2算法的公钥类: (1) X,Y 为P点(有限素数域上基点G的D倍点)坐标 (2) Curve 为SM2算法的椭圆曲线

func CalculatePubKey

func CalculatePubKey(priv *PrivateKey) *PublicKey

CalculatePubKey 为SM2利用私钥推算公钥的方法: (1) 创设公钥实例,将私钥携带的曲线赋值给公钥实例 (2) 利用GO语言标准包(crypto/elliptic)定义的Curve接口的ScalarBaseMult()方法, 根据椭圆曲线、基点G、私钥(D倍数)推算公钥(倍点P)

func RawBytesToPublicKey

func RawBytesToPublicKey(bytes []byte) (*PublicKey, error)

RawBytesToPublicKey 将字节数组形式的原始格式数据转化为SM2公钥的方法: (1) 校验原始格式数据的字节长度(32的2倍,即64个字节) (2) 利用GO语言标准包math/big的SetBytes()方法将原始格式数据转变成大端整数 (3) 赋值给PublicKey实例的相关属性,完成公钥初始化

func (*PublicKey) GetRawBytes

func (pub *PublicKey) GetRawBytes() []byte

GetRawBytes 为获得字节数组格式存储的公钥的方法(不带“未压缩”标识字节)。

func (*PublicKey) GetUnCompressBytes

func (pub *PublicKey) GetUnCompressBytes() []byte

GetUnCompressBytes 为获取未压缩字节数组格式存储的公钥的方法: (1) 将PublicKey实例的坐标(x,y)分别转化为字节数组 (2) 将“未压缩”标识"0x04"写入输出字节数组raw[]的首字节raw[0] (3) 将x坐标写入raw[:33], 将y坐标写入raw[33:]

Jump to

Keyboard shortcuts

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