赞
踩
原创代码:https://github.com/ZZMarquis/gm
引用时,请导入原创代码库。本文仅以注释方式详解代码逻辑,供学习研究使用。
对原创代码的修改内容
注释者及联系邮箱
Paul Lee
paul_lee0919@163.com
// PublicKey 代表SM2算法的公钥类:
// (1) X,Y 为P点(有限素数域上基点G的D倍点)坐标
// (2) Curve 为SM2算法的椭圆曲线
type PublicKey struct {
X, Y *big.Int
Curve P256V1Curve
}
// PrivateKey 代表SM2算法的私钥类:
// (1) D代表公钥P点相对于基点G的倍数
// (2) Curve 为SM2算法的椭圆曲线
type PrivateKey struct {
D *big.Int
Curve P256V1Curve
}
以上为SM2算法公钥类和私钥类的定义,其中:
// GenerateKey 为国密SM2生成秘钥对的函数: // (1) 利用GO语言标准包crypto/rand生成随机数rand; // (2) 将SM2推荐曲线参数和随机数rand输入GO语言标准包crypto/elliptic的公钥对生成方法GenerateKey(),生成密钥对核心参数(priv, x, y); // (3) 根据PublicKey类和PrivateKey类的定义生成公钥和私钥的实例,并将上述核心参数赋值给实例各相应属性以完成初始化. func GenerateKey(rand io.Reader) (*PrivateKey, *PublicKey, error) { priv, x, y, err := elliptic.GenerateKey(sm2P256V1, rand) if err != nil { return nil, nil, err } privateKey := new(PrivateKey) privateKey.Curve = sm2P256V1 privateKey.D = new(big.Int).SetBytes(priv) publicKey := new(PublicKey) publicKey.Curve = sm2P256V1 publicKey.X = x publicKey.Y = y return privateKey, publicKey, nil }
GenerateKey( )为国密SM2生成秘钥对的函数:
// RawBytesToPublicKey 将字节数组形式的原始格式数据转化为SM2公钥的方法:
// (1) 校验原始格式数据的字节长度(32的2倍,即64个字节)
// (2) 利用GO语言标准包math/big的SetBytes()方法将原始格式数据转变成大端整数
// (3) 赋值给PublicKey实例的相关属性,完成公钥初始化
func RawBytesToPublicKey(bytes []byte) (*PublicKey, error) {
if len(bytes) != KeyBytes*2 {
return nil, errors.New("Public key raw bytes length must be " + string(KeyBytes*2))
}
publicKey := new(PublicKey)
publicKey.Curve = sm2P256V1
publicKey.X = new(big.Int).SetBytes(bytes[:KeyBytes])
publicKey.Y = new(big.Int).SetBytes(bytes[KeyBytes:])
return publicKey, nil
}
RawBytesToPublicKey( )为将字节数组形式的原始格式数据转化为SM2公钥的函数:
// RawBytesToPrivateKey 将字节数组形式的原始格式数据转变为SM2私钥的方法:
// (1) 校验原始格式数据的字节长度(256位除以8,即32字节)
// (2) 利用GO语言标准包math/big的SetBytes()方法将原始格式数据转变成大端整数
// (3) 赋值给PrivateKey实例的相关属性,完成私钥初始化
func RawBytesToPrivateKey(bytes []byte) (*PrivateKey, error) {
if len(bytes) != KeyBytes {
return nil, errors.New("Private key raw bytes length must be " + string(KeyBytes))
}
privateKey := new(PrivateKey)
privateKey.Curve = sm2P256V1
privateKey.D = new(big.Int).SetBytes(bytes)
return privateKey, nil
}
RawBytesToPrivateKey( )为将字节数组形式的原始格式数据转变为SM2私钥的函数:
// GetUnCompressBytes 为获取未压缩字节数组格式存储的公钥的方法: // (1) 将PublicKey实例的坐标(x,y)分别转化为字节数组 // (2) 将“未压缩”标识"0x04"写入输出字节数组raw[]的首字节raw[0] // (3) 将x坐标写入raw[:33], 将y坐标写入raw[33:] func (pub *PublicKey) GetUnCompressBytes() []byte { xBytes := pub.X.Bytes() yBytes := pub.Y.Bytes() xl := len(xBytes) yl := len(yBytes) raw := make([]byte, 1+KeyBytes*2) raw[0] = UnCompress if xl > KeyBytes { copy(raw[1:1+KeyBytes], xBytes[xl-KeyBytes:]) } else if xl < KeyBytes { copy(raw[1+(KeyBytes-xl):1+KeyBytes], xBytes) } else { copy(raw[1:1+KeyBytes], xBytes) } if yl > KeyBytes { copy(raw[1+KeyBytes:], yBytes[yl-KeyBytes:]) } else if yl < KeyBytes { copy(raw[1+KeyBytes+(KeyBytes-yl):], yBytes) } else { copy(raw[1+KeyBytes:], yBytes) } return raw } // GetRawBytes 为获得字节数组格式存储的公钥的方法(不带“未压缩”标识字节)。 func (pub *PublicKey) GetRawBytes() []byte { raw := pub.GetUnCompressBytes() return raw[1:] }
GetUnCompressBytes( ) 为获取未压缩字节数组格式存储的公钥的方法:
// GetRawBytes 为获得字节数组格式存储的私钥的方法。 func (pri *PrivateKey) GetRawBytes() []byte { dBytes := pri.D.Bytes() dl := len(dBytes) if dl > KeyBytes { raw := make([]byte, KeyBytes) copy(raw, dBytes[dl-KeyBytes:]) return raw } else if dl < KeyBytes { raw := make([]byte, KeyBytes) copy(raw[KeyBytes-dl:], dBytes) return raw } else { return dBytes } }
GetRawBytes( ) 为获得字节数组格式存储的私钥的方法。
// CalculatePubKey 为SM2利用私钥推算公钥的方法:
// (1) 创设公钥实例,将私钥携带的曲线赋值给公钥实例
// (2) 利用GO语言标准包(crypto/elliptic)定义的Curve接口的ScalarBaseMult()方法,
// 根据椭圆曲线、基点G、私钥(D倍数)推算公钥(倍点P)
func CalculatePubKey(priv *PrivateKey) *PublicKey {
pub := new(PublicKey)
pub.Curve = priv.Curve
pub.X, pub.Y = priv.Curve.ScalarBaseMult(priv.D.Bytes())
return pub
}
CalculatePubKey( ) 为SM2利用私钥推算公钥的方法:
// nextK 为生成[1, max)范围内随机整数的函数: // (1) 利用标准库math/big设置整数1 // (2) 利用标准库crypto/rand生成随机数 // (3) 审核随机数范围[1, max) // (4) 本算法中max为基础域的阶数n func nextK(rnd io.Reader, max *big.Int) (*big.Int, error) { intOne := new(big.Int).SetInt64(1) var k *big.Int var err error for { k, err = rand.Int(rnd, max) if err != nil { return nil, err } if k.Cmp(intOne) >= 0 { return k, err } } }
nextK( ) 为生成[1, max)范围内随机整数的函数:
(未完待续)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。