国密
特点 | 对称加密 | 非对称加密 |
密钥 | 一个密钥 | 公钥和私钥一对 |
速度 | 更快 | 较慢 |
安全性 | 密钥需要安全传输 | 密钥可以公开,安全性高 |
典型应用 | 大数据加密、VPN | 数字签名、密钥交换 |
https://openstd.samr.gov.cn/bzgk/gb/index 可以下载相关规范
暂时无法在飞书文档外展示此内容 国密算法(又称商用密码算法)是中国国家密码管理局制定的一系列密码算法标准,包括对称加密(SM1、SM4)、非对称加密(SM2)、哈希算法(SM3)和流密码(ZUC)等。下面将详细介绍其原理、实践应用以及最佳实践。 国密算法原理 1. SM4(对称加密) - 原理:分组密码算法,分组长度128位,密钥长度128位。采用32轮非线性迭代结构(Feistel结构),使用非线性变换S盒和线性变换L层,具有较高的安全性。 - 工作模式:支持ECB、CBC、CTR、GCM等模式,常用CBC模式。 2. SM2(非对称加密) - 原理:基于椭圆曲线密码学(ECC),使用推荐曲线参数(256位素数域)。包括数字签名、密钥交换和公钥加密。 - 特点:同等安全强度下,密钥长度远小于RSA(SM2的256位相当于RSA-3072位),运算速度快。 3. SM3(哈希算法) - 原理:类似SHA-256,输出长度256位。采用Merkle-Damgard结构,64轮迭代压缩,适合数字签名和数据完整性验证。 4. SM9(标识密码算法) - 原理:基于标识的密码系统(IBC),用户标识(如邮箱)作为公钥,无需数字证书。

// gen_keys.go package main import ( "crypto/elliptic" "crypto/rand" "fmt" "log" "os" "github.com/tjfoc/gmsm/sm2" "github.com/tjfoc/gmsm/x509" ) func main() { // 生成第一套密钥对(服务端) serverPrivKey, err := sm2.GenerateKey(rand.Reader) if err != nil { panic(err) } saveKeyPair("omc", serverPrivKey) // 生成第二套密钥对(客户端) clientPrivKey, err := sm2.GenerateKey(rand.Reader) if err != nil { panic(err) } saveKeyPair("oam", clientPrivKey) } func saveKeyPair(name string, privKey *sm2.PrivateKey) { // 保存私钥 fmt.Printf("%+v Private Key: %x\n", name, privKey.D.Bytes()) fmt.Printf("%+v Public Key: %x\n", name, elliptic.Marshal(sm2.P256Sm2(), privKey.PublicKey.X, privKey.PublicKey.Y)) // 2. 明文数据 plaintext := []byte("Hello, SM2 Encryption!") // 3. 使用公钥加密 ciphertext, err := sm2.Encrypt(&privKey.PublicKey, plaintext, rand.Reader, sm2.C1C3C2) if err != nil { log.Fatalf("SM2加密失败: %v", err) } fmt.Printf("Ciphertext(hex): %x\n", ciphertext) // 4. 使用私钥解密 decrypted, err := sm2.Decrypt(privKey, ciphertext, sm2.C1C3C2) if err != nil { log.Fatalf("SM2解密失败: %v", err) } fmt.Printf("Decrypted: %s\n", decrypted) privPem, err := x509.WritePrivateKeyToPem(privKey, nil) if err != nil { panic(err) } err = os.WriteFile("sm2_sign_"+name+"_priv.pem", privPem, 0600) if err != nil { panic(err) } // 保存公钥 pubPem, err := x509.WritePublicKeyToPem(&privKey.PublicKey) if err != nil { panic(err) } err = os.WriteFile("sm2_sign_"+name+"_pub.pem", pubPem, 0644) if err != nil { panic(err) } fmt.Printf("SM2密钥对已生成: sm2_sign_%s_priv.pem, sm2_sign_%s_pub.pem\n\n", name, name) }

