gpt4 book ai didi

go - 使用 RSA 私钥加密消息(如在 OpenSSL 的 RSA_private_encrypt 中)

转载 作者:IT老高 更新时间:2023-10-28 13:09:20 26 4
gpt4 key购买 nike

我正在尝试实现 Chef API client在 Go 中,但坚持尝试创建正确的请求 header RSA 签名。根据documentation :

A canonical header is signed with the private key used by the client machine from which the request is sent, and is also encoded using Base64.

以下对 OpenSSL::PKey::RSA.private_encrypt() 的 ruby​​ 调用可以在 mixlib-authentication gem code 中找到, 它使用 OpenSSL bindings , private_encrypt() 方法调用 RSA_private_encrypt openssl function .

很遗憾,我在 Go 的标准库中找不到匹配的函数; crypto/rsa看起来很接近,但它只实现了传统的加密方法:使用 public key 进行加密,使用 private key 进行哈希签名。 OpenSSL 的 RSA_private_encrypt 则相反:它使用私钥加密(小)消息(类似于从消息哈希创建签名)。

这个“签名”也可以用这个命令来实现:

openssl rsautl -sign -inkey path/to/private/key.pem \
-in file/to/encrypt -out encrypted/output

是否有任何本地 Go 库可以实现与 OpenSSL 的 RSA_private_encrypt 相同的结果,或者唯一的方法是使用 Cgo 从 OpenSSL 库中调用此函数?也许我错过了一些东西。我的想法是在没有任何非 go 依赖项的情况下实现客户端。

我是 Go 新手,所以我不确定我是否可以深入研究 crypto/rsa 模块源代码。


找到 similar question , 但是 the answer使用 SignPKCS1v15 显然是错误的(这个 function encrypts message's hash, not the message itself )。

最佳答案

great help of the golang community ,找到了解决办法:

原代码发布于 http://play.golang.org/p/jrqN2KnUEM作者:Alex(见 mailing list)。

我添加了 rfc2313 第 8 节中指定的输入 block 大小检查: http://play.golang.org/p/dGTl9siO8E

代码如下:

package main

import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"math/big"
"os/exec"
)

var (
ErrInputSize = errors.New("input size too large")
ErrEncryption = errors.New("encryption error")
)

func PrivateEncrypt(priv *rsa.PrivateKey, data []byte) (enc []byte, err error) {

k := (priv.N.BitLen() + 7) / 8
tLen := len(data)
// rfc2313, section 8:
// The length of the data D shall not be more than k-11 octets
if tLen > k-11 {
err = ErrInputSize
return
}
em := make([]byte, k)
em[1] = 1
for i := 2; i < k-tLen-1; i++ {
em[i] = 0xff
}
copy(em[k-tLen:k], data)
c := new(big.Int).SetBytes(em)
if c.Cmp(priv.N) > 0 {
err = ErrEncryption
return
}
var m *big.Int
var ir *big.Int
if priv.Precomputed.Dp == nil {
m = new(big.Int).Exp(c, priv.D, priv.N)
} else {
// We have the precalculated values needed for the CRT.
m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
m.Sub(m, m2)
if m.Sign() < 0 {
m.Add(m, priv.Primes[0])
}
m.Mul(m, priv.Precomputed.Qinv)
m.Mod(m, priv.Primes[0])
m.Mul(m, priv.Primes[1])
m.Add(m, m2)

for i, values := range priv.Precomputed.CRTValues {
prime := priv.Primes[2+i]
m2.Exp(c, values.Exp, prime)
m2.Sub(m2, m)
m2.Mul(m2, values.Coeff)
m2.Mod(m2, prime)
if m2.Sign() < 0 {
m2.Add(m2, prime)
}
m2.Mul(m2, values.R)
m.Add(m, m2)
}
}

if ir != nil {
// Unblind.
m.Mul(m, ir)
m.Mod(m, priv.N)
}
enc = m.Bytes()
return
}

func main() {
// o is output from openssl
o, _ := exec.Command("openssl", "rsautl", "-sign", "-inkey", "t.key", "-in", "in.txt").Output()

// t.key is private keyfile
// in.txt is what to encode
kt, _ := ioutil.ReadFile("t.key")
e, _ := ioutil.ReadFile("in.txt")
block, _ := pem.Decode(kt)
privkey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
encData, _ := PrivateEncrypt(privkey, e)
fmt.Println(encData)
fmt.Println(o)
fmt.Println(string(o) == string(encData))
}

更新:我们可以期待在 Go 1.3 中原生支持这种类型的登录,请参阅 the appropriate commit .

关于go - 使用 RSA 私钥加密消息(如在 OpenSSL 的 RSA_private_encrypt 中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18011708/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com