Fer VT
Fer VT

Reputation: 508

Ruby RSA public key encryption to Golang

I'm currently working on a project where I have to "convert" some code from Ruby(version 1.9.3p194) to Golang(version 1.7). There is this part where Ruby uses RSA public key encryption and I always get a consistent result every time it gets executed. This is the function used:

Edit: I overlooked that after the public key encryption, there is a base 64 encoding as well

public_key = OpenSSL::PKey::RSA.new(public_encryption_key)
public_encrypted_text = public_key.public_encrypt(text, OpenSSL::PKey::RSA::NO_PADDING)
base64_encrypted_text = Base64.encode64(public_encrypted_text).gsub("\n", "")
escaped_encrypted_text = URI.escape(encrypted_key, "/+=")

However in Golang, due to the rsa library I can't get a consistent result since the function to encrypt takes a random parameter to generate different result each time. I understand why it needs to be different every time, but i can't get anything remotely similar to what ruby generates. These are the functions used in Golang:

//keyBytes is the public key as []byte
block, _ := pem.Decode(keyBytes)
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
    return nil, err
}

pubKey, ok := key.(*rsa.PublicKey)
if !ok {
    return nil, errors.New("Cannot convert to rsa.PublicKey")
}

result, err := rsa.EncryptPKCS1v15(cryptorand.Reader, pubKey, text)
encryptedText := base64.URLEncoding.EncodeToString(result)
encryptedText = strings.TrimRight(encryptedText, "=")

One of the problems is that ruby can encrypt the text with no problem, and in golang I'm getting an error that the key is too short to encrypt everything.

If I encrypt something else, like "Hello". When decrypting I get from ruby the error "padding check failed". The decryption is being handle like follows:

private_key.private_decrypt(Base64.decode64(text))  

EDIT: Thanks to the answer of gusto2 I now know better what is going on since I didn't have much understanding of RSA.

Now in Golang I was able to encrypt the text using PKCS1 v1.5, and just to be sure I tried to decrypt that as well, also in Golang, with no problem.

However in Ruby I still wasn't able to decrypt using the private key. So I figured that the base64 encoding used in Golang was the issue. So I changed that part to this:

encryptedText := base64.StdEncoding.EncodeToString(result)

And also I removed the last line were the equal sign was being trimmed.

With that done it worked like a charm.

Upvotes: 1

Views: 1679

Answers (1)

gusto2
gusto2

Reputation: 12075

I am no knowledgeable about golang, however I may know something about RSA.

The difference seems to be in the padding.

For ruby - no padding is used
For golang - PKCS1v15 padding is used

In the rubyexample you use OpenSSL::PKey::RSA::NO_PADDING is used which is VERY VERY unsafe. It is called textbook RSA and is not inteded in real-life use as it has many weaknesses and dangerous traps. So the ruby example is very dangerously unsafe because of using the textbook RSA. As well it is limited to encrypting small messages (much smaller than the keyspace).

There are two padding types used with RSA:

  • PKCS1 v1 (commonly referred as PKCS1) - this is a deterministic padding (the output is always the same), many cryptographers consider this option obsolete as some weaknesses has been found when not used properly, but it is still in use and not considered broken.

  • PKCS1 v2 (commonly refered as OAEP or PSS) which is stochastic (randomized) padding. You can distinguish the last two as the output of OAEP is always different.

One of the problems is that ruby can encrypt the text with no problem, and in golang I'm getting an error that the key is too short to encrypt everything

You've provided only a small part of the golang example, so here I may only assume many things.

As you claim the golang example outputs randomized output and according to the parameters PKCS1 v1.5 is used, I'd assume the implementation is doing hybrid encryption which is good and much safer way to encrypt data with RSA (using symmetric encryption with random key and wrap/encrypt the key with RSA).

Upvotes: 2

Related Questions