Golang RSA生成密钥、加密、解密、签名与验签的实现

 更新时间:2023年11月09日 09:32:45   作者:恋喵大鲤鱼  
RSA 是最常用的非对称加密算法,本文主要介绍了Golang RSA生成密钥、加密、解密、签名与验签的实现,具有一定的参考价值,感兴趣的可以了解一下

脚本之家 / 编程助手:解决程序员“几乎”所有问题!
脚本之家官方知识库 → 点击立即使用

1.RSA

RSA 是最常用的非对称加密算法,由 Ron Rivest、Adi Shamir、Leonard Adleman 于1977 年在麻省理工学院工作时提出,RSA 是三者姓氏首字母的拼接。

它的基本原理涉及到数学中的大整数因数分解问题,即将一个大的合数(通常是一个极大数字)分解为其素数因子。RSA 算法的安全性基于这个问题的难解性,目前还没有高效的方法可以在合理的时间内分解大整数。

RSA 支持变长密钥非对称加密,需要加密的文件块的长度也是可变的。

2.Golang 实现 RSA

Golang 标准库在 crypto/rsa 包实现了 RSA。

下面将利用 Golang 标准库相演示 RSA 生成密钥、加密、解密、签名与验签等操作。

生成密钥

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
// GenRsaKey generates an PKCS#1 RSA keypair of the given bit size in PEM format.
func GenRsaKey(bits int) (prvkey, pubkey []byte, err error) {
    // Generates private key.
    privateKey, err := rsa.GenerateKey(rand.Reader, bits)
    if err != nil {
        return
    }
    derStream := x509.MarshalPKCS1PrivateKey(privateKey)
    block := &pem.Block{
        Type"RSA PRIVATE KEY",
        Bytes: derStream,
    }
    prvkey = pem.EncodeToMemory(block)
 
    // Generates public key from private key.
    publicKey := &privateKey.PublicKey
    derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
    if err != nil {
        return
    }
    block = &pem.Block{
        Type"RSA PUBLIC KEY",
        Bytes: derPkix,
    }
    pubkey = pem.EncodeToMemory(block)
    return
}

加密

RSA 是一个非对称加密算法,虽然私钥也可以用于加密数据,但因为公钥是对外的,所以加密数据的意义不大,因为知道公钥的所有人都能解密。

所以常见的做法是是用公钥加密数据,私钥解密数据。而私钥则用户签名,公钥用于验签。

1
2
3
4
5
6
7
8
9
10
11
12
// RsaEncrypt encrypts data using rsa public key.
func RsaEncrypt(pubkey, data []byte) ([]byte, error) {
    block, _ := pem.Decode(pubkey)
    if block == nil {
        return nil, errors.New("decode public key error")
    }
    pub, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    return rsa.EncryptPKCS1v15(rand.Reader, pub.(*rsa.PublicKey), data)
}

解密

1
2
3
4
5
6
7
8
9
10
11
12
// RsaDecrypt decrypts data using rsa private key.
func RsaDecrypt(prvkey, cipher []byte) ([]byte, error) {
    block, _ := pem.Decode(prvkey)
    if block == nil {
        return nil, errors.New("decode private key error")
    }
    prv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    return rsa.DecryptPKCS1v15(rand.Reader, prv, cipher)
}

签名

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
// RsaSign signs using private key in PEM format.
func RsaSign(prvkey []byte, hash crypto.Hash, data []byte) ([]byte, error) {
    block, _ := pem.Decode(prvkey)
    if block == nil {
        return nil, errors.New("decode private key error")
    }
    privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }
 
    // MD5 and SHA1 are not supported as they are not secure.
    var hashed []byte
    switch hash {
    case crypto.SHA224:
        h := sha256.Sum224(data)
        hashed = h[:]
    case crypto.SHA256:
        h := sha256.Sum256(data)
        hashed = h[:]
    case crypto.SHA384:
        h := sha512.Sum384(data)
        hashed = h[:]
    case crypto.SHA512:
        h := sha512.Sum512(data)
        hashed = h[:]
    }
    return rsa.SignPKCS1v15(rand.Reader, privateKey, hash, hashed)
}

验签

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
// RsaVerifySign verifies signature using public key in PEM format.
// A valid signature is indicated by returning a nil error.
func RsaVerifySign(pubkey []byte, hash crypto.Hash, data, sig []byte) error {
    block, _ := pem.Decode(pubkey)
    if block == nil {
        return errors.New("decode public key error")
    }
    pub, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return err
    }
 
    // SHA1 and MD5 are not supported as they are not secure.
    var hashed []byte
    switch hash {
    case crypto.SHA224:
        h := sha256.Sum224(data)
        hashed = h[:]
    case crypto.SHA256:
        h := sha256.Sum256(data)
        hashed = h[:]
    case crypto.SHA384:
        h := sha512.Sum384(data)
        hashed = h[:]
    case crypto.SHA512:
        h := sha512.Sum512(data)
        hashed = h[:]
    }
    return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), hash, hashed, sig)
}