// serviceA/main.go package main import ( "bytes" "crypto/elliptic" "crypto/rand" "encoding/base64" "encoding/json" "fmt" "io" "log" "net/http" "os" "path/filepath" "runtime" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "github.com/tjfoc/gmsm/sm2" "github.com/tjfoc/gmsm/x509" ) type Msg struct { Data []byte `json:"Data"` } func init() { // 配置Logrus格式 logrus.SetFormatter(&logrus.TextFormatter{ TimestampFormat: "2006-01-02 15:04:05", // 时间格式 FullTimestamp: true, CallerPrettyfier: func(f *runtime.Frame) (string, string) { // 去掉路径,只保留文件名和行号 filename := filepath.Base(f.File) return "", fmt.Sprintf("%s:%d", filename, f.Line) }, }) logrus.SetReportCaller(true) // 必须启用调用者信息 } func main() { pubKeyBytes, err := os.ReadFile("../config/server.pem") if err != nil { panic("failed to read server.pem: " + err.Error()) } pubPem, err := x509.ReadPublicKeyFromPem(pubKeyBytes) if err != nil { panic("failed to parse public key: " + err.Error()) } logrus.Infof("Public Key: %x", elliptic.Marshal(sm2.P256Sm2(), pubPem.X, pubPem.Y)) keyData, err := os.ReadFile("../config/client.key") if err != nil { log.Fatal("加载服务端私钥失败:", err) } privPem, err := x509.ReadPrivateKeyFromPem(keyData, nil) if err != nil { log.Fatal("加载服务端证书失败:", err) } logrus.Infof("Private Key: %x", privPem.D.Bytes()) r := gin.Default() r.POST("/decrypt", func(c *gin.Context) { var req Msg if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, gin.H{"error": "Invalid request"}) return } logrus.Infof("req: %+v", req) plaintext, err := sm2.Decrypt(privPem, req.Data, sm2.C1C3C2) if err != nil { c.JSON(500, gin.H{"error": "Decryption failed"}) return } logrus.Infof("Decrypted: %s", plaintext) c.JSON(200, gin.H{"decrypted": string(plaintext)}) }) r.POST("/encrypt", func(c *gin.Context) { var req struct{ Data string } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, gin.H{"error": "Invalid request"}) return } logrus.Infof("Received request: %+v", req) ciphertext, err := sm2.Encrypt(pubPem, []byte(req.Data), rand.Reader, sm2.C1C3C2) if err != nil { c.JSON(500, gin.H{"error": "Encryption failed"}) return } logrus.Infof("Ciphertext(hex): %x", ciphertext) resp, err := http.Post( "http://localhost:8081/decrypt", "application/json", bytes.NewReader(ciphertext), ) if err != nil { logrus.Errorf("Failed to call ServiceB: %v", err) c.JSON(500, gin.H{"error": err.Error()}) return } defer resp.Body.Close() var result struct{ Decrypted string } json.NewDecoder(resp.Body).Decode(&result) c.JSON(200, gin.H{"status": "OK", "decrypted": result.Decrypted}) }) r.POST("/challenge", func(c *gin.Context) { // ciphertext, err := sm2.Encrypt(pubPem, []byte("Hello, SM2 Encryption!"), rand.Reader, sm2.C1C3C2) // if err != nil { // c.JSON(500, gin.H{"error": "Encryption failed"}) // return // } // logrus.Infof("Ciphertext(hex): %x", ciphertext) resp, err := http.Post( "http://localhost:8081/challenge", "application/json", nil, ) if err != nil { c.JSON(500, gin.H{"error": "Failed to call ServiceB"}) return } defer resp.Body.Close() var result struct{ Signature string } body, err := io.ReadAll(resp.Body) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "读取数据失败"}) return } if err := json.Unmarshal(body, &result); err != nil { c.JSON(500, gin.H{"error": "Failed to parse response"}) return } logrus.Infof("Signature(base64): %s", result.Signature) sig, err := base64.StdEncoding.DecodeString(result.Signature) if err != nil { c.JSON(500, gin.H{"error": "Base64 decode failed"}) return } logrus.Infof("sig: %x", sig) // 3. SM2 解密 ok := pubPem.Verify([]byte("Hello, SM2 1Encryption!"), sig) logrus.Infof("Signature verification result: %v", ok) c.JSON(200, gin.H{ "challenge": "Hello, SM2 Encryption!", "public_key(Hex)": fmt.Sprintf("%x", elliptic.Marshal(sm2.P256Sm2(), pubPem.X, pubPem.Y)), "public_key(Base64)": base64.StdEncoding.EncodeToString(elliptic.Marshal(sm2.P256Sm2(), pubPem.X, pubPem.Y)), "signature(Hex)": fmt.Sprintf("%x", sig), "signature(Base64)": result.Signature, "verify": ok, }) }) r.Run(":8080") // 服务A端口 }

