Search code examples
goaesrsa

Error Decrypting test message with RSA/PEM files


Hi all I am currently trying to accomplish three things with the following code.

  1. Generate a public/private key pair using the crypto/rsa library.

  2. Export the public and private keys into individual PEM files to be used in separate programs.

  3. Load the PEM files respectively into their individual scripts to encode/decode messages.

Everything works fine until I try to decrypt a test message with "Private-key-decryption.go". I received this error when decrypting the ciphertext "Error from decryption: crypto/rsa: decryption error"

Included are all of my code blocks I am using

Key-Generation.go

package main

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/pem"
    "fmt"
    "os"
)

//Write_private_key_to_file write pem_key to a file
func WriteToFile(Pem_Key string, filename string) {

    f, err := os.Create(filename)
    if err != nil {
        fmt.Println(err)
        return
    }
    l, err := f.WriteString(Pem_Key)
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(l, "bytes written successfully")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }

}

//ExportRsaPrivateKeyAsPemStr returns private pem key
func ExportRsaPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string {
    privkey_bytes := x509.MarshalPKCS1PrivateKey(privkey)
    privkey_pem := pem.EncodeToMemory(
        &pem.Block{
            Type:  "RSA PRIVATE KEY",
            Bytes: privkey_bytes,
        },
    )
    return string(privkey_pem)
}

//ExportRsaPublicKeyAsPemStr_to_pem_file extracts public key from generated private key
func ExportRsaPublicKeyAsPemStr(publickey *rsa.PublicKey) (string, error) {
    pubkey_bytes, err := x509.MarshalPKIXPublicKey(publickey)
    if err != nil {
        return "", err
    }
    //fmt.Println(pubkey_bytes)
    pubkey_pem := pem.EncodeToMemory(
        &pem.Block{
            Type:  "RSA PUBLIC KEY",
            Bytes: pubkey_bytes,
        },
    )

    return string(pubkey_pem), nil
}

func main() {
    // generate a 1024-bit private-key
    priv, err := rsa.GenerateKey(rand.Reader, 1024)

    // extract the public key from the private key as string
    pub := &priv.PublicKey

    message := []byte("test message")

    hashed := sha256.Sum256(message)

    signature, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed[:])
    if err != nil {
        fmt.Printf("Error from signing: %s\n", err)
        return
    }

    err = rsa.VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, hashed[:], signature)
    if err != nil {
        fmt.Printf("Error from verification: %s\n", err)
        return
    } else {
        fmt.Printf("signature is verified\n")
    }

    //calling function to export private key into PEM file
    pem_priv := ExportRsaPrivateKeyAsPemStr(priv)

    //writing private key to file
    WriteToFile(pem_priv, "private-key.pem")

    //calling function to export public key as pPEM file
    pem_pub, _ := ExportRsaPublicKeyAsPemStr(pub)
    WriteToFile(pem_pub, "public-key.pem")
} 




Public-key_encryption.go

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/pem"
    "errors"
    "fmt"
    "io/ioutil"
)

//ParseRsaPublicKeyFromPemStr takes a publicKeyPEM file as a string and returns a rsa.PublicKey object
func ParseRsaPublicKeyFromPemStr(pubPEM string) (*rsa.PublicKey, error) {
    block, _ := pem.Decode([]byte(pubPEM))
    if block == nil {
        return nil, errors.New("failed to parse PEM block containing the key")
    }

    pub, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }

    switch pub := pub.(type) {
    case *rsa.PublicKey:
        return pub, nil
    default:
        break // fall through
    }
    return nil, errors.New("Key type is not RSA")
}

func main() {

    //reading in the public key file to be passed the the rsa object creator
    PublicKeyAsString, err := ioutil.ReadFile("public-key.pem")
    if err != nil {
        fmt.Print(err)
    }

    //Creating parsing Public PEM key to *rsa.PublicKey
    rsa_public_key_object, _ := ParseRsaPublicKeyFromPemStr(string(PublicKeyAsString))

    challengeMsg := []byte("c")

    ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsa_public_key_object, challengeMsg, nil)
    if err != nil {
        fmt.Printf("Error from encryption: %s\n", err)
        return
    }

    fmt.Printf("%x", ciphertext)
}

Private-key-decryption.go

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/pem"
    "errors"
    "fmt"
    "io/ioutil"
)

//takes a privatekey PEM file as a string and returns a pointer rsa.PublicKey object
func parseRsaPrivateKeyFromPemStr(p string) (*rsa.PrivateKey, error) {
    block, _ := pem.Decode([]byte(p))
    if block == nil {
        return nil, errors.New("failed to parse PEM block containing the key")
    }

    key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }

    return key, nil
}

func main() {

    //reading in the public key file to be passed the the rsa object creator
    PrivateKeyAsString, err := ioutil.ReadFile("private-key.pem")
    if err != nil {
        fmt.Print(err)
    }

    //Creating parsing private PEM key to *rsa.PublicKey
    rsa_private_key_object, _ := parseRsaPrivateKeyFromPemStr(string(PrivateKeyAsString))

    ciphertext := []byte("1f58ab29106c7971c9a4307c39b6b09f8910b7ac38a8d0abc15de14cbb0f651aa5c7ca377fd64a20017eaaff0a57358bc8dd05645c8b2b24bbb137ab2e5cf657f9a6a7593ce8d043dd774d79986b00f679fc1492a6ed4961f0e1941a5ef3c6ec99f952b0756700a05314c31c768fe9463f77f23312a51a97587b04b4d8b50de0")

    plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, rsa_private_key_object, ciphertext, nil)
    if err != nil {
        fmt.Printf("Error from decryption: %s\n", err)
        return
    }

    fmt.Printf("\nPlaintext: %s\n", string(plaintext))

}

Please let me know what needs to be changed. This is my first crypto project and I am starting to get bags under my eyes lol


Solution

  • You're close. In the encryption part, you produce a hex string with that %x format string. So, in the decryption part, you should do the corresponding hex decode.

    In your Private-key-decryption.go, change

    ciphertext := []byte("1f58ab29106c7971c9a4307c39b6b09f8910b7ac38a8d0abc15de14cbb0f651aa5c7ca377fd64a20017eaaff0a57358bc8dd05645c8b2b24bbb137ab2e5cf657f9a6a7593ce8d043dd774d79986b00f679fc1492a6ed4961f0e1941a5ef3c6ec99f952b0756700a05314c31c768fe9463f77f23312a51a97587b04b4d8b50de0")
    

    to

    ciphertext, err := hex.DecodeString("1f58ab29106c7971c9a4307c39b6b09f8910b7ac38a8d0abc15de14cbb0f651aa5c7ca377fd64a20017eaaff0a57358bc8dd05645c8b2b24bbb137ab2e5cf657f9a6a7593ce8d043dd774d79986b00f679fc1492a6ed4961f0e1941a5ef3c6ec99f952b0756700a05314c31c768fe9463f77f23312a51a97587b04b4d8b50de0")
    if err != nil {
            fmt.Printf("Error from hex decode: %s\n", err)
            return
    }