sm2

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2025 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package sm2 implements ShangMi(SM) sm2 digital signature, public key encryption and key exchange algorithms.

Example (ParseCipherASN1EndsWithInvalidBytes)

This method provide a sample to handle ASN1 ciphertext ends with extra bytes.

package main

import (
	"encoding/hex"
	"errors"
	"log"
	"math/big"

	"golang.org/x/crypto/cryptobyte"
	"golang.org/x/crypto/cryptobyte/asn1"
)

func main() {
	// a sample method to get frist ASN1 SEQUENCE data
	getFirstASN1Sequence := func(ciphertext []byte) ([]byte, []byte, error) {
		input := cryptobyte.String(ciphertext)
		var inner cryptobyte.String
		if !input.ReadASN1(&inner, asn1.SEQUENCE) {
			return nil, nil, errors.New("there are no sequence tag")
		}
		if len(input) == 0 {
			return ciphertext, nil, nil
		}
		return ciphertext[:len(ciphertext)-len(input)], input, nil
	}

	ciphertext, _ := hex.DecodeString("3081980220298ED52AE2A0EBA8B7567D54DF41C5F9B310EDFA4A8E15ECCB44EDA94F9F1FC20220116BE33B0833C95D8E5FF9483CD2D7EFF7033C92FE5DEAB6197D809FF1EEE05F042097A90979A6FCEBDE883C2E07E9C286818E694EDE37C3CDAA70E4CD481BE883E00430D62160BB179CB20CE3B5ECA0F5A535BEB6E221566C78FEA92105F71BD37F3F850AD2F86F2D1E35F15E9356557DAC026A")
	_, rest, err := getFirstASN1Sequence(ciphertext)
	if err != nil || len(rest) != 0 {
		log.Fatalf("can't get a complete ASN1 sequence")
	}

	ciphertext, _ = hex.DecodeString("3081980220298ED52AE2A0EBA8B7567D54DF41C5F9B310EDFA4A8E15ECCB44EDA94F9F1FC20220116BE33B0833C95D8E5FF9483CD2D7EFF7033C92FE5DEAB6197D809FF1EEE05F042097A90979A6FCEBDE883C2E07E9C286818E694EDE37C3CDAA70E4CD481BE883E00430D62160BB179CB20CE3B5ECA0F5A535BEB6E221566C78FEA92105F71BD37F3F850AD2F86F2D1E35F15E9356557DAC026A0000")
	seq, rest, err := getFirstASN1Sequence(ciphertext)
	if err != nil || len(rest) != 2 {
		log.Fatalf("can't get a complete ASN1 sequence")
	}

	var (
		x1, y1 = &big.Int{}, &big.Int{}
		c2, c3 []byte
		inner  cryptobyte.String
	)

	input := cryptobyte.String(seq)
	if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
		!input.Empty() ||
		!inner.ReadASN1Integer(x1) ||
		!inner.ReadASN1Integer(y1) ||
		!inner.ReadASN1Bytes(&c3, asn1.OCTET_STRING) ||
		!inner.ReadASN1Bytes(&c2, asn1.OCTET_STRING) ||
		!inner.Empty() {
		log.Fatalf("invalid cipher text")
	}
}

Index

Examples

Constants

View Source
const (
	//MarshalUncompressed uncompressed marshal mode
	MarshalUncompressed pointMarshalMode = iota
	//MarshalCompressed compressed marshal mode
	MarshalCompressed
	//MarshalHybrid hybrid marshal mode
	MarshalHybrid
)
View Source
const (
	C1C3C2 ciphertextSplicingOrder = iota
	C1C2C3
)
View Source
const (
	ENCODING_PLAIN ciphertextEncoding = iota
	ENCODING_ASN1
)

Variables

View Source
var (
	ASN1EncrypterOpts = &EncrypterOpts{ENCODING_ASN1, MarshalUncompressed, C1C3C2}

	ASN1DecrypterOpts = &DecrypterOpts{ENCODING_ASN1, C1C3C2}
)
View Source
var DefaultSM2SignerOpts = NewSM2SignerOption(true, nil)

