gmkit

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: Apache-2.0

README

gmkit

一套国密(SM2/SM3/SM4)Go SDK:在「密钥容器抽象」与「国密算法实现」两层间提供统一接口,支持KMS,HMS扩炸。

项目概述

gmkit 把两层接口拼成一个一致的开发面:

  • 密钥容器抽象container/):KeyContainer 接口与三种可插拔后端(local_kvkmshsm),让业务代码不再耦合"密钥实际存在哪里"。
  • 统一算法接口crypto/):CryptoProvider,当前实现 GMProvider 基于 tjfoc/gmsm 提供 SM2 签验、SM3 哈希、SM4-GCM 认证加密。

启动时一次性从容器解密并加载默认密钥到内存,运行期任何签名/加解密调用都不再触达文件 I/O 与口令派生开销。

仓库内附一组 CLI 与示例:

  • cmd/seed-local-kv:一键生成本地国密密钥集,写入加密 KV 文件。
  • cmd/dump-local-kv:查看 KV 文件中的条目,默认不打印密钥体。
  • example/local-kv-gm:端到端示例,串起"容器 → Provider → SM3/SM2/SM4-GCM"。

设计理念是接口先行:新增 KMS / HSM 容器后端或 legacy / hsm 算法栈,业务调用点无需改动。


Installation / 安装

# 业务侧引入库
go get github.com/det101/gmkit@latest

# CLI 工具(可独立部署,无需源码)
go install github.com/det101/gmkit/cmd/seed-local-kv@latest
go install github.com/det101/gmkit/cmd/dump-local-kv@latest

业务代码 import:

import (
    "github.com/det101/gmkit/container"
    "github.com/det101/gmkit/crypto"
)

仅对外发布 container/crypto/cmd/... 三类入口;container/internal/secretkv/ 为内部实现,外部不可直接引用。


