I need to use a public key to encrypt the message "Message" and save it as a file ciphertext.txt by converting pre-received data in HEX encoding. I do not need the public key to be generated, I already have a ready-made public key. Using this public key, you need to encrypt the message.
Here's what I was able to do:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"log"
"os"
)
func main() {
publicKeyBytes, err := os.ReadFile("publicik.key")
if err!= nil {
return
}
publicKey, err := decodepublicKey(publicKeyBytes)
if err != nil {
return
}
plaintext := []byte("Message")
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, plaintext, nil)
if err != nil {
return
}
log.Printf( "%x", ciphertext)
privateKeyBytes, err := os.ReadFile("private.key")
if err != nil {
return
}
privateKey, err := decodePrivateKey(privateKeyBytes)
if err != nil {
return
}
decryptedtext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey,ciphertext, nil)
if err != nil {
return
}
log.Printf("%s", decryptedtext)
}
func decodepublicKey(key []byte) (*rsa.PublicKey, error) {
block, _:= pem.Decode(key)
if block == nil {
return nil, errors.New("can't decode pem block")
}
publicKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return nil, err
}
return publicKey, nil
}
func decodePrivateKey(key []byte) (*rsa.PrivateKey,error) { block, _ := pem.Decode(key)
if block == nil {
return nil, errors.New("can't decode pem block")
}
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return privateKey, nil
}
Then I don’t know how to solve this problem?
Please help with solving this problem
I debugged your code and found 2 potential issues:
Double check whether you need to use x509.ParsePKCS1PublicKey() or x509.ParsePKIXPublicKey(). This depends on the format of your public key. More here: https://stackoverflow.com/a/54775627/9698467
You may need to type assert the public key in your decodepublicKey function: return publicKey.(*rsa.PublicKey), nil.
Related
All I wanted to do, is to generate a new secret key, create JWT token and then validate it.
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/base64"
"fmt"
"log"
"time"
"github.com/golang-jwt/jwt/v4"
)
func main() {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatalln(err)
return
}
privateK, err := x509.MarshalECPrivateKey(key)
if err != nil {
log.Fatalln(err)
return
}
claims := jwt.MapClaims{}
claims["authorized"] = true
claims["user_id"] = 10
claims["exp"] = time.Now().Add(time.Hour * time.Duration(1)).Unix()
t := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
tokenStr, err := t.SignedString(key)
if err != nil {
log.Fatalln(err)
return
}
fmt.Printf("Secret: %s\n", base64.StdEncoding.EncodeToString(privateK))
fmt.Printf("Token: %s\n", tokenStr)
// Validate token
_, err = jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
return nil, fmt.Errorf("unexpected signing method %v", token.Header["alg"])
}
return key, nil
})
if err != nil {
log.Fatalf("Token is invalid %v", err)
} else {
fmt.Println("Token is valid")
}
}
And I get Token is invalid: key is of invalid type. What I'm doing wrong?
As per the docs
The ECDSA signing method (ES256,ES384,ES512) expect *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for validation
Your keyfunc is returning a *edcsa.PrivateKey which does not match the above. To fix this change return key, nil to return &key.PublicKey, nil (playground).
const strPrivateKey = "30820b82020100300d06092a864886f70d010101050004820b6c30820b680201000282028100acfc585f43ca36ec2dddc518b5c7d1303b658faec58b634aff16ce4b7930b93a23517f8d9c8a260f4e2eb44b01da5b6588fefe63acb68c15677"
decoded, err := hex.DecodeString(strPrivateKey)
if err != nil {
return ""
}
privateKey, err := x509.ParsePKCS8PrivateKey(decoded)
if err != nil {
return ""
}
encypt, err := rsa.EncryptPKCS1v15(rand.Reader, &privateKey.PublicKey, data)
if err != nil {
fmt.Println(err)
return ""
}
privateKey.PublicKey undefined (type any has no field or method PublicKey)
According to the doc (https://pkg.go.dev/crypto/x509#go1.19.3#ParsePKCS8PrivateKey):
func ParsePKCS8PrivateKey(der []byte) (key any, err error)
...
It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, or a ed25519.PrivateKey. More types might be supported in the future.
You should use type assertion to check the type of the key:
switch privateKey := privateKey.(type) {
case *rsa.PrivateKey:
// ...
case *ecdsa.PrivateKey:
// ...
case ed25519.PrivateKey:
// ...
default:
panic("unknown key")
}
Since rsa.EncryptPKCS1v15 expects a *rsa.PublicKey, your code can be written like this:
if privateKey, ok := privateKey.(*rsa.PrivateKey); ok {
encypt, err := rsa.EncryptPKCS1v15(rand.Reader, &privateKey.PublicKey, data)
}
BTW, the provided strPrivateKey is invalid (encoding/hex: odd length hex string). You can get some valid private keys from https://github.com/golang/go/blob/1c05968c9a5d6432fc6f30196528f8f37287dd3d/src/crypto/x509/pkcs8_test.go#L52-L124
*correct answer. I resolved privateKey.(rsa.PrivateKey)
decodedString, err := hex.DecodeString(utility.StrPrivateKey)
if err != nil {
return err
}
pkcs8PrivateKey, err := x509.ParsePKCS8PrivateKey(decodedString)
if err != nil {
return err
}
privateKey := pkcs8PrivateKey.(*rsa.PrivateKey)
I try to add tls config to "github.com/eclipse/paho.mqtt.golang" client package. However in the config pems load from a file. I want to use pem as string format. For example an object has "caPem" key and its value CA pem as string.
func NewTLSConfig(cACertificate, clientCertificate, clientKey string) *tls.Config {
certpool := x509.NewCertPool()
pemCerts, err := ioutil.ReadFile("/ca.pem")
if err == nil {
certpool.AppendCertsFromPEM(pemCerts)
}
cert, err := tls.LoadX509KeyPair("/client.pem", "/client.key")
if err != nil {
panic(err)
}
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
panic(err)
}
fmt.Println(cert.Leaf)
return &tls.Config{
RootCAs: certpool,
ClientAuth: tls.RequestClientCert,
ClientCAs: nil,
InsecureSkipVerify: false,
Certificates: []tls.Certificate{cert},
}
}
As you see above code , pemCerts get public key from a file. Functions parameters "caCertificate..." are string. I just want to use them like "pemCerts := caCertificate". How can I implement this
Made an example, of how to this this. It does assume that you do not have more than 1 PEM block in the string. If you do you should adapt it to call strPEMToPubCert multiple times.
(playground link)
package main
import (
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)
func main() {
var pubPEMData = `-----BEGIN CERTIFICATE-----
MIIG9TCCBd2gAwIBAgISBLS106X/pLzr6OgL1QIQaFjHMA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMTEyMDUxNDE1NTJaFw0yMjAzMDUxNDE1NTFaMB4xHDAaBgNVBAMM
Eyouc3RhY2tleGNoYW5nZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCad2WyTsmxXwoyz/iQST49XuSAciGr8GcyUtrestK82l4uHvU0/eCsxkUa
nT6xpm60l9OaAXCjJHEl9+0qKOUQ8+FJzr4W9PuiALE1E6j5mpYk3FRERZwX+AFZ
dN2G1rSb+uZvDSiR9eUikj0ueR5TTA+ZUsNLaByE+/EzcUqja9Qxyq7zkizSolxy
/RVTRPB2BaDkGY4I46avu8PJPm6R3skp0L96MnWSDVtJhIGc5lisoUEozrlTbTuT
SfBvPAAIqFT6702LJqFIF5rW04++GrEBh6S1I+17IZxneTMcorx0sYmXVzRGvz6e
0nOfXo6a80hAFgs+vci3UWEze7vrAgMBAAGjggQXMIIEEzAOBgNVHQ8BAf8EBAMC
BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAw
HQYDVR0OBBYEFMbQN0TT6bdr8CA4WpQ9UwT/XKTZMB8GA1UdIwQYMBaAFBQusxe3
WFbLrlAJQOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggrBgEFBQcwAYYVaHR0
cDovL3IzLm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRwOi8vcjMuaS5sZW5j
ci5vcmcvMIIB5AYDVR0RBIIB2zCCAdeCDyouYXNrdWJ1bnR1LmNvbYISKi5ibG9n
b3ZlcmZsb3cuY29tghIqLm1hdGhvdmVyZmxvdy5uZXSCGCoubWV0YS5zdGFja2V4
Y2hhbmdlLmNvbYIYKi5tZXRhLnN0YWNrb3ZlcmZsb3cuY29tghEqLnNlcnZlcmZh
dWx0LmNvbYINKi5zc3RhdGljLm5ldIITKi5zdGFja2V4Y2hhbmdlLmNvbYITKi5z
dGFja292ZXJmbG93LmNvbYIVKi5zdGFja292ZXJmbG93LmVtYWlsgg8qLnN1cGVy
dXNlci5jb22CDWFza3VidW50dS5jb22CEGJsb2dvdmVyZmxvdy5jb22CEG1hdGhv
dmVyZmxvdy5uZXSCFG9wZW5pZC5zdGFja2F1dGguY29tgg9zZXJ2ZXJmYXVsdC5j
b22CC3NzdGF0aWMubmV0gg1zdGFja2FwcHMuY29tgg1zdGFja2F1dGguY29tghFz
dGFja2V4Y2hhbmdlLmNvbYISc3RhY2tvdmVyZmxvdy5ibG9nghFzdGFja292ZXJm
bG93LmNvbYITc3RhY2tvdmVyZmxvdy5lbWFpbIIRc3RhY2tzbmlwcGV0cy5uZXSC
DXN1cGVydXNlci5jb20wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMB
AQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEF
BgorBgEEAdZ5AgQCBIH2BIHzAPEAdwDfpV6raIJPH2yt7rhfTj5a6s2iEqRqXo47
EsAgRFwqcwAAAX2LKmpMAAAEAwBIMEYCIQC1jB7OwpQiHacbVnEZgWegpCOksm6Z
TYkTjXCmIo9m1AIhAPjs+1PPNr/avFzSydhUROI+Rvqx0iZqXzNc24PIOXjBAHYA
KXm+8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVdx4QAAAF9iypqRAAABAMARzBF
AiEA0oJ418l3aDXj4EVAtzf5o2nUdYiZiH7pLvA1hd7ZSKUCICFeACPl73NNLSzR
7yoKEV6nO7Zlk4rUd/fUyROY35OMMA0GCSqGSIb3DQEBCwUAA4IBAQB+hvmbEaHF
jEkSZiTllNe+XWtfz6TiWIugoqdDL67app49ZTTZ94oLRGxybm62nBIEX/2gCRgd
fqnDecg4BWIyl2jti73eKkmt9+pcCDqZ1JcbW8rDLmZJnzdcC0o739BGRq/ufP5R
Fb8qXAap2VH/29MQImxB166PsAb9rKdS1kNSfg4Zsu7nisg7q47dyzZMT9cTbajf
D/T6hl30nHOyJFvny5vYwDLtiNg5BJ2xZzZFh4B73mY53jjN2EXn4S5LI9J+0NmY
dic7TY+lsttvfrJ+cySMO7E1T1SkgEgHtfsadlRRWNFl80R91sS98FHbhBg/MSMk
yAm4xgff5rYD
-----END CERTIFICATE-----`
crt, _, err := strPEMToPubCert(pubPEMData)
if err != nil {
panic(err)
}
fmt.Println(crt.DNSNames)
}
func strPEMToPubCert(pemStr string) (*x509.Certificate, []byte, error) {
block, rest := pem.Decode([]byte(pemStr))
if block == nil || block.Type != "CERTIFICATE" {
return nil, rest, errors.New("failed to decode PEM block containing certificate")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, rest, err
}
return cert, rest, nil
}
I am trying to send a raw transaction with eth.sendTransaction but I am getting an error that says {"code":-32000,"message":"unknown account"}. I am not sure what is causing this and I cant seem to find an answer on the internet. Can anyone help me figure it out? Here is my code:
func ExecuteSignedTransaction(rawTransaction string) {
var hash web3.Hash
data := make(map[string]interface{})
data["data"] = rawTransaction
err := Web3HTTPClient.Call("eth_sendTransaction", &hash, data)
if err != nil{
fmt.Println(err)
Os.Exit(1)
}
fmt.Println("Sent tx hash:", hash)
}
So, what I might do here:
import (
"strings"
"crypto/ecdsa"
"math/big"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
)
var chainId = big.NewInt(1) // chain id for the ethereum mainnet, change according to needs
func ecdsaPrivateKeyFromHex(privKeyHex string) *ecdsa.PrivateKey {
ecdsaKey, err := crypto.HexToECDSA(privKeyHex)
if err != nil { panic(err) }
return ecdsaKey
}
func newTransactOpts(privKey *ecdsa.PrivateKey) *bind.TransactOpts {
transactOpts, err := bind.NewKeyedTransactorWithChainID(privKey, chainId)
if err != nil { panic(err) }
return transactOpts
}
func newRpcClient() *ethclient.Client {
c, err := ethclient.Dial("insert rpc url here")
if err != nil { panic(err) }
return c
}
// note: constructing the *types.Transaction object left as
// an exercise to the reader
func ExecuteTransaction(rawTransaction *types.Transaction) {
privKeyHex := "0xblahblahblahblahblah" // use your own account's private key
transactOpts := newTransactOpts(ecdsaPrivateKeyFromHex(privKeyHex))
signedTxn, err := transactOpts.Signer(transactOpts.From, rawTransaction)
if err != nil { panic(err) }
rpcClient := newRpcClient()
if err := rpcClient.SendTransaction(context.Background(), signedTxn); err != nil { panic(err) }
// do whatever
}
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
}