DefaultSM2SignerOpts uses default UID and forceGMSign is true.

View Source
var ErrDecryption = errors.New("sm2: decryption error")

ErrDecryption represents a failure to decrypt a message. It is deliberately vague to avoid adaptive attacks.

View Source
var ErrInvalidSignature = errors.New("sm2: invalid signature")

Functions

func ASN1Ciphertext2Plain

func ASN1Ciphertext2Plain(ciphertext []byte, opts *EncrypterOpts) ([]byte, error)

ASN1Ciphertext2Plain utility method to convert ASN.1 encoding ciphertext to plain encoding format

func AdjustCiphertextSplicingOrder

func AdjustCiphertextSplicingOrder(ciphertext []byte, from, to ciphertextSplicingOrder) ([]byte, error)

AdjustCiphertextSplicingOrder utility method to change c2 c3 order

func CalculateSM2Hash

func CalculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error)

CalculateSM2Hash calculates the SM2 hash for the given public key, data, and user ID (UID). If the UID is not provided, a default UID (1234567812345678) is used. The public key must be valid, otherwise will be panic. This function is used to calculate the hash value for SM2 signature. Reference: GM/T 0009-2023 Chapter 8.1 and 8.2.

func CalculateZA

func CalculateZA(pub *ecdsa.PublicKey, uid []byte) ([]byte, error)

CalculateZA ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA). Compliance with GB/T 32918.2-2016 5.5.

This function will NOT use default UID even the uid argument is empty. Reference: GM/T 0009-2023 Chapter 8.1.

func Decrypt

func Decrypt(priv *PrivateKey, ciphertext []byte) ([]byte, error)

Decrypt sm2 decrypt implementation by default DecrypterOpts{C1C3C2}. Compliance with GB/T 32918.4-2016.

func Encrypt

func Encrypt(random io.Reader, pub *ecdsa.PublicKey, msg []byte, opts *EncrypterOpts) ([]byte, error)

Encrypt sm2 encrypt implementation, compliance with GB/T 32918.4-2016.

The random parameter is used as a source of entropy to ensure that encrypting the same message twice doesn't result in the same ciphertext. Most applications should use crypto/rand.Reader as random.

func EncryptASN1

func EncryptASN1(random io.Reader, pub *ecdsa.PublicKey, msg []byte) ([]byte, error)

EncryptASN1 sm2 encrypt and output ASN.1 result, compliance with GB/T 32918.4-2016.

The random parameter is used as a source of entropy to ensure that encrypting the same message twice doesn't result in the same ciphertext. Most applications should use crypto/rand.Reader as random.

Example
package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"log"
	"os"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	// real public key should be from cert or public key pem file
	keypoints, _ := hex.DecodeString("048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1")
	testkey, err := sm2.NewPublicKey(keypoints)
	if err != nil {
		log.Fatalf("fail to new public key %v", err)
	}

	secretMessage := []byte("send reinforcements, we're going to advance")

	// crypto/rand.Reader is a good source of entropy for randomizing the
	// encryption function.
	rng := rand.Reader

	ciphertext, err := sm2.EncryptASN1(rng, testkey, secretMessage)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
		return
	}
	// Since encryption is a randomized function, ciphertext will be
	// different each time.
	fmt.Printf("Ciphertext: %x\n", ciphertext)
}

func IsSM2PublicKey

func IsSM2PublicKey(publicKey any) bool

IsSM2PublicKey checks if the provided public key is an SM2 public key. It takes an interface{} as input and attempts to assert it to an *ecdsa.PublicKey. The function returns true if the assertion is successful and the public key's curve is SM2 P-256.

func MarshalEnvelopedPrivateKey

func MarshalEnvelopedPrivateKey(rand io.Reader, pub *ecdsa.PublicKey, tobeEnveloped *PrivateKey) ([]byte, error)

