gmsm

repository·master·Indexed 24 days ago

https://github.com/tjfoc/gmsm

A Golang library implementing Chinese National Standard (Guomi) cryptographic algorithms, including SM2 (ECC), SM3 (Hash), and SM4 (Block Cipher). It provides support for GMSSL/TLS automatic switching, TLCP mutual authentication, and HTTPS clients. The library integrates with standard Go crypto interfaces and includes utilities for PKCS#7 padding for stream encryption and decryption.

Tokens
5.2K
Snippets
10
Records
19
Agent score
83%

What's inside gmsm

  1. Overview of gmsm capabilities

    master
    gmsm is a Golang-based library providing implementations for Chinese National Standard (Guomi) cryptographic algorithms, specifically SM2, SM3, and SM4. It is designed to integrate with standard Go crypto interfaces where possible.
  2. SM4: Block Cipher

    master

    The SM4 implementation provides symmetric block cipher capabilities, including:

    • Key Management: Support for Generate Key operations.
    • Encryption/Decryption: Support for Encrypt and Decrypt operations.
    • Block Interface: Provides the Cipher.Block interface.
    • File Formats: Support for both encrypted and unencrypted PEM file formats (using PEM block encryption via x509.EncryptPEMBlock).
  3. How GMSSL/TLS automatic switching works on the server

    master

    The server can automatically switch between three modes: TLS, GMSSL, and GMSSL/TLS (Auto-Switch). This is controlled via the gmtls.Config object.

    When a gmtls.Conn performs its first Read or Write, a HandShake is triggered. In GMSSL/TLS (Auto-Switch) mode, the server analyzes the ClientHello message from the client. Based on the protocol version detected, it selects the appropriate handshake process:

    • If the client supports GMSSL, it uses the serverHandshakeStateGM context and the GMSSL handshake.
    • If the client uses standard TLS, it uses the serverHandshakeState context and the TLS handshake.

    To support this, the server must provide two sets of certificate/key pairs: one for standard TLS (RSA/ECC) and one for GMSSL (SM2). The server uses gmtls.Config#GetCertificate to dynamically select the correct pair based on the client's version, and gmtls.Config#GetKECertificate to provide the key pair used during the GMSSL key exchange.

  4. SM2: Elliptic Curve Cryptography

    master

    The SM2 implementation provides elliptic curve cryptography capabilities, including:

    • Key Management: Support for Generate Key operations.
    • Digital Signatures: Support for Sign and Verify operations.
    • File Formats: Support for both encrypted and unencrypted PEM file formats (following RFC5958).
    • Certificates: Support for generating, reading, and writing certificates (with interfaces compatible with RSA and ECDSA certificates).
    • Certificate Chains: Support for certificate chain operations (compatible with RSA and ECDSA).
    • Go Integration: Implements the crypto.Signer interface.
  5. Understand Guomi SSL (TLCP) implementation

    master

    The project supports Guomi SSL, which has been upgraded to the TLCP protocol (following GBT 38636-2020). TLCP includes support for the SM4 GCM encryption mode.

    For detailed usage, refer to the guide: gmtls/websvr/README.md (《tjfoc 国密SSL协议快速入门》).

    Example entry points in the repository:

    • HTTPS Web server test case: gmtls/websvr/websvr.go
    • TLS GRPC test case: gmtls/websvr/credentials_test.go
  6. Configure TLCP mutual (two-way) authentication

    master

    Server-side Configuration

    To require clients to present a certificate (mutual authentication) using TLCP:

    1. Enable TLCP support via gmtls.NewGMSupport().
    2. Provide both signature and encryption certificates in Certificates.
    3. Set ClientAuth to gmtls.RequireAndVerifyClientCert.
    4. Provide the root CA chain in ClientCAs to verify client certificates.
    config := &gmtls.Config{
        GMSupport:    gmtls.NewGMSupport(),
        Certificates: []gmtls.Certificate{sigCert, encCert},
        ClientAuth:   gmtls.RequireAndVerifyClientCert,
        ClientCAs:    certPool,
    }

    Client-side Configuration

    To perform mutual authentication as a client:

    1. Enable TLCP support via gmtls.NewGMSupport().
    2. Provide your client's signature certificate and key pair in Certificates.
    3. Provide the server's root CA chain in RootCAs.
    4. Set InsecureSkipVerify to false to ensure security.
    config := &gmtls.Config{
        GMSupport:          gmtls.NewGMSupport(),
        RootCAs:            certPool,
        Certificates:       []gmtls.Certificate{authKeypair},
        InsecureSkipVerify: false,
    }
  7. Enable GMSSL/TLS automatic switching mode

    master

    To implement a server that automatically switches between GMSSL and TLS, follow these steps:

    1. Prepare three certificate/key pairs: SM2 signature (sigCert), SM2 encryption (encCert), and RSA/ECC (rsaKeypair).
    2. Implement a GetCertificate function that inspects gmtls.ClientHelloInfo.SupportedVersions. If gmtls.VersionGMSSL is present, return the SM2 signature certificate; otherwise, return the RSA/ECC certificate.
    3. Implement a GetKECertificate function that returns the SM2 encryption certificate.
    4. Create a gmtls.GMSupport object and call EnableMixMode().
    5. Initialize gmtls.Config with the support object and your custom certificate functions.
    fncGetSignCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) {
        gmFlag := false
        for _, v := range info.SupportedVersions {
            if v == gmtls.VersionGMSSL {
                gmFlag = true
                break
            }
        }
        if gmFlag {
            return &sigCert, nil
        } else {
            return &rsaKeypair, nil
        }
    }
    
    fncGetEncCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) {
        return &encCert, nil
    }
    
    support := gmtls.NewGMSupport()
    support.EnableMixMode()
    config := &gmtls.Config{
        GMSupport:        support,
        GetCertificate:   fncGetSignCertKeypair,
        GetKECertificate: fncGetEncCertKeypair,
    }
    
    ln, err := gmtls.Listen("tcp", ":443", config)
    // ... use ln to serve HTTP
  8. Use PKCS#7 padding for stream encryption and decryption

    master

    When using block ciphers directly, you must manually handle padding and unpadding, which is cumbersome for files and streams. The padding package provides helpers to automate this using PKCS#7 padding.

    Stream Wrappers

    • padding.PKCS7PaddingReader: Automatically adds padding when writing to the end of a stream.
    • padding.PKCS7PaddingWriter: Automatically removes padding when reading from a stream.

    Encapsulated Block Mode Functions

    For simpler workflows with io.Reader and io.Writer types, use these high-level functions:

    • padding.P7BlockEnc: Encrypts data from a source reader to a destination writer with PKCS#7 padding.
    • padding.P7BlockDecrypt: Decrypts data from a source reader to a destination writer and removes PKCS#7 padding.
  9. Configure TLCP GCM mode on the client

    master

    By default, clients use the ECC_SM4_CBC_SM3 cipher suite. To use the ECC_SM4_GCM_SM3 suite (which uses SM4 GCM instead of SM4 CBC + SM3 HMAC), you must manually configure the CipherSuites in your gmtls.Config.

    Place the desired GCM suite at the beginning of the CipherSuites array to ensure it is prioritized.

    Supported TLCP suites include:

    • gmtls.GMTLS_ECC_SM4_GCM_SM3
    • gmtls.GMTLS_ECC_SM4_CBC_SM3
    • gmtls.ECDHE_SM4_CBC_SM3
    • gmtls.ECDHE_SM4_GCM_SM3
    config := &gmtls.Config{
    	GMSupport:    &gmtls.GMSupport{},
    	RootCAs:      certPool,
    	Certificates: []gmtls.Certificate{cert},
    	// Set GCM mode suites at the front of the array
    	CipherSuites: []uint16{gmtls.GMTLS_ECC_SM4_GCM_SM3, gmtls.GMTLS_ECC_SM4_CBC_SM3},
    }
    
    conn, err := gmtls.Dial("tcp", "localhost:50052", config)
  10. Encrypt a stream using SM4 CBC with PKCS#7 padding

    master

    To encrypt a stream (implementing io.Reader and io.Writer) using SM4 in CBC mode with PKCS#7 padding, use padding.P7BlockEnc. This function takes a block cipher mode encrypter, a source reader, and a destination writer.

    func main() {
        src := bytes.Repeat([]byte{7}, 16)
        srcIn := bytes.NewBuffer(src)
        encOut := bytes.NewBuffer(make([]byte, 0, 1024))
    
        key := make([]byte, 16)
        iv := make([]byte, 16)
        _, _ = rand.Read(key)
        _, _ = rand.Read(iv)
        fmt.Printf("key: %02X\n", key)
        fmt.Printf("iv : %02X\n", iv)
        block, err := sm4.NewCipher(key)
        if err != nil {
            panic(err)
        }
        encrypter := cipher.NewCBCEncrypter(block, iv)
        // P7填充的CBC加密
        err = padding.P7BlockEnc(encrypter, srcIn, encOut)
        if err != nil {
            panic(err)
        }
        fmt.Printf("原文: %02X\n", src)
        fmt.Printf("加密: %02X\n", encOut.Bytes())
    }