Why are the RSA signatures I generate with openssl and golang different?

golang-openssl
golang sign with private key

I use openssl command to sign the message "Test.", output with 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. 

The hex string is 091bcee24b69...

My 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-----

Generate signature with 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 run this code, following is output: 52e1cce3810c1a89693cf6965d1035618820a9e3a7b95203d885c4153dc3f7424b98e3ba628a186f1074d672bb59a1c0788a9c2064951ca2326eb1bf8e3e49e9

But I think it should be:

091bcee24b69...

Where is my wrong? Thanks

In addition to the newline added by echo described in helmbert’s answer, the OpenSSL rsautl command operates directly on the supplied data, while the Go code first hashes the data with SHA256 and then signs the resulting digest.

To perform the same as the Go code with OpenSSL, you can use the dgst command with the -sign option (note I’ve included the -n option to echo here too):

$ echo -n "Test." | openssl dgst -sha256 -sign private.key -hex
52e1cce3810c1a89693cf6965d1035618820a9e3a7b95203d885c4153dc3f7424b98e3ba628a186f1074d672bb59a1c0788a9c2064951ca2326eb1bf8e3e49e9

To go the other way and sign the raw message without hashing in Go code, you can pass 0 as the value of the hash argument to rsa.SignPKCS1v15:

indata := []byte("Test.")

s, err := rsa.SignPKCS1v15(nil, privKey, 0, indata)

go, In addition to the newline added by echo described in helmbert's answer, the OpenSSL rsautl command operates directly on the supplied data, while the Go  RSA Signature/Verify with .key and .cer; RSA Decrypt using PEM; RSA Encrypt with SHA-256 hash function and SHA-1 mask function; Walmart Partner API Authentication (Generate a Signature for a Request) Generate RSA Key and return Base64 PKCS8 Private Key; Convert RSA Private Key to Public Key; Get RSA Private Key in JWK Format (JSON Web Key) Get ECC Private Key in JWK Format (JSON Web Key) Get RSA Public Key in JWK Format (JSON Web Key) Get ECC Public Key in JWK Format (JSON Web Key) Load RSA

The echo command prints a string with a trailing newline (\n or 0a):

> echo 'Test.' | hexdump -C
00000000  54 65 73 74 2e 0a                                 |Test..|
00000006

So in your case, you're signing Test.\n the first time, and Test. the second time in your Go program. Use echo's -n switch to suppress the trailing newline:

> echo -n 'Test.' | hexdump -C
00000000  54 65 73 74 2e                                    |Test.|
00000005

RSA sign and verify using Openssl : Behind the scene, openssl genrsa -out myprivate.pem 512# Separate the public part from the Openssl decrypts the signature to generate hash and compares it to the hash of the  Package rsa implements RSA encryption as specified in PKCS#1. RSA is a single, fundamental operation that is used in this package to implement either public-key encryption or public-key signatures. The original specification for encryption and signatures with RSA is PKCS#1 and the terms "RSA encryption" and "RSA signatures" by default refer to PKCS#1 version 1.5.

This is a very useful 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

src/crypto/rsa/pkcs1v15_test.go - The Go Programming , 4 5 package rsa 6 7 import ( 8 "bytes" 9 "crypto" 10 "crypto/rand" 11 30 in, out string 31 } 32 33 // These test vectors were generated with `openssl rsautl -pkcs tested with 189 // `openssl rsautl -verify -inkey pk -in signature | hexdump -C` 190​  With your help, my problem has been resolved, thank you very much.Another question,I get the string "Test. " using the following comman: $ openssl rsautl -verify -inkey pub.key -pubin -in signature $ Test. Bug in Golang,I only found a function VerifyPKCS1v15 to verify the signature,but before call the function, I must have known this string

rsa - The Go Programming Language, Package rsa implements RSA encryption as specified in PKCS#1. RSA is a Hash: type PrecomputedValues: type PrivateKey: func GenerateKey(random io. it'll be different for the same ciphertext) and thus whether the padding was correct. I don't believe that any of the big-name certificate authorities are currently issuing RSA-PSS certificates, so they are likely to be quite uncommon in the wild. However, there are some applications that use them.

x509 - The Go Programming Language, PrivateKey) []byte: func MarshalPKCS1PublicKey(key *rsa. Time) (crlBytes []​byte, err error): func (c *Certificate) Equal(other *Certificate) bool: func (c New("​x509: cannot verify signature: algorithm unimplemented") On many Linux systems, /etc/ssl/cert.pem will contain the system wide set of root CAs in a format suitable  But create one anyway for a different key (one that can sign, e.g. RSA). To create an RSA key and an associated CSR: openssl genrsa -out rsakey.pem 1024 openssl req -new -key rsakey.pem -out rsa.csr Finally, you generate the DH cert from the RSA CSR and the DH public key.

Re: [go-nuts] Re: crypto/rsa doesn't seem to have OpenSSL's , Posted in group: golang-nuts kaori:tmp artyom$ openssl rsautl -verify -inkey id_rsa -in openssl.out It would be great if we can create with Go the same output as `openssl rsautl -sign -inkey id_rsa -out openssl.out -in input.txt`. -- same data with the exact same private key produces different signatures. Signatures you create this way will NOT verify in other software that obeys the standard, and signatures created in other software will give different (though PARTIALLY matching) results. Consider instead using. openssl {dgst -hashname | hashname} {-sign privatekey | -verify publickey}

Comments
  • With your help, my problem has been resolved, thank you very much.Another question,I get the string "Test.\n" using the following comman: $ openssl rsautl -verify -inkey pub.key -pubin -in signature $ Test. Bug in Golang,I only found a function VerifyPKCS1v15 to verify the signature,but before call the function, I must have known this string "Test.\n",in order to generate argument **hashed88. func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) Can I get the string "Test.\n" from public Key and signatrue,just like the openssl command?
  • just note, not all echo implementations support the -n switch.