MarshalEnvelopedPrivateKey, returns sm2 key pair protected data with ASN.1 format:

SM2EnvelopedKey ::= SEQUENCE {
  symAlgID                AlgorithmIdentifier,
  symEncryptedKey         SM2Cipher,
  sm2PublicKey            SM2PublicKey,
  sm2EncryptedPrivateKey  BIT STRING,
}

This implementation follows GB/T 35276-2017, uses SM4 cipher to encrypt sm2 private key. Please note the standard did NOT clarify if the ECB mode requires padding or not.

This function can be used in CSRResponse.encryptedPrivateKey, reference GM/T 0092-2020 Specification of certificate request syntax based on SM2 cryptographic algorithm.

func NewHash

func NewHash(pub *ecdsa.PublicKey) (hash.Hash, error)

NewHash creates a new hash.Hash instance using the provided SM2 public key. It uses the default SM3 hash function and default user ID.

func NewHashWithHashAndUserID

func NewHashWithHashAndUserID(pub *ecdsa.PublicKey, h func() hash.Hash, userID []byte) (hash.Hash, error)

NewHashWithHashAndUserID creates a new hash.Hash instance that incorporates SM2-specific hashing with the provided public key, inner hash and user ID. The returned hasher is reset before being returned.

func NewHashWithUserID

func NewHashWithUserID(pub *ecdsa.PublicKey, userID []byte) (hash.Hash, error)

NewHashWithUserID creates a new hash.Hash instance using the provided SM2 public key and user ID. It internally uses the SM3 hash function.

func NewPublicKey

func NewPublicKey(key []byte) (*ecdsa.PublicKey, error)

NewPublicKey checks that the provided key is valid and returns an SM2 PublicKey.

The key parameter is a byte slice representing the public key in uncompressed format. According to GB/T 32918.1-2016, the public key must be in the correct format and on the curve.

Example
package main

import (
	"crypto/elliptic"
	"encoding/hex"
	"fmt"
	"log"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	keypoints, _ := hex.DecodeString("048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1")
	pub, err := sm2.NewPublicKey(keypoints)
	if err != nil {
		log.Fatalf("fail to new public key %v", err)
	}
	fmt.Printf("%x\n", elliptic.Marshal(sm2.P256(), pub.X, pub.Y))
}
Output:

048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1

func P256

func P256() elliptic.Curve

P256 returns sm2 curve signleton, this function is for backward compatibility.

func ParseCompressedPublicKey added in v1.0.1

func ParseCompressedPublicKey(data []byte) (*ecdsa.PublicKey, error)

func ParseUncompressedPublicKey

func ParseUncompressedPublicKey(data []byte) (*ecdsa.PublicKey, error)

ParseUncompressedPublicKey parses a public key encoded as an uncompressed point according to SEC 1, Version 2.0, Section 2.3.3 (also known as the X9.62 uncompressed format). It returns an error if the point is not in uncompressed form, is not on the curve, or is the point at infinity.

Note that public keys are more commonly encoded in DER (or PEM) format, which can be parsed with [smx509.ParsePKIXPublicKey] (and encoding/pem).

func PlainCiphertext2ASN1

func PlainCiphertext2ASN1(ciphertext []byte, from ciphertextSplicingOrder) ([]byte, error)

PlainCiphertext2ASN1 utility method to convert plain encoding ciphertext to ASN.1 encoding format

func PublicKeyToECDH

func PublicKeyToECDH(k *ecdsa.PublicKey) (*ecdh.PublicKey, error)

PublicKeyToECDH returns k as a ecdh.PublicKey. It returns an error if the key is invalid according to the definition of ecdh.Curve.NewPublicKey, or if the Curve is not supported by ecdh.

func RecoverPublicKeysFromSM2Signature

func RecoverPublicKeysFromSM2Signature(hash, sig []byte) ([]*ecdsa.PublicKey, error)

