Generate RSA key with large public exponent

Issue

Step 1. I generated RSA key pairs for Alice and Bob, respectively, and encrypted a message for Alice using Alice’s public key.

Step 2. I multiplied the public exponent of Bob’s public key with the private exponent of Alice’s private key to have a new number.

Step 3. I generated a new RSA public key by keyRegen := rsa.PublicKey{N: keyPubAliceN, E: ENew} and used it to encrypt the message encrypted in step 1.

Step 4. I decrypted the re-encrypted message from step 3 using Bob’s private key. Theoretical now Bob can get the original message, which is the expected output.

Problem: However, I found that the public exponent in rsa.PublicKey should be an int, while my new public exponent generated in step 2 is a big.Int. I converted it into int and used the newly generated public key to do the encryption but error panic: crypto/rsa: public exponent too small happened. Also I guess I should not do such a conversion because the new number is probably larger than int range. Then are there any ways to generate a new RSA key with the large public exponent? Thank you!

Codes:

package main
import (
        "crypto"
        "crypto/rand"
        "crypto/rsa"
        "crypto/sha256"
        "fmt"
        "math/big"
    )
    
func main() {
    keyPriAlice, err := rsa.GenerateKey(rand.Reader, 1024)
    if err != nil {
        panic(err)
    }
    keyPubAlice := keyPriAlice.PublicKey
    keyPriAliceD := keyPriAlice.D
    keyPubAliceN := keyPubAlice.N

    keyPriBob, err := rsa.GenerateKey(rand.Reader, 1024)
    if err != nil {
        panic(err)
    }
    keyPubBob := keyPriBob.PublicKey
    keyPubBobE := big.NewInt(int64(keyPubBob.E))
    
    message := "secret"
    encryptedBytes, err := rsa.EncryptOAEP(
        sha256.New(),
        rand.Reader,
        &keyPubAlice,
        []byte(message),
        nil)
    if err != nil {
        panic(err)
    }
    
    z := new(big.Int)
    y := z.Mul(keyPriAliceD, keyPubBobE)
    ENew := int(y.Int64())
    keyRegen := rsa.PublicKey{N: keyPubAliceN, E: ENew}
    
    reEncryptedBytes, err := rsa.EncryptOAEP(
        sha256.New(),
        rand.Reader,
        &keyRegen,
        []byte(encryptedBytes),
        nil)
    if err != nil {
        panic(err)
    }
    
    // decrypt the re-encrypted plaintext using Bob's private key
    decryptedBytes, err := keyPriBob.Decrypt(nil, reEncryptedBytes, &rsa.OAEPOptions{Hash: crypto.SHA256})
    fmt.Println("decryptedBytes:", decryptedBytes)
    }

Solution

You’ll probably need to use a different library for this. In most modern RSA contexts, we want d, the private exponent, to be large for security reasons, but we want e to be small for performance reasons. As a practical matter, the vast majority of secure implementations I’ve seen choose 65537 for e, which is secure and fast (due to containing exactly two ones).

The Go library has made the assumption, based on the fact that practically every real-world scenario that isn’t an exploit wants a small e, that e will fit into an int, which may have been improvident, but is ultimately reasonable. You may find that OpenSSL is more suitable for this purpose, since it tends to make fewer assumptions about the data passed to it.

Answered By – bk2204

Answer Checked By – Pedro (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.