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
- func Decrypt(priv *PrivateKey, in []byte, cipherTextType CipherTextType) ([]byte, error)
- func Encrypt(pub *PublicKey, in []byte, cipherTextType CipherTextType) ([]byte, error)
- func MarshalCipher(in []byte, cipherTextType CipherTextType) ([]byte, error)
- func MarshalSign(r, s *big.Int) ([]byte, error)
- func ResponderConfirm(responderS2 []byte, initiatorS2 []byte) bool
- func Sign(priv *PrivateKey, userID []byte, in []byte) ([]byte, error)
- func SignToRS(priv *PrivateKey, userID []byte, in []byte) (r, s *big.Int, err error)
- func UnmarshalCipher(in []byte, cipherTextType CipherTextType) (out []byte, err error)
- func UnmarshalSign(sign []byte) (r, s *big.Int, err error)
- func Verify(pub *PublicKey, userID []byte, src []byte, sign []byte) (bool, error)
- func VerifyByRS(pub *PublicKey, userID []byte, src []byte, r, s *big.Int) (bool, error)
- type CipherTextType
- type ExchangeResult
- type P256V1Curve
- type PrivateKey
- type PublicKey
Constants ¶
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 ¶
MarshalSign 为SM2将签名对象(r, s)序列化函数,即将签名对象序列化为符合ASN.1标准DER编码规则的字节串。
func ResponderConfirm ¶
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 ¶
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 ¶
UnmarshalSign 为SM2将签名对象反序列化函数,即将符合ASN.1标准DER编码规则的字节串反序列化为SM2签名对象。
func Verify ¶
Verify 为SM2封装后的签名验证函数, 输入参数为签名人的公钥、ID、原始消息和DER编码字节数组形式的签名(r, s), 反序列化签名后调用核心算法函数VerifyByRS校验签名。
func VerifyByRS ¶
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 ¶
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标准库的一些公共方法。
type PrivateKey ¶
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 ¶
RawBytesToPublicKey 将字节数组形式的原始格式数据转化为SM2公钥的方法: (1) 校验原始格式数据的字节长度(32的2倍,即64个字节) (2) 利用GO语言标准包math/big的SetBytes()方法将原始格式数据转变成大端整数 (3) 赋值给PublicKey实例的相关属性,完成公钥初始化
func (*PublicKey) GetRawBytes ¶
GetRawBytes 为获得字节数组格式存储的公钥的方法(不带“未压缩”标识字节)。
func (*PublicKey) GetUnCompressBytes ¶
GetUnCompressBytes 为获取未压缩字节数组格式存储的公钥的方法: (1) 将PublicKey实例的坐标(x,y)分别转化为字节数组 (2) 将“未压缩”标识"0x04"写入输出字节数组raw[]的首字节raw[0] (3) 将x坐标写入raw[:33], 将y坐标写入raw[33:]