RecoverPublicKeysFromSM2Signature attempts to recover the public keys from an SM2 signature. This function takes a hash and a signature as input and returns a slice of possible public keys that could have generated the given signature.

Parameters: - hash: The hash of the message that was signed. - sig: The SM2 signature.

Returns: - A slice of pointers to ecdsa.PublicKey, representing the possible public keys. - An error if the signature is invalid or if any other error occurs during the recovery process.

The function performs the following steps: 1. Parses the signature to extract the r and s values. 2. Converts the hash to a big integer (Nat). 3. Computes the point p₁ = [-s]G. 4. Computes s = [r + s] and its modular inverse. 5. Computes the possible x-coordinates (Rx) for the point R. 6. For each possible Rx, computes the corresponding point R and derives the public key.

Note: The function handles the case where there are one or two possible values for Rx, resulting in two or four possible public keys.

func Sign

func Sign(rand io.Reader, priv *ecdsa.PrivateKey, hash []byte) (r, s *big.Int, err error)

Sign signs a hash (which should be the result of hashing a larger message) using the private key, priv. If the hash is longer than the bit-length of the private key's curve order, the hash will be truncated to that length. It returns the signature as a pair of integers. Most applications should use SignASN1 instead of dealing directly with r, s.

Compliance with GB/T 32918.2-2016 regardless it's SM2 curve or not.

func SignASN1

func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte, opts crypto.SignerOpts) ([]byte, error)

SignASN1 signs a hash (which should be the result of hashing a larger message) using the private key, priv. If the hash is longer than the bit-length of the private key's curve order, the hash will be truncated to that length. It returns the ASN.1 encoded signature.

The signature is randomized. Most applications should use crypto/rand.Reader as rand. Note that the returned signature does not depend deterministically on the bytes read from rand, and may change between calls and/or between versions.

If the opts argument is instance of *SM2SignerOption, and its ForceGMSign is true, then the hash will be treated as raw message.

func SignWithSM2

func SignWithSM2(rand io.Reader, priv *ecdsa.PrivateKey, uid, msg []byte) (r, s *big.Int, err error)

SignWithSM2 follow sm2 dsa standards for hash part, compliance with GB/T 32918.2-2016.

func Verify

func Verify(pub *ecdsa.PublicKey, hash []byte, r, s *big.Int) bool

Verify verifies the signature in r, s of hash using the public key, pub. Its return value records whether the signature is valid. Most applications should use VerifyASN1 instead of dealing directly with r, s.

Compliance with GB/T 32918.2-2016 regardless it's SM2 curve or not. Caller should make sure the hash's correctness.

func VerifyASN1

func VerifyASN1(pub *ecdsa.PublicKey, hash, sig []byte) bool

VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the public key, pub. Its return value records whether the signature is valid.

Compliance with GB/T 32918.2-2016 regardless it's SM2 curve or not. Caller should make sure the hash's correctness, in other words, the caller must pre-compute the hash value.

Example
package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	// real public key should be from cert or public key pem file
	keypoints, _ := hex.DecodeString("048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1")
	testkey, err := sm2.NewPublicKey(keypoints)
	if err != nil {
		log.Fatalf("fail to new public key %v", err)
	}

	// calculate hash value
	data := []byte("ShangMi SM2 Sign Standard")
	h, err := sm2.NewHash(testkey)
	if err != nil {
		log.Fatalf("fail to new hash %v", err)
	}
	h.Write(data)
	hashed := h.Sum(nil)

	signature, _ := hex.DecodeString("304402205b3a799bd94c9063120d7286769220af6b0fa127009af3e873c0e8742edc5f890220097968a4c8b040fd548d1456b33f470cabd8456bfea53e8a828f92f6d4bdcd77")

	ok := sm2.VerifyASN1(testkey, hashed, signature)

	fmt.Printf("%v\n", ok)
}
Output:

true

func VerifyASN1WithSM2

func VerifyASN1WithSM2(pub *ecdsa.PublicKey, uid, msg, sig []byte) bool

