HS、RSA、ES、ED 四种签名算法:
一、算法对比
属性 | HS | RSA | ES | ED |
---|
加密类型 | 对称加密 | 非对称加密 | 非对称加密 | 非对称加密 |
密钥长度 | 任意长度 | 私钥:2048+ 位 | 私钥:256+ 位 | 私钥:256 位(Ed25519) |
签名效率 | 高 | 较低 | 高 | 高 |
验证效率 | 高 | 较低 | 高 | 高 |
安全性 | 中 | 高 | 高 | 高 |
密钥分离 | 不支持 | 支持 | 支持 | 支持 |
典型场景 | 内部系统通信 | 安全性要求高的场景 | 移动设备和 IoT 场景 | 安全敏感的高效场景 |
二、构建过程
1. HS (HMAC-SHA) 密钥生成流程
步骤 | 操作代码 | 说明 |
---|
1. 定义密钥长度 | key := make([]byte, 32) | 定义对称密钥长度,常用 256 位(32 字节)。 |
2. 生成随机密钥 | _, err := rand.Read(key) | 使用随机生成器填充密钥。 |
3. 保存到文件 | os.WriteFile("hmac.key", key, 0644) | 将密钥以二进制文件形式保存到本地,确保权限控制。 |
2. RSA 密钥生成流程
步骤 | 操作代码 | 说明 |
---|
1. 生成密钥对 | privateKey, err := rsa.GenerateKey(rand.Reader, 2048) | 使用 RSA 生成 2048 位密钥对。 |
2. 转换为 x509 格式 | x509PrivateKey := x509.MarshalPKCS8PrivateKey(privateKey) | 将私钥封装为 PKCS8 格式。 |
| x509PublicKey := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) | 将公钥封装为 PKIX 格式。注意这里传地址 |
3. 封装为 PEM 格式 | privateBlock := &pem.Block{Type: "PRIVATE KEY", Bytes: x509PrivateKey} | 使用 PEM 格式封装私钥。 |
| publicBlock := &pem.Block{Type: "PUBLIC KEY", Bytes: x509PublicKey} | 使用 PEM 格式封装公钥。 |
4. 保存到文件 | os.OpenFile + pem.Encode | 将密钥分别写入 private.pem 和 public.pem 文件。 |
3. ES (Elliptic Curve) 密钥生成流程
步骤 | 操作代码 | 说明 |
---|
1. 定义曲线 | curve := elliptic.P256() | 选择椭圆曲线(如 P256)。 |
2. 生成密钥对 | privateKey, err := ecdsa.GenerateKey(es.getCurve(), rand.Reader) | 生成私钥及公钥。 |
3. 转换为 x509 格式 | x509PrivateKey := x509.MarshalECPrivateKey(privateKey) | 将私钥封装为 x509 格式。 |
4. 封装为 PEM 格式 | privateBlock := &pem.Block{Type: "EC PRIVATE KEY", Bytes: x509PrivateKey} | 使用 PEM 格式封装私钥。 |
| publicBlock := &pem.Block{Type: "PUBLIC KEY", Bytes: x509PublicKey} | 使用 PEM 格式封装公钥。 |
5. 保存到文件 | os.OpenFile + pem.Encode | 将密钥分别写入 ec_private.pem 和 ec_public.pem 文件。 |
4. ED (Ed25519) 密钥生成流程
步骤 | 操作代码 | 说明 |
---|
1. 生成密钥对 | publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) | 使用 Ed25519 算法生成密钥对,密钥长度固定。 |
2. 转换为 PEM 格式 | privateBlock := &pem.Block{Type: "PRIVATE KEY", Bytes: privateKey} | 使用 PEM 格式封装私钥。 |
| publicBlock := &pem.Block{Type: "PUBLIC KEY", Bytes: publicKey} | 使用 PEM 格式封装公钥。 |
3. 保存到文件 | os.OpenFile + pem.Encode | 将密钥分别写入 ed_private.pem 和 ed_public.pem 文件。 |
总结表格
加密方式 | 密钥类型 | 生成流程关键步骤 |
---|
HS | 对称密钥 | 随机生成固定长度的密钥,直接保存到文件。 |
RSA | 公钥 + 私钥 | 生成密钥对 → 转换为 x509 → 封装为 PEM → 写入文件。 |
ES | 公钥 + 私钥 | 选择椭圆曲线 → 生成密钥对 → 转换为 x509 → 封装为 PEM → 写入文件。 |
ED | 公钥 + 私钥 | 直接生成 Ed25519 密钥对 → 封装为 PEM → 写入文件。 |
go案例实现
hs.go
package secretimport ("encoding/hex""math/rand""time"
)
type HsGenerator struct {Length int
}
func (hs *HsGenerator) Generate() (*OutSecret, error) {out := &OutSecret{}length := 32if hs.Length > 0 {length = hs.Length}rand.New(rand.NewSource(time.Now().UnixNano()))b := make([]byte, length)rand.Read(b)out.Secret = hex.EncodeToString(b)[:length]return out, nil
}
rsa.go
package secretimport ("crypto/rand""crypto/rsa""crypto/x509""encoding/pem""log""os"
)type RsGenerator struct {
}
func (rs *RsGenerator) Generate() (*OutSecret, error) {out := &OutSecret{}var err errorprivateKey, err := rsa.GenerateKey(rand.Reader, 1024)if err != nil {log.Fatalln(err)return nil, err}x509PrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey)if err != nil {log.Fatalln(err)return nil, err}x509PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)if err != nil {log.Fatalln(err)return nil, err}privateBlock := &pem.Block{Type: "PRIVATE KEY", Bytes: x509PrivateKey, }privateKeyFile := KEY_PATH + "/rsa/private.pem"privateFile, err := os.OpenFile(privateKeyFile, os.O_CREATE|os.O_WRONLY, 0644)if err != nil {log.Fatalln(err)return nil, err}defer privateFile.Close()pem.Encode(privateFile, privateBlock) publicBlock := &pem.Block{Type: "PUBLIC KEY",Bytes: x509PublicKey,}publicKeyFile := KEY_PATH + "/rsa/public.pem"publicFile, err := os.OpenFile(publicKeyFile, os.O_CREATE|os.O_WRONLY, 0644)if err != nil {log.Fatalln(err)return nil, err}defer publicFile.Close()pem.Encode(publicFile, publicBlock)out.PrivateKeyFile = privateKeyFileout.PublicKeyFile = publicKeyFilereturn out, nil}
ed.go
package secretimport ("crypto/ed25519""crypto/rand""crypto/x509""encoding/pem""log""os"
)type EdGenerator struct {
}func (ed *EdGenerator) Generate() (*OutSecret, error) {out := &OutSecret{}publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)if err != nil {log.Println(err)return nil, err}x509PrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey) if err != nil {log.Println(err)return nil, err}x509PublicKey, err := x509.MarshalPKIXPublicKey(publicKey)if err != nil {log.Println(err)return nil, err}privateBlock := &pem.Block{Type: "PRIVATE_KEY",Bytes: x509PrivateKey,}privateKeyFile := KEY_PATH + "/ed/private.pem"privateFile, err := os.OpenFile(privateKeyFile, os.O_CREATE|os.O_WRONLY, 0644)if err != nil {log.Fatalln(err)return nil, err}defer privateFile.Close()pem.Encode(privateFile, privateBlock) publicBlock := &pem.Block{Type: "PUBLIC KEY",Bytes: x509PublicKey,}publicKeyFile := KEY_PATH + "/ed/public.pem"publicFile, err := os.OpenFile(publicKeyFile, os.O_CREATE|os.O_WRONLY, 0644)if err != nil {log.Fatalln(err)return nil, err}defer publicFile.Close()pem.Encode(publicFile, publicBlock)out.PrivateKeyFile = privateKeyFileout.PublicKeyFile = publicKeyFilereturn out, nil
}
es.go
package secretimport ("crypto/ecdsa""crypto/elliptic""crypto/rand""crypto/x509""encoding/pem""log""os"
)
const (ES256 ESSigningMethodS = "ES256"ES384 ESSigningMethodS = "ES384"ES512 ESSigningMethodS = "ES512"
)type ESSigningMethodS stringtype EsGenerator struct {SigningMethod ESSigningMethodS
}func (es *EsGenerator) getCurve() elliptic.Curve {switch es.SigningMethod {case ES256:return elliptic.P256()case ES384:return elliptic.P384()case ES512:return elliptic.P521()default:return elliptic.P256()}
}func (es *EsGenerator) Generate() (*OutSecret, error) {out := &OutSecret{}privateKey, err := ecdsa.GenerateKey(es.getCurve(), rand.Reader)if err != nil {log.Println(err)return nil, err}x509PrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey) if err != nil {log.Println(err)return nil, err}x509PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)if err != nil {log.Println(err)return nil, err}privateBlock := &pem.Block{Type: "PRIVATE_KEY",Bytes: x509PrivateKey,}privateKeyFile := KEY_PATH + "/es/private.pem"privateFile, err := os.OpenFile(privateKeyFile, os.O_CREATE|os.O_WRONLY, 0644)if err != nil {log.Fatalln(err)return nil, err}defer privateFile.Close()pem.Encode(privateFile, privateBlock) publicBlock := &pem.Block{Type: "PUBLIC KEY",Bytes: x509PublicKey,}publicKeyFile := KEY_PATH + "/es/public.pem"publicFile, err := os.OpenFile(publicKeyFile, os.O_CREATE|os.O_WRONLY, 0644)if err != nil {log.Fatalln(err)return nil, err}defer publicFile.Close()pem.Encode(publicFile, publicBlock)out.PrivateKeyFile = privateKeyFileout.PublicKeyFile = publicKeyFilereturn out, nil
}
https://github.com/0voice