Hi all I am currently trying to accomplish three things with the following code.
Generate a public/private key pair using the crypto/rsa library.
Export the public and private keys into individual PEM files to be used in separate programs.
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
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
}