国密

特点 对称加密 非对称加密
密钥 一个密钥 公钥和私钥一对
速度 更快 较慢
安全性 密钥需要安全传输 密钥可以公开,安全性高
典型应用 大数据加密、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)

} 
gen_keys.go
// 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端口
}
client.go
// 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端口
}
server.go

 

posted on 2025-06-13 18:36  csuyangpeng  阅读(35)  评论(0)    收藏  举报

导航

//替换成自己路径的js文件