VerifyASN1WithSM2 verifies the signature in ASN.1 encoding format sig of raw msg and uid using the public key, pub. The uid can be empty, meaning to use the default value.

It returns value records whether the signature is valid. Compliance with GB/T 32918.2-2016.

Example
package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	// real public key should be from cert or public key pem file
	keypoints, _ := hex.DecodeString("048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1")
	testkey, err := sm2.NewPublicKey(keypoints)
	if err != nil {
		log.Fatalf("fail to new public key %v", err)
	}

	data := []byte("ShangMi SM2 Sign Standard")
	signature, _ := hex.DecodeString("304402205b3a799bd94c9063120d7286769220af6b0fa127009af3e873c0e8742edc5f890220097968a4c8b040fd548d1456b33f470cabd8456bfea53e8a828f92f6d4bdcd77")

	ok := sm2.VerifyASN1WithSM2(testkey, nil, data, signature)

	fmt.Printf("%v\n", ok)
}
Output:

true

func VerifyWithSM2

func VerifyWithSM2(pub *ecdsa.PublicKey, uid, msg []byte, r, s *big.Int) bool

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.

Types

type DecrypterOpts

type DecrypterOpts struct {
	// contains filtered or unexported fields
}

DecrypterOpts represents the options for the decryption process. It includes settings for how the ciphertext is encoded and how the components of the ciphertext are spliced together.

Fields:

  • ciphertextEncoding: Specifies the encoding format of the ciphertext.
  • ciphertextSplicingOrder: Defines the order in which the components of the ciphertext are spliced together.

func NewPlainDecrypterOpts

func NewPlainDecrypterOpts(splicingOrder ciphertextSplicingOrder) *DecrypterOpts

NewPlainDecrypterOpts creates a SM2 non-ASN1 decrypter options.

func (*DecrypterOpts) SetCiphertextEncoding

func (o *DecrypterOpts) SetCiphertextEncoding(ciphertextEncoding ciphertextEncoding)

func (*DecrypterOpts) SetCiphertextSplicingOrder

func (o *DecrypterOpts) SetCiphertextSplicingOrder(ciphertextSplicingOrder ciphertextSplicingOrder)

type EncrypterOpts

type EncrypterOpts struct {
	// contains filtered or unexported fields
}

EncrypterOpts represents the options for the SM2 encryption process. It includes settings for ciphertext encoding, point marshaling mode, and the order in which the ciphertext components are spliced together.

func NewPlainEncrypterOpts

func NewPlainEncrypterOpts(marshalMode pointMarshalMode, splicingOrder ciphertextSplicingOrder) *EncrypterOpts

NewPlainEncrypterOpts creates a SM2 non-ASN1 encrypter options.

func (*EncrypterOpts) SetCiphertextEncoding

func (o *EncrypterOpts) SetCiphertextEncoding(ciphertextEncoding ciphertextEncoding)

func (*EncrypterOpts) SetCiphertextSplicingOrder

func (o *EncrypterOpts) SetCiphertextSplicingOrder(ciphertextSplicingOrder ciphertextSplicingOrder)

func (*EncrypterOpts) SetPointMarshalMode

func (o *EncrypterOpts) SetPointMarshalMode(pointMarshalMode pointMarshalMode)

type KeyExchange

type KeyExchange struct {
	// contains filtered or unexported fields
}

KeyExchange key exchange struct, include internal stat in whole key exchange flow. Initiator's flow will be: NewKeyExchange -> InitKeyExchange -> transmission -> ConfirmResponder Responder's flow will be: NewKeyExchange -> waiting ... -> RepondKeyExchange -> transmission -> ConfirmInitiator

func NewKeyExchange

func NewKeyExchange(priv *PrivateKey, peerPub *ecdsa.PublicKey, uid, peerUID []byte, keyLen int, genSignature bool) (ke *KeyExchange, err error)

NewKeyExchange create one new KeyExchange object