// server.go package main import ( "bytes" "crypto/rand" "encoding/base64" "encoding/json" "fmt" "io" "log" "net/http" "os" "path/filepath" "runtime" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "github.com/tjfoc/gmsm/sm2" "github.com/tjfoc/gmsm/x509" ) type Msg struct { Data []byte `json:"Data"` } func init() { // 配置Logrus格式 logrus.SetFormatter(&logrus.TextFormatter{ TimestampFormat: "2006-01-02 15:04:05", // 时间格式 FullTimestamp: true, CallerPrettyfier: func(f *runtime.Frame) (string, string) { // 去掉路径,只保留文件名和行号 filename := filepath.Base(f.File) return "", fmt.Sprintf("%s:%d", filename, f.Line) }, }) logrus.SetReportCaller(true) // 必须启用调用者信息 } func main() { pubKeyBytes, err := os.ReadFile("../config/client.pem") if err != nil { panic("failed to read server.pem: " + err.Error()) } pubPem, err := x509.ReadPublicKeyFromPem(pubKeyBytes) if err != nil { panic("failed to parse public key: " + err.Error()) } // 加载server.key keyData, err := os.ReadFile("../config/server.key") if err != nil { log.Fatal("加载服务端私钥失败:", err) } privPem, err := x509.ReadPrivateKeyFromPem(keyData, nil) if err != nil { log.Fatal("加载服务端证书失败:", err) } logrus.Infof("Private Key: %x", privPem.D.Bytes()) r := gin.Default() // 解密接口 r.POST("/decrypt", func(c *gin.Context) { // 1. 获取密文 // var req Msg // if err := c.ShouldBindJSON(&req); err != nil { // c.JSON(400, gin.H{"error": "Invalid request"}) // return // } req, err := io.ReadAll(c.Request.Body) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "读取数据失败"}) return } logrus.Infof("req: %x", req) // 2. SM2 解密 plaintext, err := sm2.Decrypt(privPem, req, sm2.C1C3C2) if err != nil { c.JSON(500, gin.H{"error": "Decryption failed"}) return } logrus.Infof("plaintext: %s", plaintext) // 3. 返回明文 c.JSON(200, gin.H{"decrypted": string(plaintext)}) }) // 加密接口 r.POST("/encrypt", func(c *gin.Context) { // 1. 获取明文 var req struct{ Data string } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, gin.H{"error": "Invalid request"}) return } logrus.Infof("req: %+v", req) // 2. SM2 加密 ciphertext, err := sm2.Encrypt(pubPem, []byte(req.Data), rand.Reader, sm2.C1C3C2) if err != nil { c.JSON(500, gin.H{"error": "Encryption failed"}) return } logrus.Infof("Ciphertext(hex): %x", ciphertext) // 3. 发送密文到服务B var msg Msg msg.Data = ciphertext // 将字节切片转换为十六进制字符串 fmt.Printf("msg: %+v\n", msg) ciphertext, err = json.Marshal(msg) if err != nil { c.JSON(500, gin.H{"error": "Failed to marshal ciphertext"}) return } resp, err := http.Post( "http://localhost:8080/decrypt", "application/json", bytes.NewBuffer(ciphertext), ) if err != nil { c.JSON(500, gin.H{"error": "Failed to call ServiceB"}) return } defer resp.Body.Close() logrus.Infof("resp: %+v", resp) // 4. 返回结果 var result struct{ Decrypted string } json.NewDecoder(resp.Body).Decode(&result) c.JSON(200, gin.H{"status": "OK", "decrypted": result.Decrypted}) }) r.POST("/challenge", func(c *gin.Context) { // 2. SM2 解密 sig, err := privPem.Sign(rand.Reader, []byte("Hello, SM2 Encryption!"), nil) if err != nil { logrus.Errorf("Sign failed: %v", err) c.JSON(500, gin.H{"error": "Sign failed"}) return } base64Sig := base64.StdEncoding.EncodeToString(sig) logrus.Infof("base64Sig: %s", base64Sig) // 3. 返回明文 c.JSON(200, gin.H{"signature": base64Sig}) }) r.Run(":8081") // 服务B端口 }
posted on 2025-06-13 18:36 csuyangpeng 阅读(35) 评论(0) 收藏 举报