SM2
SM2 is an elliptic curve public key cryptographic algorithm (GM/T 0003-2012) established by China's State Cryptography Administration, and is one of the core algorithms of China's commercial cryptography standards. dongle supports standard and streaming SM2 digital signatures, providing signature and verification functions compliant with GM/T 0009-2012 standard.
SM2 signature algorithm features:
- Chinese Cryptographic Standard: Fully compliant with GM/T 0009-2012 digital signature standard
- High Security: Uses 256-bit elliptic curve, providing security strength equivalent to RSA 3072 bits
- User Identifier: Supports custom UID (User Identifier), default is
"1234567812345678" - Hash Algorithm: Built-in SM3 hash algorithm for message digest
- Signature Format: Uses ASN.1 DER format (
SEQUENCE { r, s }) by default, and can be switched to the fixed 64-byter || sformat withSetSingMode(keypair.Bytes) - Performance Optimization: Supports window size optimization to improve signature and verification performance
Notes:
- Key format: Uses
PKCS#8format for private keys,SPKI/PKIXformat for public keys - Signature format: Signing and verification must use the same
SingMode; the default isASN1, which is what BouncyCastle and Java usually produce, while some gateways and embedded devices use the fixed 64-byte raw signature - Key material: In addition to PEM,
SetPublicKey/SetPrivateKeyaccept base64 or hex encoded DER and raw key material (a 65 byte uncompressed point for public keys, a 32 byte scalar for private keys), and normalize the result to PEM - UID Consistency: Signing and verification must use the same UID, otherwise verification will fail
- Default UID: If UID is not set, the default value
"1234567812345678"will be used (compliant with GM/T 0009-2012) - Private key security: Private keys must be properly secured and not leaked. Only the private key holder can generate valid signatures
- Signature verification: Anyone can use the public key to verify the validity of signatures
- Standards compliance: Fully compliant with GM/T 0009-2012 (Digital Signature Algorithm) standard
Import required modules:
import (
"github.com/dromara/dongle"
"github.com/dromara/dongle/crypto/keypair"
)Create Key Pair
kp := keypair.NewSm2KeyPair()
// Set user identifier UID (optional, default is "1234567812345678")
kp.SetUID([]byte("user@example.com"))
// Set signature format (optional, default is ASN1)
kp.SetSingMode(keypair.ASN1) // or keypair.Bytes
// Set window size (optional, default is 4, range 2-6, for performance optimization)
kp.SetWindow(4)Generate Key Pair
// Generate SM2 key pair (256-bit elliptic curve)
err := kp.GenKeyPair()
if err != nil {
panic(err)
}
// Get PEM format public key
publicKey := kp.PublicKey
// Get PEM format private key
privateKey := kp.PrivateKeySet Key Pair from Existing PEM Format Keys
// Set PEM format public key
kp.PublicKey = []byte(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEv6TXzg5xkLbTkzQzmucCcGbVF1pv
BuOVxSa7tZEvT1bEKqF7WJx8UQ/a7R5YDslbMxPByZGqfPaeQEpwv3emQg==
-----END PUBLIC KEY-----`)
// Set PEM format private key
kp.PrivateKey = []byte(`-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgsXklJOzFBfCXQGaP
5kVornBxt1WjgUIv21Imv7ALAtygCgYIKoEcz1UBgi2hRANCAAS/pNfODnGQttOT
NDOa5wJwZtUXWm8G45XFJru1kS9PVsQqoXtYnHxRD9rtHlgOyVszE8HJkap89p5A
SnC/d6ZC
-----END PRIVATE KEY-----`)Set Key Pair from Existing DER Format Keys
Besides base64 encoded DER, SetPublicKey / SetPrivateKey also accept hex encoded DER and raw key material (a 65 byte uncompressed point for public keys, a 32 byte scalar for private keys), and normalize the result to PEM.
// Set Base64 encoded DER format public key
kp.SetPublicKey([]byte("MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEv6TXzg5xkLbTkzQzmucCcGbVF1pvBuOVxSa7tZEvT1bEKqF7WJx8UQ/a7R5YDslbMxPByZGqfPaeQEpwv3emQg=="))
// Set Base64 encoded DER format private key
kp.SetPrivateKey([]byte("MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgsXklJOzFBfCXQGaP5kVornBxt1WjgUIv21Imv7ALAtygCgYIKoEcz1UBgi2hRANCAAS/pNfODnGQttOTNDOa5wJwZtUXWm8G45XFJru1kS9PVsQqoXtYnHxRD9rtHlgOyVszE8HJkap89p5ASnC/d6ZC"))Format DER Format Keys to PEM Format
// Format base64 encoded DER format public key to PEM format
publicKey, err := kp.FormatPublicKey([]byte("MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEv6TXzg5xkLbTkzQzmucCcGbVF1pvBuOVxSa7tZEvT1bEKqF7WJx8UQ/a7R5YDslbMxPByZGqfPaeQEpwv3emQg=="))
// Format base64 encoded DER format private key to PEM format
privateKey, err := kp.FormatPrivateKey([]byte("MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgsXklJOzFBfCXQGaP5kVornBxt1WjgUIv21Imv7ALAtygCgYIKoEcz1UBgi2hRANCAAS/pNfODnGQttOTNDOa5wJwZtUXWm8G45XFJru1kS9PVsQqoXtYnHxRD9rtHlgOyVszE8HJkap89p5ASnC/d6ZC"))Compress PEM Format Keys to DER Format
// Compress PEM format public key to base64 encoded DER format (extract the base64 encoded DER from the PEM block)
publicKey := kp.CompressPublicKey([]byte(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEv6TXzg5xkLbTkzQzmucCcGbVF1pv
BuOVxSa7tZEvT1bEKqF7WJx8UQ/a7R5YDslbMxPByZGqfPaeQEpwv3emQg==
-----END PUBLIC KEY-----`))
// Compress PEM format private key to base64 encoded DER format (extract the base64 encoded DER from the PEM block)
privateKey := kp.CompressPrivateKey([]byte(`-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgsXklJOzFBfCXQGaP
5kVornBxt1WjgUIv21Imv7ALAtygCgYIKoEcz1UBgi2hRANCAAS/pNfODnGQttOT
NDOa5wJwZtUXWm8G45XFJru1kS9PVsQqoXtYnHxRD9rtHlgOyVszE8HJkap89p5A
SnC/d6ZC
-----END PRIVATE KEY-----`))
CompressPublicKey/CompressPrivateKeydecode the input withpem.Decode, so PEM blocks with optional headers such asBag Attributesare handled as well.
Private Key Signing
Streaming SM2 signatures buffer the whole input and sign it once on
Close.
Input Data
// Input string
signer := dongle.Sign.FromString("hello world").BySm2(kp)
// Input byte slice
signer := dongle.Sign.FromBytes([]byte("hello world")).BySm2(kp)
// Input file stream
file, _ := os.Open("test.txt")
signer := dongle.Sign.FromFile(file).BySm2(kp)
// Check signing error
if signer.Error != nil {
fmt.Printf("Signing error: %v\n", signer.Error)
return
}Output Data
// Output Hex encoded signature string
hexString := signer.ToHexString() // e.g.: 3045022100a1b2c3d4e5f6...
// Output Hex encoded signature byte slice
hexBytes := signer.ToHexBytes() // e.g.: []byte("3045022100a1b2c3d4e5f6...")
// Output Base64 encoded signature string
base64String := signer.ToBase64String() // e.g.: MEUCIQCobLPeVv...
// Output Base64 encoded signature byte slice
base64Bytes := signer.ToBase64Bytes() // e.g.: []byte("MEUCIQCobLPeVv...")
// Output raw unencoded signature string
rawString := signer.ToRawString()
// Output raw unencoded signature byte slice
rawBytes := signer.ToRawBytes()With
keypair.Bytes,ToRawBytes()returns a fixed 64-byter || svalue (32 bytes each forrands), andToHexString()returns 128 hexadecimal characters.
Public Key Verification
Note: The
WithXxxSignmethod must be called beforeBySm2
Input Data
// Input string
verifier := dongle.Verify.FromString("hello world")
// Input byte slice
verifier := dongle.Verify.FromBytes([]byte("hello world"))
// Input file stream
file, _ := os.Open("test.txt")
verifier := dongle.Verify.FromFile(file)
// Set Hex encoded signature
verifier.WithHexSign(hexBytes).BySm2(kp)
// Set Base64 encoded signature
verifier.WithBase64Sign(base64Bytes).BySm2(kp)
// Set raw unencoded signature
verifier.WithRawSign(rawBytes).BySm2(kp)
// Check verification error
if verifier.Error != nil {
fmt.Printf("Verification error: %v\n", verifier.Error)
return
}Output Data
// Output verification result
verifier.ToBool() // true or false