在部分场景中,在初始 KeyExchange 时暂时没有对端的公开信息(如公钥、UID),这些信息可能需要在后续的交换中得到。 这种情况下,可设置 peerPub、peerUID 参数为 nil,并在合适的时候通过 KeyExchange.SetPeerParameters 方法配置相关参数。 注意 KeyExchange.SetPeerParameters 方法必须要在 KeyExchange.RepondKeyExchange 或 KeyExchange.RepondKeyExchange 方法之前调用。

func (*KeyExchange) ConfirmInitiator

func (ke *KeyExchange) ConfirmInitiator(s1 []byte) ([]byte, error)

ConfirmInitiator for responder's step B10

func (*KeyExchange) ConfirmResponder

func (ke *KeyExchange) ConfirmResponder(rB *ecdsa.PublicKey, sB []byte) ([]byte, []byte, error)

ConfirmResponder for initiator's step A4-A10, returns keying data and optional signature.

It will check if there are peer's public key and validate the peer's Ephemeral Public Key.

If the peer's signature is not empty, then it will also validate the peer's signature and return generated signature depends on KeyExchange.genSignature value.

func (*KeyExchange) Destroy

func (ke *KeyExchange) Destroy()

Destroy clear all internal state and Ephemeral private/public keys.

func (*KeyExchange) InitKeyExchange

func (ke *KeyExchange) InitKeyExchange(rand io.Reader) (*ecdsa.PublicKey, error)

InitKeyExchange is for initiator's step A1-A3, returns generated Ephemeral Public Key which will be passed to Reponder.

func (*KeyExchange) RepondKeyExchange

func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, rA *ecdsa.PublicKey) (*ecdsa.PublicKey, []byte, error)

RepondKeyExchange is for responder's step B1-B8, returns generated Ephemeral Public Key and optional signature depends on KeyExchange.genSignature value.

It will check if there are peer's public key and validate the peer's Ephemeral Public Key.

func (*KeyExchange) SetPeerParameters

func (ke *KeyExchange) SetPeerParameters(peerPub *ecdsa.PublicKey, peerUID []byte) error

SetPeerParameters 设置对端公开信息,该方法用于某些初期状态无法取得对端公开参数的场景。 例如:在TLCP协议中,基于SM2算法ECDHE过程。

注意该方法仅在 NewKeyExchange 没有提供 peerPub、peerUID参数时允许被调用, 且该方法只能调用一次不可重复调用,若多次调用或peerPub、peerUID已经存在则会发生错误。

type PrivateKey

type PrivateKey struct {
	ecdsa.PrivateKey
	// contains filtered or unexported fields
}

PrivateKey represents an ECDSA SM2 private key. It embeds ecdsa.PrivateKey and includes additional fields for SM2-specific operations. It implements both crypto.Decrypter and crypto.Signer interfaces.

func GenerateKey

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

GenerateKey generates a new SM2 private key.

Most applications should use crypto/rand.Reader as rand. Note that the returned key does not depend deterministically on the bytes read from rand, and may change between calls and/or between versions.

According GB/T 32918.1-2016, the private key must be in [1, n-2].

func NewPrivateKey

func NewPrivateKey(key []byte) (*PrivateKey, error)

NewPrivateKey checks that key is valid and returns a SM2 PrivateKey.

key - the private key byte slice, the length must be 32 for SM2.

According GB/T 32918.1-2016, the private key must be in [1, n-2].

Example
package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	keyBytes, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
	priv, err := sm2.NewPrivateKey(keyBytes)
	if err != nil {
		log.Fatalf("fail to new private key %v", err)
	}
	fmt.Printf("%x\n", priv.D.Bytes())
}
Output:

6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85

func NewPrivateKeyFromInt

func NewPrivateKeyFromInt(key *big.Int) (*PrivateKey, error)

NewPrivateKeyFromInt creates a new SM2 private key from a given big integer. It returns an error if the provided key is nil.

Example
package main

