I am tring to generate dkim key using golang, my current code is :
package appdkim
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"fmt"
"os"
)
func Keymaker(path string) {
reader := rand.Reader
bitSize := 2048
key, err := rsa.GenerateKey(reader, bitSize)
checkError(err)
publicKey := key.PublicKey
savePEMKey(path+".priv", key)
savePublicPEMKey2(path+".pub", publicKey)
return
}
func savePEMKey(fileName string, key *rsa.PrivateKey) {
outFile, err := os.Create(fileName)
checkError(err)
defer outFile.Close()
var privateKey = &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}
err = pem.Encode(outFile, privateKey)
checkError(err)
}
func savePublicPEMKey2(fileName string, pubkey rsa.PublicKey) {
//var PublicKeyRow bytes.Buffer
var pemkey = &pem.Block{
Type: "PUBLIC KEY",
Bytes: x509.MarshalPKCS1PublicKey(&pubkey),
}
pemfile, err := os.Create(fileName)
checkError(err)
defer pemfile.Close()
err = pem.Encode(pemfile, pemkey)
checkError(err)
//err = pem.Encode(&PublicKeyRow, pemkey)
//checkError(err)
//return PublicKeyRow.String()
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error ", err.Error())
os.Exit(1)
}
}
the code is working, generate the dkim private/public keys, problem is this keys return bad keys by sender, if i generate keys using this site : https://easydmarc.com/tools/dkim-record-generator/ the keys results valid.
this is my dkim settings in dns :
v=DKIM1;t=s;p=MIGJAoGBD1DSPRFFTujiCAiadP9ZeA6eAyf0GktfCQO2WKbrAx2Cu15y2A+agQMWNTmZbbhcznGZiz3kA9y7c0wOqN2iaJchBAxt4qdg1vUhy+6CkSZcY5bdm8uOxsXW3gjOTyZrOur/c118wMTOmSJKHOjn9xLG3ta8tXJtqab8idtx4TlBAgMBAAE=
I try to understend what if diferent with my golang key like key generated by easydmarc.com. What i need to change to my golang code for be valid for dkim validation ?
Related
I have a private key in a file -----BEGIN PRIVATE KEY-----\nxxx-----END PRIVATE KEY-----\n
I am trying to perform the below which is in Ruby in Go and got stuck as Go accepts only pem file. Kindly suggest.
azure_certificate_private_key = OpenSSL::PKey.read(private_key_file)
base64_signature = Base64.strict_encode64(private_key.sign(OpenSSL::Digest::SHA256.new, headerPayloadConcatenated))
I have tried as,
signBytes, err := ioutil.ReadFile(privKeyPath)
signer, err := ParsePrivateKey(signBytes)
no key found error
package main
import (
"encoding/pem"
"crypto/x509"
"io/ioutil"
)
func main() {
signBytes, err := ioutil.ReadFile(privKeyPath)
if err != nil {
panic(err) //or do whatever with err
}
keyRSA := parseRSAKey(signBytes)
//keyRSA is a *rsa.PrivateKey
//....use the key
}
func parseRSAKey(b []byte) *rsa.PrivateKey {
block, _ := pem.Decode(b)
if block == nil {
panic("no PEM block")
}
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
return key
}
this should work to parse a RSA private key.
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
}
I am tring to generate dkim key using golang, my current code is :
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/gob"
"encoding/pem"
"fmt"
"os"
)
func Keymaker(path string) {
reader := rand.Reader
bitSize := 2048
key, err := rsa.GenerateKey(reader, bitSize)
checkError(err)
publicKey := key.PublicKey
//saveGobKey("private.key", key)
savePEMKey(path+".priv", key)
//saveGobKey("public.key", publicKey)
savePublicPEMKey(path+".pub", publicKey)
}
func savePEMKey(fileName string, key *rsa.PrivateKey) {
outFile, err := os.Create(fileName)
checkError(err)
defer outFile.Close()
var privateKey = &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}
err = pem.Encode(outFile, privateKey)
checkError(err)
}
func savePublicPEMKey(fileName string, pubkey rsa.PublicKey) {
asn1Bytes, err := asn1.Marshal(pubkey)
checkError(err)
var pemkey = &pem.Block{
Type: "PUBLIC KEY",
Bytes: asn1Bytes,
}
pemfile, err := os.Create(fileName)
checkError(err)
defer pemfile.Close()
err = pem.Encode(pemfile, pemkey)
checkError(err)
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error ", err.Error())
os.Exit(1)
}
}
the code is working, generate the dkim private/public keys, problem is this keys return bad keys by sender, if i generate keys using this site : https://easydmarc.com/tools/dkim-record-generator/ the keys results valid.
this is my dkim settings in dns :
v=DKIM1;t=s;p=MIGJAoGBD1DSPRFFTujiCAiadP9ZeA6eAyf0GktfCQO2WKbrAx2Cu15y2A+agQMWNTmZbbhcznGZiz3kA9y7c0wOqN2iaJchBAxt4qdg1vUhy+6CkSZcY5bdm8uOxsXW3gjOTyZrOur/c118wMTOmSJKHOjn9xLG3ta8tXJtqab8idtx4TlBAgMBAAE=
i try to understend way keys generated by easydmarc.com working, and golang keys not working. Any ideea ?
I met this issue and really do not know how to resolve it, can anyone help to provide a working solution?
func GenerateJWT(name, role string) (string, error) {
//create a singner for rsa 256
claims := &jwt.StandardClaims{
ExpiresAt: 15000,
Issuer: "test",
}
token :=jwt.NewWithClaims(jwt.SigningMethodES256, claims)
log.Println("generated toke is ")
log.Println(token)
tokenString, err := token.SignedString([]byte("secret"))
....
}
Now I am alway having:
key is of invalid type
error. I google a lot, and even for jwt-go library it self, they are providing exactly same solution, but why I kept having the
key is of invalid type
error?
Can anyone help to provide a working sample about how to generate jwt token in go?
From the README:
The ECDSA signing method (ES256,ES384,ES512) expect *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for validation
So use an elliptic curve key:
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"log"
jwt "github.com/dgrijalva/jwt-go"
)
func main() {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatal(err)
}
claims := &jwt.StandardClaims{
ExpiresAt: 15000,
Issuer: "test",
}
token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
tokenString, err := token.SignedString(key)
if err != nil {
log.Fatal(err)
}
log.Println(tokenString)
}
To store the generated key for later use with jwt.ParseECPrivateKeyFromPEM and jwt.ParseECPublicKeyFromPEM:
import (
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
)
func pemKeyPair(key *ecdsa.PrivateKey) (privKeyPEM []byte, pubKeyPEM []byte, err error) {
der, err := x509.MarshalECPrivateKey(key)
if err != nil {
return nil, nil, err
}
privKeyPEM = pem.EncodeToMemory(&pem.Block{
Type: "EC PRIVATE KEY",
Bytes: der,
})
der, err = x509.MarshalPKIXPublicKey(key.Public())
if err != nil {
return nil, nil, err
}
pubKeyPEM = pem.EncodeToMemory(&pem.Block{
Type: "EC PUBLIC KEY",
Bytes: der,
})
return
}
I'm using crypto/rsa, and trying to find a way to properly save and load a key. Is there a correct way to create a []byte from an rsa.PrivateKey. If so, is there a way to properly do so for an rsa.PublicKey?
Thank you all very much.
You need some sort of format to marshal the key into. One format supported by the Go standard library can be found here: http://golang.org/pkg/crypto/x509/#MarshalPKCS1PrivateKey
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte
The inverse function is http://golang.org/pkg/crypto/x509/#ParsePKCS1PrivateKey.
func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)
However, it is relatively standard to encode the marshaled key into a PEM file.
pemdata := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
},
)
You can find a full example here.
Here's code snippet that shows the import and export of both public and private keys. It's based on the other answers which were super helpful, as well as copy-pasta from the official docs.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)
func GenerateRsaKeyPair() (*rsa.PrivateKey, *rsa.PublicKey) {
privkey, _ := rsa.GenerateKey(rand.Reader, 4096)
return privkey, &privkey.PublicKey
}
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)
}
func ParseRsaPrivateKeyFromPemStr(privPEM string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(privPEM))
if block == nil {
return nil, errors.New("failed to parse PEM block containing the key")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return priv, nil
}
func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) {
pubkey_bytes, err := x509.MarshalPKIXPublicKey(pubkey)
if err != nil {
return "", err
}
pubkey_pem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubkey_bytes,
},
)
return string(pubkey_pem), nil
}
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() {
// Create the keys
priv, pub := GenerateRsaKeyPair()
// Export the keys to pem string
priv_pem := ExportRsaPrivateKeyAsPemStr(priv)
pub_pem, _ := ExportRsaPublicKeyAsPemStr(pub)
// Import the keys from pem string
priv_parsed, _ := ParseRsaPrivateKeyFromPemStr(priv_pem)
pub_parsed, _ := ParseRsaPublicKeyFromPemStr(pub_pem)
// Export the newly imported keys
priv_parsed_pem := ExportRsaPrivateKeyAsPemStr(priv_parsed)
pub_parsed_pem, _ := ExportRsaPublicKeyAsPemStr(pub_parsed)
fmt.Println(priv_parsed_pem)
fmt.Println(pub_parsed_pem)
// Check that the exported/imported keys match the original keys
if priv_pem != priv_parsed_pem || pub_pem != pub_parsed_pem {
fmt.Println("Failure: Export and Import did not result in same Keys")
} else {
fmt.Println("Success")
}
}
Since the public key part of your question wasn't answered and I just ran into the same problem and solved it, here it is:
Note the & in front of the Argument to MarshalPKIXPublicKey
Priv := rsa.GenerateKey(rand.Reader, 4096)
pubASN1, err := x509.MarshalPKIXPublicKey(&Priv.PublicKey)
if err != nil {
// do something about it
}
pubBytes := pem.EncodeToMemory(&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubASN1,
})
ioutil.WriteFile("key.pub", pubBytes, 0644)
Relevant reads:
MarshalPKIXPublicKey(pub interface{}) ([]byte, error) godoc
EncodeToMemory(b *Block) []byte godoc
Block godoc
PS: MarshalPKIXPublicKey also accepts ECDSA keys, ajust the pem header appropriately.