Golang RSA库使用问题排查与解决

Golang RSA库使用问题排查与解决 大家好, 我在使用RSA库时遇到了一个非常奇怪的问题。 我用Go语言编写了一个区块链程序,有多个相互连接的本地主机节点。具体流程是:localhost1发送数据,localhost2加密数据,然后当localhost3请求数据时,localhost2需要将数据解密返回。

我使用了标准的解密函数:

rng:=rand.Reader
private:=BytesToPrivateKey(privateKey)
infoSign, err:=rsa.DecryptPKCS1v15(rng,private,[]byte(hash))

程序执行到最后一步时就会"卡死",甚至不会去检查错误值是否为nil。我多次运行这个过程,有时候能正常工作,有时候看起来像是陷入了无限循环,影响了localhost3和localhost2的运行。

我知道这个描述可能比较混乱,但有没有人遇到过同样的问题并知道解决方案? 非常感谢任何帮助。谢谢。


更多关于Golang RSA库使用问题排查与解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

很高兴你解决了问题,感谢分享解决方案!

更多关于Golang RSA库使用问题排查与解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题已解决,问题出在内存管理上。 当我通过以下方式清空垃圾回收器后,程序就能正常工作了:

debug.SetGCPercent(-1)

感谢

欢迎来到社区!

如果能看一些更多的代码会很有帮助。 你可以使用底部的代码片段工具在这里将代码包裹成块。

如果能在 play.golang.org 上运行代码也会很有帮助。他们让保存和分享任何类型的 Go 代码链接变得非常容易。

请注意,如果你需要从磁盘调用数据,Playground 中的代码将无法运行。(以及一些其他功能,比如 osnet 包中的函数)

type code here

前三个反引号后面的单词 “go” 可以启用语法高亮。

你好, 感谢! 项目规模较大,很难将包含API等的完整代码发送给你。 但与RSA相关的未正常运行部分如下:

func DecryptInfo(hash []byte, privateKey []byte) string {
	rng := rand.Reader
	private := BytesToPrivateKey(privateKey)
	infoSign, err := rsa.DecryptPKCS1v15(rng, private, []byte(hash)) //程序在此处"卡死",像是进入了无限循环无法执行下一步
	if err != nil {
		fmt.Println(err)
		return ""
	}
	return string(infoSign)
}

我在另一个类中这样调用该函数:

decoded := datadApps.DecryptInfo(valueJson, privateKey)

其中valueJson是加密的字节数组。

从你的描述来看,问题很可能出现在随机数生成器(rand.Reader)上。rsa.DecryptPKCS1v15函数需要一个密码学安全的随机数生成器,而rand.Reader在Go中默认使用crypto/rand,这通常是安全的。但程序"卡死"的现象表明可能在等待随机数生成器的熵源。

以下是几个可能的排查方向和解决方案:

1. 检查随机数生成器状态

首先确认随机数生成器是否正常工作:

import (
    "crypto/rand"
    "fmt"
)

func checkRandomSource() {
    // 测试随机数生成器
    testBytes := make([]byte, 16)
    n, err := rand.Read(testBytes)
    if err != nil {
        fmt.Printf("随机数生成错误: %v\n", err)
        return
    }
    fmt.Printf("成功生成 %d 字节随机数据\n", n)
}

2. 添加超时机制

由于解密操作可能阻塞,建议添加超时控制:

import (
    "context"
    "crypto/rsa"
    "time"
)

func decryptWithTimeout(privateKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    result := make(chan struct {
        data []byte
        err  error
    })
    
    go func() {
        rng := rand.Reader
        plaintext, err := rsa.DecryptPKCS1v15(rng, privateKey, ciphertext)
        result <- struct {
            data []byte
            err  error
        }{plaintext, err}
    }()
    
    select {
    case <-ctx.Done():
        return nil, ctx.Err()
    case res := <-result:
        return res.data, res.err
    }
}

3. 完整的解密函数示例

这里是一个更健壮的实现:

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "errors"
    "time"
)

func BytesToPrivateKey(priv []byte) (*rsa.PrivateKey, error) {
    block, _ := pem.Decode(priv)
    if block == nil {
        return nil, errors.New("failed to parse PEM block containing the key")
    }
    
    privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    
    return privKey, nil
}

func SafeDecrypt(privateKeyBytes []byte, ciphertext []byte) ([]byte, error) {
    privateKey, err := BytesToPrivateKey(privateKeyBytes)
    if err != nil {
        return nil, err
    }
    
    // 使用带超时的解密
    return decryptWithTimeout(privateKey, ciphertext)
}

4. 检查系统熵源

在Linux系统上,可以检查系统的熵源状态:

import (
    "os/exec"
    "strings"
)

func checkSystemEntropy() string {
    cmd := exec.Command("cat", "/proc/sys/kernel/random/entropy_avail")
    output, err := cmd.Output()
    if err != nil {
        return "无法检查熵源"
    }
    return strings.TrimSpace(string(output))
}

5. 替代方案:使用OAEP填充

如果问题持续存在,考虑使用更现代的OAEP填充方式:

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
)

func DecryptWithOAEP(privateKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
    rng := rand.Reader
    plaintext, err := rsa.DecryptOAEP(sha256.New(), rng, privateKey, ciphertext, nil)
    if err != nil {
        return nil, err
    }
    return plaintext, nil
}

主要排查步骤:

  1. 首先运行随机数生成器测试
  2. 添加超时机制防止永久阻塞
  3. 检查系统熵源是否充足
  4. 考虑使用OAEP作为替代方案

程序卡死在解密阶段通常与随机数生成器等待熵源有关,特别是在虚拟化环境或容器中运行时。

回到顶部