目录结构

  • container/
    • container.go: KeyContainer 接口(读写密钥),以及 KeyLister / KeyDeleter 能力接口
    • types.go: 容器类型与密钥模型(含 KeyMeta
    • config.go: 容器配置与校验
    • local_kv_container.go: 本地加密 KV 容器实现(SM4-GCM + Argon2id)
    • internal/secretkv/: 文件级加密读写实现,对外不可见
  • crypto/
    • provider.go: CryptoProvider 接口(哈希、签名、验签、加解密)
    • types.go: 算法模式与 TLS 入参模型
    • config.go: 算法配置与运行时组合配置
    • seed.go: GenerateLocalSeed 生成本地国密密钥素材(SM2/SM4/HMAC)
    • gm_provider.go: 基于 tjfoc/gmsm 的国密实现(SM2/SM3/SM4-GCM)
    • factory.go: NewProvider(ctx, cfg, container) 工厂入口
  • cmd/
    • seed-local-kv/: 命令行工具,将一份新生成的国密密钥写入加密 KV 文件
    • dump-local-kv/: 命令行工具,读取/列出加密 KV 文件中的条目(默认不输出密钥体)
  • example/
    • local-kv-gm/: 端到端示例,演示从 local_kv 装载到 GMProvider 完成 SM3/SM2/SM4-GCM

设计要点

  • 业务侧只依赖接口,不直接依赖具体容器或算法实现。
  • 容器类型支持:
    • local_kv:单文件 SM4-GCM 加密的本地键值存储
    • kms
    • hsm(预留)
  • 算法模式支持:
    • legacy
    • gm
    • hsm(预留)
  • KeyEntry 同时支持可导出与不可导出密钥:
    • 可导出:使用 KeyBase64
    • 不可导出(KMS/HSM):使用 KeyRef + Exportable=false

配置示例(接口层)

runtimeCfg := crypto.RuntimeConfig{
	Container: container.ContainerConfig{
		Type: container.ContainerTypeLocalKV,
		LocalKV: container.LocalKVConfig{
			Path:       "/var/lib/gmkit/keys.enc",
			Passphrase: os.Getenv("GO_GM_PASSPHRASE"),
		},
	},
	Provider: crypto.CryptoConfig{
		Mode:          crypto.ModeGM,
		AllowFallback: true,
	},
}

if err := runtimeCfg.Container.Validate(); err != nil {
	panic(err)
}
if err := runtimeCfg.Provider.Validate(); err != nil {
	panic(err)
}

生成本地密钥种子

使用 cmd/seed-local-kv 一键生成 SM2 密钥对、SM4 默认主密钥、HMAC 密钥与相关标识,写入加密 KV 文件(替代历史脚本 bin/generate-kms-local-config.sh)。

方式 A:开发期 go run(需要本机有 go)
GO_GM_PASSPHRASE='your-strong-passphrase' \
go run ./cmd/seed-local-kv \
  --out ./local.gmkv \
  --alias local-default
方式 B:预编译二进制部署(目标机无需安装 go)
# 在带 go 的机器编译(可交叉编译)
go build -o ./bin/seed-local-kv ./cmd/seed-local-kv
# 静态二进制(推荐用于无 glibc / Alpine 等场景)
CGO_ENABLED=0 go build -ldflags='-s -w' -o ./bin/seed-local-kv ./cmd/seed-local-kv

# 把 bin/seed-local-kv 与 bin/seed-local-kv.sh 拷到目标机
GO_GM_PASSPHRASE='...' ./bin/seed-local-kv --out /var/lib/gmkit/local.gmkv
# 或继续走 shell 包装:
./bin/seed-local-kv.sh --out /var/lib/gmkit/local.gmkv

项目本身(容器/算法层)只是 Go 库;CI 编译出二进制后,运行时不再需要 go 工具链

写入的别名(按 kms.local.* 命名沿用历史 properties 习惯):

Alias 类型 说明
kms.local.defaultKeyCipher.id string 主密钥 keyId
kms.local.defaultKeyCipher 16 bytes SM4 默认主密钥(raw)
kms.local.defaultAlias string 默认别名
kms.local.defaultSm2PrivateKey bytes SM2 私钥(PKCS#8 DER)
kms.local.defaultSm2PublicKey bytes SM2 公钥(X.509 DER)
kms.local.defaultDataKeyId string DataKey 标识
kms.local.hmacKey 32 bytes HMAC 密钥(raw)

读取本地密钥种子

CLI:cmd/dump-local-kv
# 列出全部别名(默认不打印密钥体,只显示 alias / 字节数 / 更新时间)
GO_GM_PASSPHRASE='your-strong-passphrase' \
go run ./cmd/dump-local-kv --in ./local.gmkv

# 只取一个 alias,且打印 base64 密钥体
GO_GM_PASSPHRASE='...' \
go run ./cmd/dump-local-kv --in ./local.gmkv \
  --alias kms.local.defaultSm2PublicKey --show-key

# JSON 格式(便于脚本/日志采集消费)
GO_GM_PASSPHRASE='...' \
go run ./cmd/dump-local-kv --in ./local.gmkv --format json --show-key

错口令会立刻失败(secretkv: incorrect passphrase),不会打印任何明文。

库集成:在你的服务里读取
package main

import (
	"context"
	"encoding/base64"
	"log"
	"os"

	"github.com/det101/gmkit/container"
	"github.com/det101/gmkit/crypto"
)

func main() {
	c, err := container.NewLocalKVContainer(container.LocalKVConfig{
		Path:       "/var/lib/gmkit/local.gmkv",
		Passphrase: os.Getenv("GO_GM_PASSPHRASE"),
	})
	if err != nil {
		log.Fatalf("open kv: %v", err)
	}

	entry, err := c.Read(context.Background(), container.KeyQuery{
		Alias: crypto.AliasDefaultSm2PrivateKey,
	})
	if err != nil {
		log.Fatalf("read sm2 priv: %v", err)
	}
	privDER, _ := base64.StdEncoding.DecodeString(entry.KeyBase64)
	log.Printf("loaded SM2 private key, %d bytes (PKCS#8 DER)", len(privDER))
}

国密算法实现:crypto.GMProvider

GMProvider 基于 tjfoc/gmsm 实现:构造时一次性把容器中的默认密钥(SM2 私钥/公钥、SM4 主密钥、HMAC 密钥及标识)解密、解析并缓存到内存,之后算法调用不再访问容器。

推荐用法:通过工厂
ctx := context.Background()

c, err := container.NewLocalKVContainer(container.LocalKVConfig{
    Path:       "/var/lib/gmkit/local.gmkv",
    Passphrase: os.Getenv("GO_GM_PASSPHRASE"),
})
if err != nil { log.Fatal(err) }

provider, err := crypto.NewProvider(ctx, crypto.CryptoConfig{Mode: crypto.ModeGM}, c)
if err != nil { log.Fatal(err) }

digest, _ := provider.Hash([]byte("hello"))                 // SM3
sig, _   := provider.Sign([]byte("payload"), nil)          // SM2 默认私钥
ok, _    := provider.Verify([]byte("payload"), sig, nil)   // SM2 默认公钥
ct, _    := provider.Encrypt([]byte("plain"), nil, nil)    // SM4-GCM,nonce 嵌入密文头
pt, _    := provider.Decrypt(ct, nil, nil)
_ = digest; _ = ok; _ = pt
接口语义约定
调用 nil / 空入参的回落 显式入参类型
Hash(data)
Sign(data, priv) 用容器加载的默认 SM2 私钥 *sm2.PrivateKey
Verify(data, sig, pub) 用容器加载的默认 SM2 公钥 *sm2.PublicKey
Encrypt(plain, key, iv) key 空 → 默认 SM4 主密;iv 空 → 随机 12B nonce 并前置到密文 key 必须 16B;iv 必须 12B
Decrypt(ct, key, iv) 同上;iv 空 → 从密文头读 12B 同上

调用 provider.Info() 可拿到非敏感的 KeyID/Alias/DataKeyID,可用于审计日志。

端到端示例

example/local-kv-gm/main.go 把"加载容器 → 构造 GMProvider → SM3/SM2/SM4-GCM"五步串成一个可执行示例:

# 1) 先 seed 一个本地 KV
GO_GM_PASSPHRASE='your-passphrase' go run ./cmd/seed-local-kv --out ./local.gmkv --force

# 2) 跑端到端示例
GO_GM_PASSPHRASE='your-passphrase' go run ./example/local-kv-gm --in ./local.gmkv

预期输出:

[1/5] 加载容器   : ./local.gmkv
[2/5] 初始化 GM  : mode=gm keyId=local-key-... alias=local-default dataKeyId=local-datakey-...
[3/5] SM3 摘要   : 32 bytes
[4/5] SM2 签验   : sign=71 bytes, verify=true
[5/5] SM4-GCM    : ct=41 bytes, decrypted="hello sm4-gcm"

当前状态

  • 接口契约与配置校验已完成。
  • 本地 KV 容器(local_kv)已具备 Read/Write/Delete/List/Refresh 能力。
  • 提供 cmd/seed-local-kv / cmd/dump-local-kv 用于一键初始化与查看本地国密密钥。
  • 国密算法层 crypto.GMProvider 已落地(基于 tjfoc/gmsm),从容器一次性加载密钥到内存。
  • KMS / HSM 容器、legacy/hsm 算法实现仍预留,待具体接入需求时补齐。

Releasing / 发布到 GitHub

首次发布到 github.com/det101/gmkit 的标准流程:

# 1) 初始化并推送主干
git init
git add .
git commit -m "feat: initial release of gmkit (container + GMProvider)"
git branch -M main
git remote add origin git@github.com:det101/gmkit.git
git push -u origin main

# 2) 打 SemVer tag(go get 按 tag 选版本)
git tag -a v0.1.0 -m "v0.1.0: local_kv container + GMProvider (SM2/SM3/SM4-GCM)"
git push origin v0.1.0

之后业务方即可:

go get github.com/det101/gmkit@v0.1.0

后续版本沿用 SemVer:bug 修复走 vX.Y.Z+1,新功能走 vX.Y+1.0不兼容改动走 vX+1.0.0 并把 module path 升到 github.com/det101/gmkit/v2


License

Apache License 2.0 — see LICENSE and NOTICE for third-party attributions.

Directories

Path Synopsis
cmd
dump-local-kv command
Command dump-local-kv inspects a local_kv container file.
Command dump-local-kv inspects a local_kv container file.
seed-local-kv command
Command seed-local-kv generates a fresh GM key set (SM2 keypair, SM4 default cipher, HMAC key, identifiers) and persists it into a local_kv container file (SM4-GCM + Argon2id).
Command seed-local-kv generates a fresh GM key set (SM2 keypair, SM4 default cipher, HMAC key, identifiers) and persists it into a local_kv container file (SM4-GCM + Argon2id).
internal/secretkv
Package secretkv provides an SM4-GCM encrypted key-value file format.
Package secretkv provides an SM4-GCM encrypted key-value file format.
example
local-kv-gm command
Package main demonstrates the end-to-end flow:
Package main demonstrates the end-to-end flow:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL