mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 04:06:18 +08:00
sm2: makes CalculateSM2Hash public
This commit is contained in:
parent
44336ac775
commit
880691746d
15
docs/sm2.md
15
docs/sm2.md
@ -18,7 +18,7 @@
|
|||||||
| 公钥加密算法 | ECIES |
|
| 公钥加密算法 | ECIES |
|
||||||
|
|
||||||
# SM2公私钥对
|
# SM2公私钥对
|
||||||
SM2公私钥对的话,要么是自己产生,要么是别的系统产生后通过某种格式传输给您的。
|
SM2公私钥对的话,要么是自己产生,要么是别的系统产生后通过某种方式传输给您的。
|
||||||
|
|
||||||
## SM2公私钥对的生成
|
## SM2公私钥对的生成
|
||||||
您可以通过调用```sm2.GenerateKey```方法产生SM2公私钥对,SM2的私钥通过组合方式扩展了```ecdsa.PrivateKey```,用于定义一些SM2特定的方法:
|
您可以通过调用```sm2.GenerateKey```方法产生SM2公私钥对,SM2的私钥通过组合方式扩展了```ecdsa.PrivateKey```,用于定义一些SM2特定的方法:
|
||||||
@ -32,7 +32,10 @@ type PrivateKey struct {
|
|||||||
SM2的公钥类型沿用了```ecdsa.PublicKey```结构。
|
SM2的公钥类型沿用了```ecdsa.PublicKey```结构。
|
||||||
|
|
||||||
## SM2公钥的解析、构造
|
## SM2公钥的解析、构造
|
||||||
通常情况下,公钥是通过PEM编码的文本传输的,您可以通过两步获得公钥:
|
通常情况下,公钥是通过PEM编码的文本传输的,您可以通过两步获得公钥:
|
||||||
|
* 获得PEM中的block
|
||||||
|
* 解析block中的公钥
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func getPublicKey(pemContent []byte) (any, error) {
|
func getPublicKey(pemContent []byte) (any, error) {
|
||||||
block, _ := pem.Decode(pemContent)
|
block, _ := pem.Decode(pemContent)
|
||||||
@ -84,7 +87,7 @@ func getPublicKey(pemContent []byte) (any, error) {
|
|||||||
priv.D = d
|
priv.D = d
|
||||||
priv.PublicKey.X, priv.PublicKey.Y = priv.ScalarBaseMult(priv.D.Bytes())
|
priv.PublicKey.X, priv.PublicKey.Y = priv.ScalarBaseMult(priv.D.Bytes())
|
||||||
```
|
```
|
||||||
当然,你也可以使用ecdh包的方法```ecdh.P256().NewPrivateKey```来构造私钥,您要确保输入的字节数组是256位(16字节)的。
|
当然,你也可以使用ecdh包的方法```ecdh.P256().NewPrivateKey```来构造私钥,您要确保输入的字节数组是256位(16字节)的,如果不是,请先自行处理。
|
||||||
|
|
||||||
# 数字签名算法
|
# 数字签名算法
|
||||||
您可以直接使用sm2私钥的签名方法```Sign```:
|
您可以直接使用sm2私钥的签名方法```Sign```:
|
||||||
@ -170,7 +173,7 @@ func ExampleEncryptASN1() {
|
|||||||
fmt.Printf("Ciphertext: %x\n", ciphertext)
|
fmt.Printf("Ciphertext: %x\n", ciphertext)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
如果您需要要普通拼接编码输出,您可以调用```sm2.Encrypt```方法,其中```EncrypterOpts```类型参数可以传入nil,表示默认C1C3C2。
|
如果您需要普通拼接编码输出,您可以调用```sm2.Encrypt```方法,其中```EncrypterOpts```类型参数可以传入nil,表示默认C1C3C2。
|
||||||
|
|
||||||
sm2包也提供了辅助方法用于密文输出编码格式转换:您可以通过```sm2.ASN1Ciphertext2Plain```方法把ASN.1密文转换为简单拼接输出;反过来,您也可以通过```sm2.PlainCiphertext2ASN1```将简单拼接密文输出转换为ASN.1密文。你还可以通过```sm2.AdjustCiphertextSplicingOrder```方法来改变串接顺序。
|
sm2包也提供了辅助方法用于密文输出编码格式转换:您可以通过```sm2.ASN1Ciphertext2Plain```方法把ASN.1密文转换为简单拼接输出;反过来,您也可以通过```sm2.PlainCiphertext2ASN1```将简单拼接密文输出转换为ASN.1密文。你还可以通过```sm2.AdjustCiphertextSplicingOrder```方法来改变串接顺序。
|
||||||
|
|
||||||
@ -197,12 +200,12 @@ func ExamplePrivateKey_Decrypt() {
|
|||||||
// Output: Plaintext: send reinforcements, we're going to advance
|
// Output: Plaintext: send reinforcements, we're going to advance
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
这个SM2私钥的解密方法```Decrypt```,通常情况下,对```crypto.DecrypterOpts```类型参数,您只需传入nil,系统会自己检测输入密文是ASN.1还是普通拼接,但是,如果密文是老旧的C1 || C2 || C3拼接,请传入相应的```crypto.DecrypterOpts```类型参数,或者您可以先通过上面介绍的辅助函数转换一下。
|
这个SM2私钥的解密方法```Decrypt```,通常情况下,对```crypto.DecrypterOpts```类型参数,您只需传入nil,系统会自己检测输入密文是ASN.1还是普通拼接,但是,如果密文是老旧的C1||C2||C3拼接,请传入相应的```crypto.DecrypterOpts```类型参数,或者您可以先通过上面介绍的辅助函数转换一下。
|
||||||
|
|
||||||
具体API文档请参考:[API Document](https://godoc.org/github.com/emmansun/gmsm)
|
具体API文档请参考:[API Document](https://godoc.org/github.com/emmansun/gmsm)
|
||||||
|
|
||||||
# 与KMS集成
|
# 与KMS集成
|
||||||
国内云服务商的KMS服务大都提供SM2密钥,我们一般调用其API进行签名和解密,而验签和加密操作,一般在本地用公钥即可完成。不过需要注意的是,KMS提供的签名通常需要您在本地进行hash操作,而sm2签名的hash又比较特殊,下面示例供参考(将在下个发布版本公开此函数):
|
国内云服务商的KMS服务大都提供SM2密钥,我们一般调用其API进行签名和解密,而验签和加密操作,一般在本地用公钥即可完成。不过需要注意的是,KMS提供的签名通常需要您在本地进行hash操作,而sm2签名的hash又比较特殊,下面示例供参考(将在下个发布版本**v0.24.0**中公开此函数```sm2.CalculateSM2Hash```):
|
||||||
```go
|
```go
|
||||||
func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
|
func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
|
||||||
if len(uid) == 0 {
|
if len(uid) == 0 {
|
||||||
|
10
sm2/sm2.go
10
sm2/sm2.go
@ -485,7 +485,11 @@ func CalculateZA(pub *ecdsa.PublicKey, uid []byte) ([]byte, error) {
|
|||||||
return md.Sum(nil), nil
|
return md.Sum(nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
|
// CalculateSM2Hash calculates hash value for data including uid and public key parameters
|
||||||
|
// according standards.
|
||||||
|
//
|
||||||
|
// uid can be nil, then it will use default uid (1234567812345678)
|
||||||
|
func CalculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
|
||||||
if len(uid) == 0 {
|
if len(uid) == 0 {
|
||||||
uid = defaultUID
|
uid = defaultUID
|
||||||
}
|
}
|
||||||
@ -512,7 +516,7 @@ func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
|
|||||||
// then the hash will be treated as raw message.
|
// then the hash will be treated as raw message.
|
||||||
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte, opts crypto.SignerOpts) ([]byte, error) {
|
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||||
if sm2Opts, ok := opts.(*SM2SignerOption); ok && sm2Opts.forceGMSign {
|
if sm2Opts, ok := opts.(*SM2SignerOption); ok && sm2Opts.forceGMSign {
|
||||||
newHash, err := calculateSM2Hash(&priv.PublicKey, hash, sm2Opts.uid)
|
newHash, err := CalculateSM2Hash(&priv.PublicKey, hash, sm2Opts.uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -692,7 +696,7 @@ func verifySM2EC(c *sm2Curve, pub *ecdsa.PublicKey, hash, sig []byte) bool {
|
|||||||
//
|
//
|
||||||
// It returns value records whether the signature is valid. Compliance with GB/T 32918.2-2016.
|
// It returns value records whether the signature is valid. Compliance with GB/T 32918.2-2016.
|
||||||
func VerifyASN1WithSM2(pub *ecdsa.PublicKey, uid, msg, sig []byte) bool {
|
func VerifyASN1WithSM2(pub *ecdsa.PublicKey, uid, msg, sig []byte) bool {
|
||||||
digest, err := calculateSM2Hash(pub, msg, uid)
|
digest, err := CalculateSM2Hash(pub, msg, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func fermatInverse(k, N *big.Int) *big.Int {
|
|||||||
|
|
||||||
// SignWithSM2 follow sm2 dsa standards for hash part, compliance with GB/T 32918.2-2016.
|
// SignWithSM2 follow sm2 dsa standards for hash part, compliance with GB/T 32918.2-2016.
|
||||||
func SignWithSM2(rand io.Reader, priv *ecdsa.PrivateKey, uid, msg []byte) (r, s *big.Int, err error) {
|
func SignWithSM2(rand io.Reader, priv *ecdsa.PrivateKey, uid, msg []byte) (r, s *big.Int, err error) {
|
||||||
digest, err := calculateSM2Hash(&priv.PublicKey, msg, uid)
|
digest, err := CalculateSM2Hash(&priv.PublicKey, msg, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ func verifyLegacy(pub *ecdsa.PublicKey, hash, sig []byte) bool {
|
|||||||
// VerifyWithSM2 verifies the signature in r, s of raw msg and uid using the public key, pub.
|
// VerifyWithSM2 verifies the signature in r, s of raw msg and uid using the public key, pub.
|
||||||
// It returns value records whether the signature is valid. Compliance with GB/T 32918.2-2016.
|
// It returns value records whether the signature is valid. Compliance with GB/T 32918.2-2016.
|
||||||
func VerifyWithSM2(pub *ecdsa.PublicKey, uid, msg []byte, r, s *big.Int) bool {
|
func VerifyWithSM2(pub *ecdsa.PublicKey, uid, msg []byte, r, s *big.Int) bool {
|
||||||
digest, err := calculateSM2Hash(pub, msg, uid)
|
digest, err := CalculateSM2Hash(pub, msg, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user