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 ¶
- Constants
- Variables
- func ASN1Ciphertext2Plain(ciphertext []byte, opts *EncrypterOpts) ([]byte, error)
- func AdjustCiphertextSplicingOrder(ciphertext []byte, from, to ciphertextSplicingOrder) ([]byte, error)
- func CalculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error)
- func CalculateZA(pub *ecdsa.PublicKey, uid []byte) ([]byte, error)
- func Decrypt(priv *PrivateKey, ciphertext []byte) ([]byte, error)
- func Encrypt(random io.Reader, pub *ecdsa.PublicKey, msg []byte, opts *EncrypterOpts) ([]byte, error)
- func EncryptASN1(random io.Reader, pub *ecdsa.PublicKey, msg []byte) ([]byte, error)
- func IsSM2PublicKey(publicKey any) bool
- func MarshalEnvelopedPrivateKey(rand io.Reader, pub *ecdsa.PublicKey, tobeEnveloped *PrivateKey) ([]byte, error)
- func NewHash(pub *ecdsa.PublicKey) (hash.Hash, error)
- func NewHashWithHashAndUserID(pub *ecdsa.PublicKey, h func() hash.Hash, userID []byte) (hash.Hash, error)
- func NewHashWithUserID(pub *ecdsa.PublicKey, userID []byte) (hash.Hash, error)
- func NewPublicKey(key []byte) (*ecdsa.PublicKey, error)
- func P256() elliptic.Curve
- func ParseCompressedPublicKey(data []byte) (*ecdsa.PublicKey, error)
- func ParseUncompressedPublicKey(data []byte) (*ecdsa.PublicKey, error)
- func PlainCiphertext2ASN1(ciphertext []byte, from ciphertextSplicingOrder) ([]byte, error)
- func PublicKeyToECDH(k *ecdsa.PublicKey) (*ecdh.PublicKey, error)
- func RecoverPublicKeysFromSM2Signature(hash, sig []byte) ([]*ecdsa.PublicKey, error)
- func Sign(rand io.Reader, priv *ecdsa.PrivateKey, hash []byte) (r, s *big.Int, err error)
- func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte, opts crypto.SignerOpts) ([]byte, error)
- func SignWithSM2(rand io.Reader, priv *ecdsa.PrivateKey, uid, msg []byte) (r, s *big.Int, err error)
- func Verify(pub *ecdsa.PublicKey, hash []byte, r, s *big.Int) bool
- func VerifyASN1(pub *ecdsa.PublicKey, hash, sig []byte) bool
- func VerifyASN1WithSM2(pub *ecdsa.PublicKey, uid, msg, sig []byte) bool
- func VerifyWithSM2(pub *ecdsa.PublicKey, uid, msg []byte, r, s *big.Int) bool
- type DecrypterOpts
- type EncrypterOpts
- type KeyExchange
- func (ke *KeyExchange) ConfirmInitiator(s1 []byte) ([]byte, error)
- func (ke *KeyExchange) ConfirmResponder(rB *ecdsa.PublicKey, sB []byte) ([]byte, []byte, error)
- func (ke *KeyExchange) Destroy()
- func (ke *KeyExchange) InitKeyExchange(rand io.Reader) (*ecdsa.PublicKey, error)
- func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, rA *ecdsa.PublicKey) (*ecdsa.PublicKey, []byte, error)
- func (ke *KeyExchange) SetPeerParameters(peerPub *ecdsa.PublicKey, peerUID []byte) error
- type PrivateKey
- func GenerateKey(rand io.Reader) (*PrivateKey, error)
- func NewPrivateKey(key []byte) (*PrivateKey, error)
- func NewPrivateKeyFromInt(key *big.Int) (*PrivateKey, error)
- func ParseEnvelopedPrivateKey(priv *PrivateKey, enveloped []byte) (*PrivateKey, error)
- func ParseRawPrivateKey(data []byte) (*PrivateKey, error)
- func (priv *PrivateKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)
- func (k *PrivateKey) ECDH() (*ecdh.PrivateKey, error)
- func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool
- func (priv *PrivateKey) FromECPrivateKey(key *ecdsa.PrivateKey) (*PrivateKey, error)
- func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error)
- func (priv *PrivateKey) SignMessage(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error)
- func (priv *PrivateKey) SignWithSM2(rand io.Reader, uid, msg []byte) ([]byte, error)
- type SM2SignerOption
- type Signer
Examples ¶
Constants ¶
const ( //MarshalUncompressed uncompressed marshal mode MarshalUncompressed pointMarshalMode = iota //MarshalCompressed compressed marshal mode MarshalCompressed //MarshalHybrid hybrid marshal mode MarshalHybrid )
const ( C1C3C2 ciphertextSplicingOrder = iota C1C2C3 )
const ( ENCODING_PLAIN ciphertextEncoding = iota ENCODING_ASN1 )
Variables ¶
var ( ASN1EncrypterOpts = &EncrypterOpts{ENCODING_ASN1, MarshalUncompressed, C1C3C2} ASN1DecrypterOpts = &DecrypterOpts{ENCODING_ASN1, C1C3C2} )
var DefaultSM2SignerOpts = NewSM2SignerOption(true, nil)
DefaultSM2SignerOpts uses default UID and forceGMSign is true.
var ErrDecryption = errors.New("sm2: decryption error")
ErrDecryption represents a failure to decrypt a message. It is deliberately vague to avoid adaptive attacks.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ParseCompressedPublicKey ¶ added in v1.0.1
func ParseUncompressedPublicKey ¶
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 ¶
PlainCiphertext2ASN1 utility method to convert plain encoding ciphertext to ASN.1 encoding format
func PublicKeyToECDH ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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
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 ¶
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 ¶
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 ¶
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.