Overview of gmsm capabilities
mastercrypto interfaces where possible.repository·master·Indexed 24 days ago
https://github.com/tjfoc/gmsmA 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.
crypto interfaces where possible.The SM4 implementation provides symmetric block cipher capabilities, including:
Generate Key operations.Encrypt and Decrypt operations.Cipher.Block interface.x509.EncryptPEMBlock).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:
serverHandshakeStateGM context and the GMSSL handshake.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.
The SM2 implementation provides elliptic curve cryptography capabilities, including:
Generate Key operations.Sign and Verify operations.crypto.Signer interface.The SM3 implementation provides cryptographic hashing capabilities, including:
sm3Sum operation.hash.Hash interface.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:
gmtls/websvr/websvr.gogmtls/websvr/credentials_test.goTo require clients to present a certificate (mutual authentication) using TLCP:
gmtls.NewGMSupport().Certificates.ClientAuth to gmtls.RequireAndVerifyClientCert.ClientCAs to verify client certificates.config := &gmtls.Config{
GMSupport: gmtls.NewGMSupport(),
Certificates: []gmtls.Certificate{sigCert, encCert},
ClientAuth: gmtls.RequireAndVerifyClientCert,
ClientCAs: certPool,
}To perform mutual authentication as a client:
gmtls.NewGMSupport().Certificates.RootCAs.InsecureSkipVerify to false to ensure security.config := &gmtls.Config{
GMSupport: gmtls.NewGMSupport(),
RootCAs: certPool,
Certificates: []gmtls.Certificate{authKeypair},
InsecureSkipVerify: false,
}Install the gmsm library using the following command:
go get -u github.com/tjfoc/gmsmTo implement a server that automatically switches between GMSSL and TLS, follow these steps:
sigCert), SM2 encryption (encCert), and RSA/ECC (rsaKeypair).GetCertificate function that inspects gmtls.ClientHelloInfo.SupportedVersions. If gmtls.VersionGMSSL is present, return the SM2 signature certificate; otherwise, return the RSA/ECC certificate.GetKECertificate function that returns the SM2 encryption certificate.gmtls.GMSupport object and call EnableMixMode().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 HTTPWhen 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.
padding.PKCS7PaddingReader: Automatically adds padding when writing to the end of a stream.padding.PKCS7PaddingWriter: Automatically removes padding when reading from a stream.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.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_SM3gmtls.GMTLS_ECC_SM4_CBC_SM3gmtls.ECDHE_SM4_CBC_SM3gmtls.ECDHE_SM4_GCM_SM3config := &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)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())
}