3.dablelv/cyan

以上函数已放置 Golang 实用函数库 dablelv/cyan,欢迎大家 import 使用。

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
package main
 
import (
    stdcrypto "crypto"
    "fmt"
 
    "github.com/dablelv/cyan/crypto"
)
 
func main() {
    prvkey, pubkey, err := crypto.GenRsaKey(2048)
    if err != nil {
        panic(err)
    }
 
    data := []byte("foo")
 
    // Encrypt data.
    cipher, err := crypto.RsaEncrypt(pubkey, data)
    if err != nil {
        panic(err)
    }
    if len(cipher) != 2048/8 {
        panic("cipher len not equal to key length")
    }
 
    // Decrypt data.
    plain, err := crypto.RsaDecrypt(prvkey, cipher)
    if err != nil {
        panic(err)
    }
    if string(data) == string(plain) {
        fmt.Printf("rsa encrypt and decrypt succeeded, data:%v plain:%v\n", string(data), string(plain))
    }
 
    // Using SHA256 to hash msg and then use rsa private key to sign.
    sig, err := crypto.RsaSign(prvkey, stdcrypto.SHA256, data)
    if err != nil {
        panic(err)
    }
    if len(sig) != 2048/8 {
        panic("signature len not equal to key length")
    }
 
    // Using public key to verify signature.
    err = crypto.RsaVerifySign(pubkey, stdcrypto.SHA256, data, sig)
    if err != nil {
        panic(err)
    }
    fmt.Println("verify signature succeeded")
}

运行输出:

1
2
rsa encrypt and decrypt succeeded, data:foo plain:foo
verify signature succeeded

参考文献

rsa.com

一文读懂 HTTPS 背后的加密知识

到此这篇关于Golang RSA生成密钥、加密、解密、签名与验签的实现的文章就介绍到这了,更多相关Golang RSA加密解密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

蓄力AI

微信公众号搜索 “ 脚本之家 ” ,选择关注

程序猿的那些事、送书等活动等着你

原文链接:https://dablelv.blog.csdn.net/article/details/132709147

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!

相关文章

  • Go语言sync.Cond使用方法详解

    Go语言sync.Cond使用方法详解

    Go语言标准库中还包含条件变量 sync.Cond,它可以让一组 Goroutine 都在满足特定条件时被唤醒,每一个sync.Cond结构体在初始化时都需要传入一个互斥锁,接下来我们将通过文中例子了解它的使用方法,感兴趣的同学跟着小编一起来看看吧
    2023-07-07
  • 使用golang开发一个curl命令行工具

    使用golang开发一个curl命令行工具

    这篇文章主要为大家详细介绍了如何使用golang开发一个简单的curl命令行工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-11-11
  • GO 使用Webhook 实现github 自动化部署的方法

    GO 使用Webhook 实现github 自动化部署的方法

    这篇文章主要介绍了GO 使用Webhook 实现github 自动化部署的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • Go设计模式之备忘录模式讲解和代码示例

    Go设计模式之备忘录模式讲解和代码示例

    备忘录是一种行为设计模式, 允许生成对象状态的快照并在以后将其还原,本文就通过代码示例给大家讲讲Go备忘录模式,感兴趣的小伙伴跟着小编一起来看看吧
    2023-08-08
  • Golang中的闭包(Closures)详解

    Golang中的闭包(Closures)详解

    在 Golang 中,闭包是一个引用了作用域之外的变量的函数,Golang 中的匿名函数也被称为闭包,闭包可以被认为是一种特殊类型的匿名函数,所以本文就给大家详细的介绍一下Golang的闭包到底是什么,感兴趣的小伙伴跟着小编一起来看看吧
    2023-07-07
  • go doudou开发gRPC服务快速上手实现详解

    go doudou开发gRPC服务快速上手实现详解

    这篇文章主要为大家介绍了go doudou开发gRPC服务快速上手实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • golang关闭chan通道的方法示例

    golang关闭chan通道的方法示例

    在go语言中,通道(channel)是一个非常重要的概念,通道提供了一种在不同 goroutine 之间安全地传递数据的方式,在本文中,我们将讨论如何关闭通道以及在关闭通道时需要考虑的事项,需要的朋友可以参考下
    2024-02-02
  • grpcurl通过命令行访问gRPC服务

    grpcurl通过命令行访问gRPC服务

    这篇文章主要为大家介绍了grpcurl通过命令行访问gRPC服务示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Go语言常用的打log方式详解

    Go语言常用的打log方式详解

    Golang的log包短小精悍,可以非常轻松的实现日志打印转存功能,下面这篇文章主要给大家介绍了关于Go语言常用的打log方式的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-10-10
  • golang并发编程使用Select语句的实现

    golang并发编程使用Select语句的实现

    Go语言中的select语句是并发编程中的重要工具,允许Goroutine等待多个通道操作,它阻塞直至任一case可执行,可用于接收数据、实现超时机制和非阻塞通道操作,感兴趣的可以了解一下
    2024-10-10

最新评论