### SM4 CBC encryption and decryption examples Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm4.md These Go examples show how to encrypt and decrypt data using the SM4 block cipher in CBC mode with PKCS7 padding. The encryption example generates a random IV and prepends it to the ciphertext; the decryption example extracts the IV from the beginning of the ciphertext and unpads the result. Both use a hard-coded key for demonstration only. ```go func Example_encryptCBC() { // Load your secret key from a safe place and reuse it across multiple // NewCipher calls. (Obviously don't use this example key for anything // real.) If you want to convert a passphrase to a key, use a suitable // package like bcrypt or scrypt. key, _ := hex.DecodeString("6368616e676520746869732070617373") plaintext := []byte("sm4 exampleplaintext") block, err := sm4.NewCipher(key) if err != nil { panic(err) } // CBC mode works on blocks so plaintexts may need to be padded to the // next whole block. For an example of such padding, see // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize) paddedPlainText := pkcs7.Pad(plaintext) // The IV needs to be unique, but not secure. Therefore it's common to // include it at the beginning of the ciphertext. ciphertext := make([]byte, sm4.BlockSize+len(paddedPlainText)) iv := ciphertext[:sm4.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { panic(err) } mode := cipher.NewCBCEncrypter(block, iv) mode.CryptBlocks(ciphertext[sm4.BlockSize:], paddedPlainText) fmt.Printf("%x\n", ciphertext) } ``` ```go func Example_decryptCBC() { // Load your secret key from a safe place and reuse it across multiple // NewCipher calls. (Obviously don't use this example key for anything // real.) If you want to convert a passphrase to a key, use a suitable // package like bcrypt or scrypt. key, _ := hex.DecodeString("6368616e676520746869732070617373") ciphertext, _ := hex.DecodeString("4d5a1486bfda1b34447afd5bb852e77a867cc6b726a8a0e0ef9b2c21fffc3a30b42acf504628f65cb3fba339101c98ff") block, err := sm4.NewCipher(key) if err != nil { panic(err) } // The IV needs to be unique, but not secure. Therefore it's common to // include it at the beginning of the ciphertext. if len(ciphertext) < sm4.BlockSize { panic("ciphertext too short") } iv := ciphertext[:sm4.BlockSize] ciphertext = ciphertext[sm4.BlockSize:] mode := cipher.NewCBCDecrypter(block, iv) // CryptBlocks can work in-place if the two arguments are the same. mode.CryptBlocks(ciphertext, ciphertext) // Unpad plaintext pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize) ciphertext, err = pkcs7.Unpad(ciphertext) if err != nil { panic(err) } fmt.Printf("%s\n", ciphertext) // Output: sm4 exampleplaintext } ``` -------------------------------- ### SM9 key wrapping and unwrapping with EncryptMasterPublicKey.WrapKey and EncryptPrivateKey.UnwrapKey Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm9.md These two Go examples show the SM9 key encapsulation workflow: first wrap a key using the master public key and user identifier, then unwrap it with the user's private key. The WrapKey function is randomized, so its output varies each run; the UnwrapKey example includes a fixed expected output. ```go func ExampleEncryptMasterPublicKey_WrapKey() { // get master public key, can be from pem masterPubKey := new(sm9.EncryptMasterPublicKey) keyBytes, _ := hex.DecodeString("03420004787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1") err := masterPubKey.UnmarshalASN1(keyBytes) if err != nil { fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err) return } hid := byte(0x03) uid := []byte("Bob") key, cipherDer, err := masterPubKey.WrapKey(rand.Reader, uid, hid, 32) if err != nil { fmt.Fprintf(os.Stderr, "Error from WrapKeyASN1: %s\n", err) return } // Since WrapKey is a randomized function, result will be // different each time. fmt.Printf("%s %s\n", hex.EncodeToString(key), hex.EncodeToString(cipherDer)) } ``` ```go func ExampleEncryptPrivateKey_UnwrapKey() { // real user encrypt private key should be from secret storage, e.g. password protected pkcs8 file kb, _ := hex.DecodeString("038182000494736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1") userKey := new(sm9.EncryptPrivateKey) err := userKey.UnmarshalASN1(kb) if err != nil { fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err) return } cipherDer, _ := hex.DecodeString("0342000447689629d1fa57e8def447f42b75e28518a1b692891528ca596f7bcbf581c7cf429ed01b114ce157ed4eadd0b2ded9a7e475e347f67b6affa3a6cf654573f978") key, err := userKey.UnwrapKey([]byte("Bob"), cipherDer, 32) if err != nil { fmt.Fprintf(os.Stderr, "Error from UnwrapKey: %s\n", err) return } fmt.Printf("%s\n", hex.EncodeToString(key)) // Output: 270c42505bca90a8084064ea8af279364405a8195f30664082ead3d6991ed70f } ``` -------------------------------- ### Construct private key from big.Int with sm2.NewPrivateKeyFromInt Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm2.md Constructs a private key from a big.Int value. The example prints the private key's D value in hex, which matches the input. ```go func ExampleNewPrivateKeyFromInt() { key := big.NewInt(0x123456) priv, err := sm2.NewPrivateKeyFromInt(key) if err != nil { log.Fatalf("私钥创建失败: %v", err) } fmt.Printf("%x\n", priv.D.Bytes()) // Output: 123456 } ``` -------------------------------- ### Construct public key from raw coordinates with sm2.NewPublicKey Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm2.md Constructs a public key from an uncompressed point (0x04 || X || Y). The example verifies by marshaling back and printing the hex. The output matches the input. ```go func ExampleNewPublicKey() { // 非压缩点格式: 0x04 || X || Y keypoints, _ := hex.DecodeString( "048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988" + "981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1") pub, err := sm2.NewPublicKey(keypoints) if err != nil { log.Fatalf("公钥创建失败: %v", err) } // 通过序列化回去验证 marshaled := elliptic.Marshal(sm2.P256(), pub.X, pub.Y) fmt.Printf("%x\n", marshaled) // Output: 048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1 } ``` -------------------------------- ### Complete HSMPrivateKey Example Implementing crypto.Signer and crypto.Decrypter Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm2-en.md Complete example of an HSMPrivateKey type that implements crypto.Signer and crypto.Decrypter. It includes the struct definition, compile-time interface compliance checks, and full implementations of Public(), Sign(), and Decrypt(). The Sign method handles SM2-specific signing by calculating the SM2 hash when opts is *sm2.SM2SignerOption with ForceGMSign, otherwise uses the digest as-is. The Decrypt method calls the SDK's InternalDecrypt. ```go package hsm import ( "crypto" "crypto/ecdsa" "io" "github.com/emmansun/gmsm/sm2" ) // HSMPrivateKey represents a private key stored in HSM type HSMPrivateKey struct { keyHandle int // HSM key handle/index publicKey *ecdsa.PublicKey // Associated public key sdkClient *SDFClient // SDF/SKF SDK client } // Ensure interface compliance at compile time var ( _ crypto.Signer = (*HSMPrivateKey)(nil) _ crypto.Decrypter = (*HSMPrivateKey)(nil) ) func (h *HSMPrivateKey) Public() crypto.PublicKey { return h.publicKey } func (h *HSMPrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { var hash []byte // Check if this is SM2-specific signing if sm2Opts, ok := opts.(*sm2.SM2SignerOption); ok && sm2Opts.ForceGMSign { // Calculate SM2 hash (ZA || message) var err error hash, err = sm2.CalculateSM2Hash(h.publicKey, digest, sm2Opts.UID) if err != nil { return nil, err } } else { // Use digest as-is (assumed to be pre-computed hash) hash = digest } // Call HSM signing function signature, err := h.sdkClient.InternalSign(h.keyHandle, hash) if err != nil { return nil, err } return signature, nil } func (h *HSMPrivateKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) ([]byte, error) { plaintext, err := h.sdkClient.InternalDecrypt(h.keyHandle, msg) if err != nil { return nil, err } return plaintext, nil } ``` -------------------------------- ### Construct private key from raw bytes with sm2.NewPrivateKey Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm2.md Constructs a private key from a 32-byte scalar. The example prints the private key's D value in hex, which matches the input. ```go func ExampleNewPrivateKey() { // 32字节标量形式的私钥 keyBytes, _ := hex.DecodeString( "6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85") priv, err := sm2.NewPrivateKey(keyBytes) if err != nil { log.Fatalf("私钥创建失败: %v", err) } fmt.Printf("%x\n", priv.D.Bytes()) // Output: 6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85 } ``` -------------------------------- ### Load two consecutive 64-bit integers with LXVD2X (PPC64LE) Source: https://github.com/emmansun/gmsm/wiki/Golang-ppc64x-asm-Reference Example of using LXVD2X to load two consecutive 64-bit integers with a permute mask for endian swap. The mask is defined with DATA and GLOBL directives. After loading, V[0] and V[1] contain the swapped values. ```asm DATA ·mask+0x00(SB)/8, $0x0f0e0d0c0b0a0908 // Permute for vector doubleword endian swap DATA ·mask+0x08(SB)/8, $0x0706050403020100 GLOBL ·mask(SB), RODATA, $16 MOVD $·mask(SB), R4 LVXD2X (R4), V0 ``` -------------------------------- ### Sign and detach content with pkcs7 Source: https://github.com/emmansun/gmsm/blob/develop/pkcs7/README.md Shows how to create a detached PKCS7 signature using NewSignedData, AddSigner, Detach, and Finish. It then parses the signed data, reattaches the content, and verifies the signature. The example prints the signed data as PEM to stdout. ```go package main import ( "bytes" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "os" "github.com/emmansun/gmsm/pkcs7" ) func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateKey) (signed []byte, err error) { toBeSigned, err := NewSignedData(content) if err != nil { err = fmt.Errorf("Cannot initialize signed data: %s", err) return } if err = toBeSigned.AddSigner(cert, privkey, SignerInfoConfig{}); err != nil { err = fmt.Errorf("Cannot add signer: %s", err) return } // Detach signature, omit if you want an embedded signature toBeSigned.Detach() signed, err = toBeSigned.Finish() if err != nil { err = fmt.Errorf("Cannot finish signing data: %s", err) return } // Verify the signature pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed}) p7, err := pkcs7.Parse(signed) if err != nil { err = fmt.Errorf("Cannot parse our signed data: %s", err) return } // since the signature was detached, reattach the content here p7.Content = content if bytes.Compare(content, p7.Content) != 0 { err = fmt.Errorf("Our content was not in the parsed data:\n\tExpected: %s\n\tActual: %s", content, p7.Content) return } if err = p7.Verify(); err != nil { err = fmt.Errorf("Cannot verify our signed data: %s", err) return } return signed, nil } ``` -------------------------------- ### Load two consecutive 64-bit integers with LVX (PPC64LE) Source: https://github.com/emmansun/gmsm/wiki/Golang-ppc64x-asm-Reference Example of using LVX to load two consecutive 64-bit integers with a permute mask for endian swap. The mask is defined with DATA and GLOBL directives. After loading, V[2] and V[3] contain the swapped values. ```asm DATA ·mask+0x00(SB)/8, $0x0f0e0d0c0b0a0908 // Permute for vector doubleword endian swap DATA ·mask+0x08(SB)/8, $0x0706050403020100 GLOBL ·mask(SB), RODATA, $16 MOVD $·mask(SB), R4 LVX (R4), V0 ``` -------------------------------- ### signTBS: Sign TBS bytes (incomplete) Source: https://github.com/emmansun/gmsm/blob/develop/scripts/smx509/baseline/x509.go.txt Starts the signTBS function, which is intended to sign the to-be-signed (TBS) bytes. It obtains the hash function from the signature algorithm, but the function body is incomplete in the source. ```go func signTBS(tbs []byte, key crypto.Signer, sigAlg SignatureAlgorithm, rand io.Reader) ([]byte, error) { hashFunc := sigAlg.hashFunc() } ``` -------------------------------- ### Install GMSM with go get Source: https://github.com/emmansun/gmsm/blob/develop/README-EN.md Use this command to add the GMSM library to your Go module. Run it in your project directory. ```bash go get github.com/emmansun/gmsm@latest ``` -------------------------------- ### SLH-DSA Signing (Pure and Pre-hash Modes) Source: https://github.com/emmansun/gmsm/blob/develop/docs/pqc-en.md Demonstrates pure signing (recommended), signing with a context string, and pre-hash mode using PrehashOID. The opts must match those used during signing. ```go // Pure signing (recommended) opts := &slhdsa.Options{} sig, err := sk.SignMessage(rand.Reader, message, opts) // With a context string opts = &slhdsa.Options{Context: []byte("my-context")} sig, err = sk.SignMessage(rand.Reader, message, opts) // Pre-hash mode (HashSLH-DSA) opts = &slhdsa.Options{ PrehashOID: slhdsa.OIDDigestAlgorithmSHA256, } sig, err = sk.SignMessage(rand.Reader, message, opts) ``` -------------------------------- ### EC-ElGamal homomorphic encryption voting example Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm2-en.md Example of EC-ElGamal partially homomorphic encryption for electronic voting. Encrypts votes, adds them without decryption, and decrypts the total. Supports uint32 and int32 types; practical for small values due to discrete log computation. ```go // Electronic voting: Add encrypted votes without decryption encryptedVote1 := Encrypt(publicKey, 1) // Vote "yes" encryptedVote2 := Encrypt(publicKey, 0) // Vote "no" encryptedTotal := Add(encryptedVote1, encryptedVote2) totalVotes := Decrypt(privateKey, encryptedTotal) // Result: 1 ``` -------------------------------- ### Plan 9 system roots loading in smx509 Source: https://github.com/emmansun/gmsm/blob/develop/scripts/smx509/baseline/root_plan9.go.txt Plan 9 build-tagged implementation for the smx509 package. Defines the certificate file path /sys/lib/tls/ca.pem, a no-op systemVerify, and loadSystemRoots that reads the first available PEM file into a CertPool, returning the best error if none load. ```go // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build plan9 package smx509 import ( "os" ) // Possible certificate files; stop after finding one. var certFiles = []string{ "/sys/lib/tls/ca.pem", } func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } func loadSystemRoots() (*CertPool, error) { roots := NewCertPool() var bestErr error for _, file := range certFiles { data, err := os.ReadFile(file) if err == nil { roots.AppendCertsFromPEM(data) return roots, nil } if bestErr == nil || (os.IsNotExist(bestErr) && !os.IsNotExist(err)) { bestErr = err } } if bestErr == nil { return roots, nil } return nil, bestErr } ``` -------------------------------- ### Create and sign a PKIX CertificateList (CRL) Source: https://github.com/emmansun/gmsm/blob/develop/scripts/smx509/baseline/x509.go.txt Builds a PKIX CertificateList (CRL) by normalizing revocation times to UTC, constructing the TBSCertificateList, optionally adding the Authority Key Identifier extension, marshaling the TBS list, signing it with signTBS, and returning the ASN.1 DER-encoded certificate list. Requires prior variables: revokedCerts, algorithmIdentifier, c, now, expiry, key, signatureAlgorithm, rand, and oidExtensionAuthorityKeyId. ```go // Force revocation times to UTC per RFC 5280. revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts)) for i, rc := range revokedCerts { rc.RevocationTime = rc.RevocationTime.UTC() revokedCertsUTC[i] = rc } tbsCertList := pkix.TBSCertificateList{ Version: 1, Signature: algorithmIdentifier, Issuer: c.Subject.ToRDNSequence(), ThisUpdate: now.UTC(), NextUpdate: expiry.UTC(), RevokedCertificates: revokedCertsUTC, } // Authority Key Id if len(c.SubjectKeyId) > 0 { var aki pkix.Extension aki.Id = oidExtensionAuthorityKeyId aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) if err != nil { return nil, err } tbsCertList.Extensions = append(tbsCertList.Extensions, aki) } tbsCertListContents, err := asn1.Marshal(tbsCertList) if err != nil { return nil, err } tbsCertList.Raw = tbsCertListContents signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand) if err != nil { return nil, err } return asn1.Marshal(pkix.CertificateList{ TBSCertList: tbsCertList, SignatureAlgorithm: algorithmIdentifier, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } ``` -------------------------------- ### subjectBytes: Get certificate subject bytes Source: https://github.com/emmansun/gmsm/blob/develop/scripts/smx509/baseline/x509.go.txt Returns the raw subject bytes of a certificate, either from the cached RawSubject field or by marshaling the Subject's RDN sequence. ```go func subjectBytes(cert *Certificate) ([]byte, error) { if len(cert.RawSubject) > 0 { return cert.RawSubject, nil } return asn1.Marshal(cert.Subject.ToRDNSequence()) } ``` -------------------------------- ### sm2.NewPublicKey() Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm2.md Constructs a public key from raw uncompressed point coordinates. Returns the public key and an error. ```APIDOC ## sm2.NewPublicKey() ### Description Constructs a public key from raw uncompressed point coordinates. Returns the public key and an error. ### Function Signature ```go func NewPublicKey(keypoints []byte) (*ecdsa.PublicKey, error) ``` ### Parameters - **keypoints** ([]byte) - Required - Uncompressed point format: 0x04 || X || Y. ### Return Values - **pub** (*ecdsa.PublicKey) - The constructed public key. - **err** (error) - Error if construction fails. ### Example ```go func ExampleNewPublicKey() { keypoints, _ := hex.DecodeString( "048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988" + "981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1") pub, err := sm2.NewPublicKey(keypoints) if err != nil { log.Fatalf("公钥创建失败: %v", err) } marshaled := elliptic.Marshal(sm2.P256(), pub.X, pub.Y) fmt.Printf("%x\n", marshaled) } ``` ``` -------------------------------- ### ParseCRL: Parse PEM or DER CRL Source: https://github.com/emmansun/gmsm/blob/develop/scripts/smx509/baseline/x509.go.txt Deprecated function that transparently handles PEM encoding if the input starts with the PEM CRL prefix, then delegates to ParseDERCRL. Use ParseRevocationList instead. ```go var pemCRLPrefix = []byte("-----BEGIN X509 CRL") // pemType is the type of a PEM encoded CRL. var pemType = "X509 CRL" // ParseCRL parses a CRL from the given bytes. It's often the case that PEM // encoded CRLs will appear where they should be DER encoded, so this function // will transparently handle PEM encoding as long as there isn't any leading // garbage. // // Deprecated: Use [ParseRevocationList] instead. func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) { if bytes.HasPrefix(crlBytes, pemCRLPrefix) { block, _ := pem.Decode(crlBytes) if block != nil && block.Type == pemType { crlBytes = block.Bytes } } return ParseDERCRL(crlBytes) } ``` -------------------------------- ### string Source: https://github.com/emmansun/gmsm/blob/develop/scripts/smx509/baseline/verify.go.txt string ```string string ``` -------------------------------- ### Benchmark output for Invert and P256Inverse Source: https://github.com/emmansun/gmsm/wiki/High‐assurance-field-inversion-for-curve‐based-cryptography These are the benchmark results for the two inversion methods on Windows with an Intel i5-9500 CPU. The Invert method (addchain-optimized) runs in about 5806 ns/op with zero allocations, while P256Inverse (fiat-crypto) runs in about 20644 ns/op with 32 B/op and 1 alloc/op. The results show that the divsteps-based fiat-crypto inversion is slower than the addchain-optimized method. ```text goos: windows goarch: amd64 pkg: github.com/emmansun/gmsm/internal/sm2ec/fiat cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz BenchmarkInvert BenchmarkInvert-6 227496 5806 ns/op 0 B/op 0 allocs/op PASS ok github.com/emmansun/gmsm/internal/sm2ec/fiat 1.792s goos: windows goarch: amd64 pkg: github.com/emmansun/gmsm/internal/sm2ec/fiat cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz BenchmarkP256Inverse BenchmarkP256Inverse-6 58394 20644 ns/op 32 B/op 1 allocs/op PASS ok github.com/emmansun/gmsm/internal/sm2ec/fiat 1.793s ``` -------------------------------- ### Client Flow: Generate key shares and compute shared secret Source: https://github.com/emmansun/gmsm/blob/develop/docs/pqc-en.md Shows how to create a key exchange object for X25519MLKEM768, generate ClientHello key shares, and compute the shared secret from the server's key share. The clientKeyShares slice contains a hybrid share and a classical-only fallback share. ```go import "github.com/emmansun/gmsm/tls13" // Create a key exchange object ke, err := tls13.NewKeyExchange(tls13.X25519MLKEM768) // Generate ClientHello key shares // clientKeyShares[0]: hybrid key share // clientKeyShares[1]: classical-only fallback share priv, clientKeyShares, err := ke.KeyShares(rand.Reader) // Send clientKeyShares[0].Data to the server (in ClientHello) // Receive serverKeyShare from the server (in ServerHello) // Compute the shared secret from the server's key share sharedSecret, err := ke.ClientSharedSecret(priv, serverKeyShare.Data) ``` -------------------------------- ### SM2 Decryption with Auto-Detection using PrivateKey.Decrypt Source: https://github.com/emmansun/gmsm/blob/develop/docs/sm2-en.md Decrypts an SM2 ciphertext using the private key's Decrypt method, which automatically detects ASN.1 or C1C3C2 format. The example loads a private key from hex and prints the recovered plaintext. The expected output is shown in the comment. ```go func ExamplePrivateKey_Decrypt() { ciphertext, _ := hex.DecodeString( "308194022100bd31001ce8d39a4a0119ff96d71334cd12d8b75bbc780f5bfc6e1efab535e85a" + "02201839c075ff8bf761dcbe185c9750816410517001d6a130f6ab97fb23337cce1504" + "20ea82bd58d6a5394eb468a769ab48b6a26870ca075377eb06663780c920ea5ee00" + "42be22abcf48e56ae9d29ac770d9de0d6b7094a874a2f8d26c26e0b1daaf4ff50a484b88163d04785b04585bb") // Load private key privKey, _ := hex.DecodeString( "6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85") privateKey, err := sm2.NewPrivateKey(privKey) if err != nil { log.Fatalf("Failed to create private key: %v", err) } // Decrypt (auto-detects ASN.1 or C1C3C2 format) plaintext, err := privateKey.Decrypt(nil, ciphertext, nil) if err != nil { fmt.Fprintf(os.Stderr, "Decryption error: %s\n", err) return } fmt.Printf("Plaintext: %s\n", string(plaintext)) // Output: Plaintext: send reinforcements, we're going to advance } ``` -------------------------------- ### Configure signer options for RSA-PSS and sign message Source: https://github.com/emmansun/gmsm/blob/develop/scripts/smx509/baseline/x509.go.txt Sets up signer options for RSA-PSS with salt length equal to hash, then signs the message using crypto.SignMessage. After signing, it verifies the signature with checkSignature and returns an error if invalid. ```go var signerOpts crypto.SignerOpts = hashFunc if sigAlg.isRSAPSS() { signerOpts = &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc, } } signature, err := crypto.SignMessage(key, rand, tbs, signerOpts) if err != nil { return nil, err } // Check the signature to ensure the crypto.Signer behaved correctly. if err := checkSignature(sigAlg, tbs, signature, key.Public(), true); err != nil { return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err) } return signature, nil } ``` -------------------------------- ### Sample lookup table and matrix M for SM4 Source: https://github.com/emmansun/gmsm/wiki/SM4-with-AESENCLAST Sample lookup table data showing two example tables with their first element (C) and the resulting matrix M. The first table uses T[0]=0x06 and the second uses T[0]=0x3c. The matrix rows are derived by XORing the table entries at indices 1,2,4,8,16,32,64,128 with T[0]. ```text 1 2 3 4 5 6 7 8 00000110 01110011 01110101 11100101 11100011 10010110 10010000 01010110 0x00, 0x06, 0x73 0x75 0xE5 0xE3 0x96 0x90 0x56 1 10100010 2 01001001 3 11111011 4 00001001 5 10101011 6 01000000 7 11100010 8 00010010 9 00010010 00001001 01001001 10100010 01010110 11100101 01110011 00000110 1 2 3 4 5 6 7 8 00111100 10101001 11111010 10110110 0x00 0x3c 0xa9 0xfa 0xb6 1 11011100 2 10101111 3 4 11011101 5 6 7 8 10111111 10111111 11011101 10101111 11011100 10110110 11111010 10101001 00111100 ```