首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【加密算法】简单区分HS、RSA、ES 和 ED,与对应go实现案例

  • 25-02-20 16:00
  • 3310
  • 5345
blog.csdn.net

HS、RSA、ES、ED 四种签名算法:

一、算法对比

属性HSRSAESED
加密类型对称加密非对称加密非对称加密非对称加密
密钥长度任意长度私钥: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 secret

import (
	"encoding/hex"
	"math/rand"
	"time"
)

// HsGenerator HS HS256、HS384、HS512 属于对称加密算法。
// 加密和验证使用相同的密钥。
type HsGenerator struct {
	Length int
}

// Generate 生成一个指定长度随机密钥,将其编码为16进制字符串返回
// 生成过程,直接生成密钥
func (hs *HsGenerator) Generate() (*OutSecret, error) {
	out := &OutSecret{}
	length := 32
	if hs.Length > 0 {
		length = hs.Length
	}
	//rand.Seed(time.Now().UnixNano())
	rand.New(rand.NewSource(time.Now().UnixNano()))
	b := make([]byte, length)
	rand.Read(b)
	out.Secret = hex.EncodeToString(b)[:length]
	return out, nil
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

rsa.go

package secret

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"log"
	"os"
)

type RsGenerator struct {
}

// Generate 生成RSA密钥对
// 步骤:
// 生成RSA私钥和公钥。
// 将私钥和公钥转换为X509格式。
// 将私钥和公钥封装为PEM格式并保存到指定路径。
// 返回包含私钥和公钥文件路径的对象。
func (rs *RsGenerator) Generate() (*OutSecret, error) {
	out := &OutSecret{}
	var err error
	// 生成密钥对
	privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
	// rsa.GenerateKey 用于生成指定位数rsa密钥对 rand.Reader提供加密安全随机数,1024位数
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}

	// x509格式封装
	// x509是一种公私钥证书标准格式,定义公钥证书结构
	// 用x509封装,保证一致性
	x509PrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	// ,privateKey.PublicKey 是一个 rsa.PublicKey 类型的值(不是指针),
	// 因此你需要使用 & 来获取它的地址,以便将其传递给 x509.MarshalPKIXPublicKey 函数。
	// 这里接收的是 &privateKey.PublicKey,表示获取 privateKey.PublicKey 的地址。
	x509PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}

	// 表示 PEM 编码的数据块。block用于保存加密密钥、证书等二进制数据。
	privateBlock := &pem.Block{
		Type:  "PRIVATE KEY",  // 数据块类型,例如"PRIVATE KEY" 或 "PUBLIC KEY"
		Bytes: x509PrivateKey, // 用x509封装的,实际的二进制数据
	}
	// 生成对应文件
	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) // pem.Encode将block数据块写入到io.Writer接口,这里就是文件

	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 = privateKeyFile
	out.PublicKeyFile = publicKeyFile

	return out, nil

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

ed.go

package secret

import (
	"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
	}

	// x509格式封装
	x509PrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey) // ed25519的这里privateKey不是一个指针
	if err != nil {
		log.Println(err)
		return nil, err
	}
	x509PublicKey, err := x509.MarshalPKIXPublicKey(publicKey)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	// 设置pem编码的数据块
	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) // pem编码

	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 = privateKeyFile
	out.PublicKeyFile = publicKeyFile

	return out, nil
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

es.go

package secret

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"encoding/pem"
	"log"
	"os"
)

/*
为什么需要分类
在 ES 算法中,不同的签名方法(如 ES256、ES384、ES512)
对应不同的椭圆曲线和哈希函数。具体来说:
ES256 使用 P-256 曲线和 SHA-256 哈希函数。
ES384 使用 P-384 曲线和 SHA-384 哈希函数。
ES512 使用 P-521 曲线和 SHA-512 哈希函数。
这些不同的曲线和哈希函数提供了不同级别的安全性。
通过定义常量和类型 ESSigningMethodS,可以方便地管理和切换不同的签名方法,确保代码的灵活性和可扩展性
*/
const (
	ES256 ESSigningMethodS = "ES256"
	ES384 ESSigningMethodS = "ES384"
	ES512 ESSigningMethodS = "ES512"
)

type ESSigningMethodS string

type 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
	}

	// x509格式封装
	x509PrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey) // privateKey是一个指针
	if err != nil {
		log.Println(err)
		return nil, err
	}
	// ,privateKey.PublicKey 是一个 rsa.PublicKey 类型的值(不是指针),
	// 因此你需要使用 & 来获取它的地址,以便将其传递给 x509.MarshalPKIXPublicKey 函数。
	// 这里接收的是 &privateKey.PublicKey,表示获取 privateKey.PublicKey 的地址。
	x509PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	// 设置pem编码的数据块
	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) // pem编码

	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 = privateKeyFile
	out.PublicKeyFile = publicKeyFile

	return out, nil
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

https://github.com/0voice

注:本文转载自blog.csdn.net的{⌐■_■}的文章"https://blog.csdn.net/m0_74282926/article/details/145345044"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

132
搜索
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top