为什么我用 openssl 和 golang 生成的 RSA 签名不同?
Why are the RSA signatures I generate with openssl and golang different?
我使用 openssl 命令对消息进行签名 "Test.",使用 hexdump
输出
# echo "Test." | openssl rsautl -inkey privite.key -sign -hexdump
0000 - 09 1b ce e2 4b 69 86 be-d7 b1 fb f0 ec e4 53 0e ....Ki........S.
0010 - ef 9c a4 7b db d3 21 d5-3e 78 23 61 89 34 7e bc ...{..!.>x#a.4~.
0020 - e9 1e 5a e9 f4 40 e6 53-07 e4 dd 1a fe 31 ec 42 ..Z..@.S.....1.B
0030 - 98 a5 07 d4 7e d9 f4 01-2f ba a3 65 18 b7 69 a4 ....~.../..e..i.
十六进制字符串是 091bcee24b69...
我的private.Key
# cat private.Key
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
-----END RSA PRIVATE KEY-----
使用 Golang 生成签名
var prvKeyPem = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
-----END RSA PRIVATE KEY-----`
func GenerateSignature() {
block, _ := pem.Decode([]byte(prvKeyPem))
if block == nil {
panic("failed to parse root certificate PEM")
}
privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) //x509.ParseCertificate(block.Bytes)
if err != nil {
panic("failed to parse certificate: " + err.Error())
}
indata := "Test."
h := sha256.New()
h.Write([]byte(indata))
digest := h.Sum(nil)
s, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, digest)
if err != nil {
panic("failed to sign:" + err.Error())
}
fmt.Printf("%x\n", s)
}
func main() {
GenerateSignature()
}
go 运行这段代码,输出如下:
52e1cce3810c1a89693cf6965d1035618820a9e3a7b95203d885c4153dc3f7424b98e3ba628a186f1074d672bb59a1c0788a9c2064951ca2326eb1bf8e3e4=e39]9[=
不过我觉得应该是:
091bcee24b69...
我哪里错了?谢谢
echo
命令打印带有尾随换行符的字符串(\n
或 0a
):
> echo 'Test.' | hexdump -C
00000000 54 65 73 74 2e 0a |Test..|
00000006
因此,在您的情况下,您在 Go 程序中第一次签名 Test.\n
,第二次签名 Test.
。使用 echo
的 -n
开关来抑制结尾的换行符:
> echo -n 'Test.' | hexdump -C
00000000 54 65 73 74 2e |Test.|
00000005
除了 中描述的 echo
添加的换行符外,OpenSSL rsautl
命令直接对提供的数据进行操作,而 Go 代码首先使用 SHA256 对数据进行哈希处理然后签署生成的摘要。
要使用 OpenSSL 执行与 Go 代码相同的操作,您可以使用 dgst
command 和 -sign
选项(注意我已经将 -n
选项包含在 echo
这里也是):
$ echo -n "Test." | openssl dgst -sha256 -sign private.key -hex
52e1cce3810c1a89693cf6965d1035618820a9e3a7b95203d885c4153dc3f7424b98e3ba628a186f1074d672bb59a1c0788a9c2064951ca2326eb1bf8e3e49e9
要走另一条路并在 Go 代码中不使用散列对原始消息进行签名,您可以将 0
作为 hash
参数的值传递给 rsa.SignPKCS1v15
:
indata := []byte("Test.")
s, err := rsa.SignPKCS1v15(nil, privKey, 0, indata)
这非常有用link。
// Sign secret with rsa with PKCS 1.5 as the padding algorithm
// The result should be exactly same as "openssl rsautl -sign -inkey "YOUR_RSA_PRIVATE_KEY" -in "YOUR_PLAIN_TEXT""
signer, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey.(*rsa.PrivateKey), crypto.Hash(0), []byte(message))
https://github.com/bitmartexchange/bitmart-go-api/blob/master/bm_client.go
我使用 openssl 命令对消息进行签名 "Test.",使用 hexdump
输出# echo "Test." | openssl rsautl -inkey privite.key -sign -hexdump
0000 - 09 1b ce e2 4b 69 86 be-d7 b1 fb f0 ec e4 53 0e ....Ki........S.
0010 - ef 9c a4 7b db d3 21 d5-3e 78 23 61 89 34 7e bc ...{..!.>x#a.4~.
0020 - e9 1e 5a e9 f4 40 e6 53-07 e4 dd 1a fe 31 ec 42 ..Z..@.S.....1.B
0030 - 98 a5 07 d4 7e d9 f4 01-2f ba a3 65 18 b7 69 a4 ....~.../..e..i.
十六进制字符串是 091bcee24b69...
我的private.Key
# cat private.Key
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
-----END RSA PRIVATE KEY-----
使用 Golang 生成签名
var prvKeyPem = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
-----END RSA PRIVATE KEY-----`
func GenerateSignature() {
block, _ := pem.Decode([]byte(prvKeyPem))
if block == nil {
panic("failed to parse root certificate PEM")
}
privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) //x509.ParseCertificate(block.Bytes)
if err != nil {
panic("failed to parse certificate: " + err.Error())
}
indata := "Test."
h := sha256.New()
h.Write([]byte(indata))
digest := h.Sum(nil)
s, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, digest)
if err != nil {
panic("failed to sign:" + err.Error())
}
fmt.Printf("%x\n", s)
}
func main() {
GenerateSignature()
}
go 运行这段代码,输出如下: 52e1cce3810c1a89693cf6965d1035618820a9e3a7b95203d885c4153dc3f7424b98e3ba628a186f1074d672bb59a1c0788a9c2064951ca2326eb1bf8e3e4=e39]9[=
不过我觉得应该是:
091bcee24b69...
我哪里错了?谢谢
echo
命令打印带有尾随换行符的字符串(\n
或 0a
):
> echo 'Test.' | hexdump -C
00000000 54 65 73 74 2e 0a |Test..|
00000006
因此,在您的情况下,您在 Go 程序中第一次签名 Test.\n
,第二次签名 Test.
。使用 echo
的 -n
开关来抑制结尾的换行符:
> echo -n 'Test.' | hexdump -C
00000000 54 65 73 74 2e |Test.|
00000005
除了 echo
添加的换行符外,OpenSSL rsautl
命令直接对提供的数据进行操作,而 Go 代码首先使用 SHA256 对数据进行哈希处理然后签署生成的摘要。
要使用 OpenSSL 执行与 Go 代码相同的操作,您可以使用 dgst
command 和 -sign
选项(注意我已经将 -n
选项包含在 echo
这里也是):
$ echo -n "Test." | openssl dgst -sha256 -sign private.key -hex
52e1cce3810c1a89693cf6965d1035618820a9e3a7b95203d885c4153dc3f7424b98e3ba628a186f1074d672bb59a1c0788a9c2064951ca2326eb1bf8e3e49e9
要走另一条路并在 Go 代码中不使用散列对原始消息进行签名,您可以将 0
作为 hash
参数的值传递给 rsa.SignPKCS1v15
:
indata := []byte("Test.")
s, err := rsa.SignPKCS1v15(nil, privKey, 0, indata)
这非常有用link。
// Sign secret with rsa with PKCS 1.5 as the padding algorithm
// The result should be exactly same as "openssl rsautl -sign -inkey "YOUR_RSA_PRIVATE_KEY" -in "YOUR_PLAIN_TEXT""
signer, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey.(*rsa.PrivateKey), crypto.Hash(0), []byte(message))
https://github.com/bitmartexchange/bitmart-go-api/blob/master/bm_client.go