import (
	"fmt"
	"log"
	"math/big"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	key := big.NewInt(0x123456)
	priv, err := sm2.NewPrivateKeyFromInt(key)
	if err != nil {
		log.Fatalf("fail to new private key %v", err)
	}
	fmt.Printf("%x\n", priv.D.Bytes())
}
Output:

123456

func ParseEnvelopedPrivateKey

func ParseEnvelopedPrivateKey(priv *PrivateKey, enveloped []byte) (*PrivateKey, error)

ParseEnvelopedPrivateKey parses an enveloped private key using the provided private key. The enveloped key is expected to be in ASN.1 format and encrypted with a symmetric cipher.

Parameters: - priv: The private key used to decrypt the symmetric key. - enveloped: The ASN.1 encoded and encrypted enveloped private key.

Returns: - A pointer to the decrypted PrivateKey. - An error if the parsing or decryption fails.

The function performs the following steps: 1. Unmarshals the ASN.1 data to extract the symmetric algorithm identifier, encrypted symmetric key, public key, and encrypted private key. 2. Verifies that the symmetric algorithm is supported (SM4 or SM4ECB). 3. Parses the public key from the ASN.1 data. 4. Decrypts the symmetric key using the provided private key. 5. Decrypts the SM2 private key using the decrypted symmetric key. 6. Verifies that the decrypted private key matches the public key.

Errors are returned if any of the steps fail, including invalid ASN.1 format, unsupported symmetric cipher, decryption failures, or key mismatches.

func ParseRawPrivateKey

func ParseRawPrivateKey(data []byte) (*PrivateKey, error)

ParseRawPrivateKey parses a private key encoded as a fixed-length big-endian integer, according to SEC 1, Version 2.0, Section 2.3.6 (sometimes referred to as the raw format). It returns an error if the value is not reduced modulo the curve's order minus one, or if it's zero.

Note that private keys are more commonly encoded in ASN.1 or PKCS#8 format, which can be parsed with [smx509.ParseECPrivateKey] or [smx509.ParsePKCS8PrivateKey] (and encoding/pem).

func (*PrivateKey) Decrypt

func (priv *PrivateKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)

Decrypt decrypts ciphertext msg to plaintext. The opts argument should be appropriate for the primitive used. Compliance with GB/T 32918.4-2016 chapter 7.

Example
package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"os"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	ciphertext, _ := hex.DecodeString("308194022100bd31001ce8d39a4a0119ff96d71334cd12d8b75bbc780f5bfc6e1efab535e85a02201839c075ff8bf761dcbe185c9750816410517001d6a130f6ab97fb23337cce150420ea82bd58d6a5394eb468a769ab48b6a26870ca075377eb06663780c920ea5ee0042be22abcf48e56ae9d29ac770d9de0d6b7094a874a2f8d26c26e0b1daaf4ff50a484b88163d04785b04585bb")

	// real private key should be from secret storage
	privKey, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
	testkey, err := sm2.NewPrivateKey(privKey)
	if err != nil {
		log.Fatalf("fail to new private key %v", err)
	}

	plaintext, err := testkey.Decrypt(nil, ciphertext, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
		return
	}

	fmt.Printf("Plaintext: %s\n", string(plaintext))
}
Output:

Plaintext: send reinforcements, we're going to advance

func (*PrivateKey) ECDH

func (k *PrivateKey) ECDH() (*ecdh.PrivateKey, error)

ECDH returns k as a ecdh.PrivateKey. It returns an error if the key is invalid according to the definition of ecdh.Curve.NewPrivateKey, or if the Curve is not supported by ecdh.

func (*PrivateKey) Equal

func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool

func (*PrivateKey) FromECPrivateKey

func (priv *PrivateKey) FromECPrivateKey(key *ecdsa.PrivateKey) (*PrivateKey, error)

FromECPrivateKey convert an ecdsa private key to SM2 private key.

func (*PrivateKey) Sign

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

Sign signs digest with priv, reading randomness from rand. Compliance with GB/T 32918.2-2016. The opts argument is currently used for SM2SignerOption checking only. If the opts argument is SM2SignerOption and its ForceGMSign is true, digest argument will be treated as raw data and UID will be taken from opts.

This method implements crypto.Signer, which is an interface to support keys where the private part is kept in, for example, a hardware module.

Example (ForceSM2)

This is a reference method to force SM2 standard with SDK crypto.Signer.

package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"log"
	"os"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	toSign := []byte("ShangMi SM2 Sign Standard")
	// real private key should be from secret storage
	privKey, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
	testkey, err := sm2.NewPrivateKey(privKey)
	if err != nil {
		log.Fatalf("fail to new private key %v", err)
	}

	// force SM2 sign standard and use default UID
	sig, err := testkey.Sign(rand.Reader, toSign, sm2.DefaultSM2SignerOpts)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error from sign: %s\n", err)
		return
	}

	// Since sign is a randomized function, signature will be
	// different each time.
	fmt.Printf("%x\n", sig)
}
Example (WithHash)
package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"log"
	"os"

	"github.com/yunmoon/gmsm/sm2"
)

func main() {
	toSign := []byte("ShangMi SM2 Sign Standard")
	// real private key should be from secret storage
	privKey, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
	testkey, err := sm2.NewPrivateKey(privKey)
	if err != nil {
		log.Fatalf("fail to new private key %v", err)
	}

	// calculate hash value
	h, err := sm2.NewHash(&testkey.PublicKey)
	if err != nil {
		log.Fatalf("fail to new hash %v", err)
	}
	h.Write(toSign)
	hashed := h.Sum(nil)

	sig, err := testkey.Sign(rand.Reader, hashed, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error from sign: %s\n", err)
		return
	}
	// Since sign is a randomized function, signature will be
	// different each time.
	fmt.Printf("%x\n", sig)
}

func (*PrivateKey) SignMessage

func (priv *PrivateKey) SignMessage(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error)

SignMessage signs a message with the private key, reading randomness from rand. If opts is an instance of SM2SignerOption, it will use the UID from opts. This method is used to comply with the crypto.MessageSigner interface.

func (*PrivateKey) SignWithSM2

func (priv *PrivateKey) SignWithSM2(rand io.Reader, uid, msg []byte) ([]byte, error)

SignWithSM2 signs uid, msg with priv, reading randomness from rand. Compliance with GB/T 32918.2-2016. Deprecated: please use Sign method directly.

type SM2SignerOption

type SM2SignerOption struct {
	// contains filtered or unexported fields
}

SM2SignerOption implements crypto.SignerOpts interface and is used for SM2-specific signing options. It is specific for SM2, used in private key's Sign method.

func NewSM2SignerOption

func NewSM2SignerOption(forceGMSign bool, uid []byte) *SM2SignerOption

NewSM2SignerOption creates a SM2 specific signer option. forceGMSign - if use GM specific sign logic, if yes, should pass raw message to sign. uid - if forceGMSign is true, then you can pass uid, if no uid is provided, system will use default one.

func (*SM2SignerOption) HashFunc

func (*SM2SignerOption) HashFunc() crypto.Hash

type Signer

type Signer interface {
	// Public returns the public key corresponding to the opaque,
	// private key.
	Public() crypto.PublicKey

	// SignWithSM2 signs raw message with the private key, possibly using entropy from
	// rand, and the user ID (UID). If the UID is not provided, a default UID (1234567812345678) is used.
	// The signature is generated using the SM2 algorithm.
	SignWithSM2(rand io.Reader, uid, msg []byte) ([]byte, error)
}

Signer is an interface for an opaque private key that can be used for signing operations. For example, an SM2 key kept in a hardware module. Deprecated: please use crypto.Signer directly.

Directories

Path Synopsis
Package sm2ec defines/implements SM2 elliptic curve structure.
Package sm2ec defines/implements SM2 elliptic curve structure.

Jump to

Keyboard shortcuts

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