Load encrypted PKCS1 private key from file - go

I have a PKCS1 private key in a file and I load it using
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
Then, I try to convert it into private key object
block, _ := pem.Decode(b)
der, err := x509.DecryptPEMBlock(block, []byte("qwerty"))
if err != nil {
return nil, err
}
bytes := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: der})
return x509.ParsePKCS1PrivateKey(bytes)
But this code throws exception in DecryptPEMBlock
x509: no DEK-Info header in block
I didn't find any documentation about this in golang

I made a mistake with my private key file and here is a working code
func GetPrivateKey(path string) (*rsa.PrivateKey, error) {
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
block, _ := pem.Decode(b)
der, err := x509.DecryptPEMBlock(block, []byte(*PrivateKeyPassword))
if err != nil {
return nil, err
}
return x509.ParsePKCS1PrivateKey(der)
}
P.S. Go does have a package to decrypt PKCS1 private keys, but does not have for PKCS8.

Go does not have package to decode PKCS files it seems
Checkout this link for more details PKCS
I cant find a package to decode PKCS1 keys
Use this package to decode the PKCS8 files, there are some packages to decode PKCS8, PKCS10, PKCS12 but not for PKCS1

Related

How to write *PrivateKey type variable to a file in golang? [duplicate]

This question already has answers here:
Save and load crypto/rsa PrivateKey to and from the disk
(3 answers)
Use golang to get RSA key the same way openssl genrsa
(1 answer)
Closed 4 months ago.
I have generated a RSA private key (using crypto/rsa) and corresponding public key in go. Now I want to write them to two files (each one to a file), but WriteString and Write functions are specific to string and []byte variable. Also instructions like String(privateKey) generate error. How I can write these keys to the files?
You would need pem.Encode. An example can be seen in maplepie/rsa#savePrivateKey():
func (p *PemKey) savePrivateKey(privateKey *rsa.PrivateKey, filename string) error {
raw := x509.MarshalPKCS1PrivateKey(privateKey)
block := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: raw,
}
file, err := os.Create(filename)
if err != nil {
return err
}
err = pem.Encode(file, block)
if err != nil {
return err
}
return nil
}
Same idea for public key:
func (p *PemKey) savePublicKey(publicKey *rsa.PublicKey, filename string) error {
raw, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return err
}
block := &pem.Block{
Type: "PUBLIC KEY",
Bytes: raw,
}
file, err := os.Create(filename)
if err != nil {
return err
}
err = pem.Encode(file, block)
if err != nil {
return err
}
return nil
}

How to check pkcs format of a private key using golang code?

I am trying find the encryption format of a private key whether it is pkcs1 or pkcs8. Is there any golang code that helps me identify it
func main() {
pemString := `-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,1ADE9ED351F5B8C7
z8nRX5jG2eUxcahgzF/Sn47DWXKs/y+pOcyYzTA3eBYwkqnjOzSqK9YbV8irAAZm
uwwoGBCjn7740nCo+pEYe+ECC4MJBrAl6uPcX6eL0ltj1En5gqFB6bPqFrVa8uuf
MDoSGJzIcDl9kuLK4xS0q9TE7K5ayrzfn7ecn6/KHjqgIdGtEsrZT1Ajhm6Quubs
PhCRTldky/o1LegEoooUm2s509EGX2PixAWfTS36Z3UENOSWAgHJCdfybDR7+jvP
lC9ZHXD/OVcgDVC+K3UjF7kV5HMD+CosuCwR6oXHEiKGv6X6rW46wyB17ul/zDA5
6MbQeEDDE3uEa+cpAGzeYwudCRttclsBlLKBDHv2DgjI+yoGU/GuwuV5Gd9y4fYw
5ZakGhezbm9W5g4XiuA3wTM9j4x2hNIB2Bexu8b9KlZwJnXZOY8glDcfdT5+kmQL
CY4LlqZQU/YXFLoGpChidQmIQhxzVsYRx46NK0l+hrrJJ2xGz+Cj5AhqomOjq69y
5AAjL3THAj1ys2dy54Ue1m1T4w12Oz+fAICVC2mb966821cUjkSzC2QVGqE+UdrS
C9qaMtBvKxumN/88Pl3SsO1tDpgSG4OTcr+Hyeh20fg3wVnFPZJZyWDVnv4cXrVs
SYAk7m3ngAvr+XOu8WOdOc8ouuiWlaFhKNpGC6MZT1FKCCD53VANeehdBbYngmrR
oZAuQBtS1aJpMpP2zcsXcexcuZrHSdVlaU1Cs3JykIXt1kmJDKAcyz1C8dRA23fI
QlP3Q+lbohQpWdS8hSDhetxUaCYHIYHJL3fp/0hsOWrd2oJ7ukNBEPIaEK9FnKHe
nrAp6spTrtCAFum6UAqiV6eoAyX2SwIJepPivgxcquA7rIeO/D4OZCHRsQtLMFPn
FG7KYJ0ZcAincs5AKX67hxrZBLt1VvjvqyifdhFEJoCI0vwza1Q9tFtrkJ4dXr5W
n5wnS8dSZnin9JWYCf1ltxVwPNxlii1jwYmIKM49D3qcmSsKsWNNrAW/nvrkOP0R
CasZKUGgpYu6cu0T1JYayZyb5gWjawDUkZpdd0E/RS/xk5qvJ6jrcu8QoiOo0s+f
EizdBvhiLuA6SNWHj/ksXf3seTTdHxDdG91iea5t+vK1ZJoJC9PTxB18ws6BALCH
3DGXBo1vdoz7HVTq0YeTwavzhY9l3UYPcNeM6+blEuy7S0p5OoavVevynKXp+/Ct
gsODMh6Xhz1kjPIDfvuA36HJiB84FGED6d2s+7MOTh/z7p5d1OfUMu+0IsyDR6Un
p17G82ihgZlE9MbJVnAGSpUPQd6gmtdFh7jgu2S7SYqph5P6s/aVlZsH36xVgdRG
3pdo+7qhuWulBwN9dsdSigy0CLAOiGJAU3Pxu1QdKiwE+/Qs6LmLRkLWbd4S42N2
Ur1xwXiBC8Qz35JZpE6+MyvR4jUybSC6IMhWPHrpQ2sVw6HFlRvPN78egO9zuO6v
UTqL30g3J5+SS+ulLm16xwRgBAiLBYgvDLpfsQB3G3rShOyiNvvOneGZ8FZIerpB
RVpv18PvAvhFICyUuxVkvTm6j1BObmMvoefPOUWeZHsE+Miu/N2UoQ==
-----END RSA PRIVATE KEY-----`
block, _ := pem.Decode([]byte(pemString))
_, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
fmt.Println(err)
fmt.Println("hi")
} else {
fmt.Println("bye")
}
}
asn1: structure error: length too large
hi
Just parse the key, err comes if mismatch.
func pkcs() {
var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031`
derBytes, _ := hex.DecodeString(pkcs8RSAPrivateKeyHex)
_, err := x509.ParsePKCS1PrivateKey(derBytes)
if err != nil {
log.Fatalln(err)
return
}
}
2022/08/10 15:59:08 x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)
EDIT:
For encrypted private key, need to decrypt first:
bytes, err := x509.DecryptPEMBlock(block, []byte("password"))
if err != nil {
log.Fatalln(err)
return
}
_, err = x509.ParsePKCS1PrivateKey(bytes)

Golang crypto/rsa problem decrypting text using private key from PEM file

So i'm building a basic generator/encryptor/decryptor for RSA keys in Golang.
I have four main functions.
GenKeys() generates the key pair using rsa.GenerateKey, then writes this private key to a pem file.
GetKeys() Gets the private key from the pem file.
Encrypt() Encrypts a string manually entered into the console and then spits out the ciphertext
Decrypt() Takes in the cipher text and decrypts it, using the GetKeys function to get the private key from the pem file.
The GenKeys function works fine. And the Encrypt function works fine. Entering a string and spitting out a cipher text.
But I get crypto/rsa: decryption error when I run the decrypt flag.
Tried:
The private key is identical when I gen the key to when i Import it again from the pem file.
Ive tried the different decryption methods included in the crypto package.
I've tried just importing the ciphertext directly from the encrypt method into the decrypt, just in case there was a problem when spitting it out to console.
To note:
This worked when I only wrote the private key to memory, instead of spitting it out to a file, which tells me that something is going wrong when importing the key again from the pem file. But I cant figure out what.
Please if somebody could look through my code and tell me if im missing something I'd be eternaly grateful.
main.go
func main() {
var action = flag.String("action", "", "Whether to decrypt or encrypt")
flag.Parse()
task := *action
var err error
if task == "gen" {
//gen the priv key and write to file
err = services.GenKeys()
if err != nil {
fmt.Println("Could not generate keys:", err)
}
}
if task == "encrypt" {
//Get key from file
privateKey, err := services.GetKeys()
if err != nil {
fmt.Println("Could not retrieve key file", err)
return
}
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter the text you would like to encrypt: ")
text, _ := reader.ReadString('\n')
cipherText, err := services.Encrypt(&privateKey.PublicKey, text)
if err != nil {
fmt.Println("Could not encrypt", err)
return
}
fmt.Printf("Encrypted message: %x", cipherText)
}
if task == "decrypt" {
//Get key from file
privateKey, err := services.GetKeys()
if err != nil {
fmt.Println("Could not retrieve key file", err)
}
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter the cypher text you would like to decrypt: ")
text, _ := reader.ReadString('\n')
decryptedText, err := services.Decrypt(privateKey, []byte(text))
if err != nil {
fmt.Println("Could not decrypt text", err.Error())
return
}
fmt.Println("decrypted text: ", string(decryptedText))
}
}
crypto_service.go
func Encrypt(pub *rsa.PublicKey, text string) ([]byte, error) {
encryptedBytes, err := rsa.EncryptOAEP(
sha256.New(),
rand.Reader,
pub,
[]byte(text),
nil)
if err != nil {
return nil, err
}
return encryptedBytes, nil
}
func Decrypt(privKey *rsa.PrivateKey, cipherText []byte) ([]byte, error) {
decryptedBytes, err := rsa.DecryptOAEP(sha256.New(), nil, privKey, cipherText, nil)
if err != nil {
return nil, err
}
return decryptedBytes, nil
}
gen_keys_service.go
func GenKeys() error {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
privFile, err := os.Create("private_key.pem")
if err != nil {
return err
}
pemData := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privKey),
}
err = pem.Encode(privFile, pemData)
if err != nil {
return err
}
privFile.Close()
fmt.Println("Your keys have been written to private_key.pem")
return nil
}
func GetKeys() (*rsa.PrivateKey, error) {
file, err := os.Open("private_key.pem")
if err != nil {
return nil, err
}
defer file.Close()
//Create a byte slice (pemBytes) the size of the file size
pemFileInfo, _ := file.Stat()
var size = pemFileInfo.Size()
pemBytes := make([]byte, size)
//Create new reader for the file and read into pemBytes
buffer := bufio.NewReader(file)
_, err = buffer.Read(pemBytes)
if err != nil {
return nil, err
}
//Now decode the byte slice
data, _ := pem.Decode(pemBytes)
if data == nil {
return nil, errors.New("could not read pem file")
}
privKeyImport, err := x509.ParsePKCS1PrivateKey(data.Bytes)
if err != nil {
return nil, err
}
return privKeyImport, nil
}
Oh and heres the format of my pem file:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEApX2AUrhtH3FHSds3JAWmBDZcSwixydY/M52WmWfqDmQDRc6X
V4FqLyiEIMSq3Z7zOR9GH4a2Ps3HPlTvJa2EGkgKDk7hVRWlocbQvRsdSk/aEZ7U
O0SgB6s0H2/9MdWsXaJHADuUJYlSgG+VH7vf5uIi4w8OKNfmHfB7uJQJByb4+8jg
rzMFgmFyEUnWOgUh3dXtdV1XD5BPQiDk2D8vYR8JUjK9uWHVMaR2y51uK3vNZHmR
/ce1g36Gzhl5aRfUqJ8gWLCsJ42VEDHznz04YvrH/DRrcuSb/65JlpQMOKr9wdf/
/sILXkeEylifeZoUENRbgIz5UCyyQtTrfCMcDwIDAQABAoIBAQCBVx41CKlY2rsh
0TA+eh+vySDHECuMGWPaHn92tE2tI6OfKoEERkRMSTlDNxJoFfP4oCW5PBsx6Lih
UdZ7Nys5MzaQyju4uStzziSUuB1jWBeSj/VFwTPl6nvZWjike2C06cDeQLJfx/zw
HsWJQNgU5obnuXuSlnLm0W6Q6zpHGH/GdtS6O5kLjLySgb87xDTivdKEH5iqUNRe
fs6WTJpsKsT92lT/AcO/QUuw7sK/GSW2spnzO8xF4ZdQhjj72NkWqa/K/ncfKhuk
eI/+1HPvSru+nOJts6j3Xd98EQbIDBVZLArl6gB49B6UsEogAYgRJAs5mIIHzxRS
YfiQckzRAoGBAMijQPc+ygZ9pTNLOCi7zHQtHHOj8lMGuqQKTFsDIxVGI7Iy6tm/
CQbbpZiQiDoskCSJq3pWcydu+csDmdq/PrTJ4yuJMAgUaOItvuNu5vS3nOGPiJBl
0zDERW2GA0jcE4STreVM5GR3kOgNG8EIbmjVC1eQqhKK7a0+kPbYqYBnAoGBANMn
e6VcmL19WNIEYHyXLdCOaPj7LOMmAA2SNRA7V4YkaXbgRSHmnHboHEVzytSJH9gY
mmZ9+8dkq9n+ODi1vn2hCR9TIJHapn8aWHOqgnZesJ2xThV78S8Kp8jZD4lx8Ejy
5t3TMVIZ6hQXWfkQjpKs3QAXJszrZR0Cb0sJOp4ZAoGAVb3mmoKbxXBWc/g2NLok
4pUQrp6mhTK/+jBodxB9Iq9Ju/KkiI9qJSMivnMttGas5uBqhqqBJZ34Y/jS/Dd0
bcBFM6q5+wn11IqmI/2V94isI3y6aLMLMLD/1pFJwA5EzQhrbS2SARlTtMc9UB3x
SR2abj5lX+09KycsvkDTFwsCgYEAhG4b509W4GlQHo/uL9XlPwtCHP3zXhdEKz7K
lv6Q2ynVF2B7G1L2SME0kf6YdIn39eEgXS2gjqK+AX+mpTKfYU1xWjsZj0CR8d+F
IC4Nms2yeYRtU54jWvyU1KwGSY6zRB1L3E4LfdGQ9L7ciA/xS16tUNQ0Wos8JGCV
inskT2kCgYBg4zzkUAmQ75hlRsM0r7ezrx4xt8GHrlxwOTeQYgVcymiSSMXVITNI
ByBfs+wqV7PrXjM69xPdV/CHczFcA7g/M0o0CJZhWead403knjZmGFlZypvWskOT
aK4nArJ0zaS7FGhCe24QORYZPGjCzg7dLKhKDvK1PB4ogRVo4dDckA==
-----END RSA PRIVATE KEY-----
In the encryption part the ciphertext is displayed hex encoded. If it is entered hex encoded in the decryption part, it must be hex decoded accordingly, which is missing in the posted code. The hex decoding can be done with the hex package.
Also, as mentioned in Peter's comment, the trailing newline must be removed, e.g. with strings.TrimSuffix(). Alternatively, fmt.Scan() or bufio.Scanner can be used instead of bufio.Reader. The last two options do not return the trailing newline.
Possible implementation (for simplicity without exception handling):
...
var text string
fmt.Println("Please enter the ciphertext you would like to decrypt: ")
fmt.Scan(&text)
textHexDec, _ := hex.DecodeString(text)
decryptedText, _ := Decrypt(privateKey, textHexDec)
fmt.Println("Decrypted text: ", string(decryptedText))
...

Encrypting/Decrypting JWE with Jose in Go

I'm trying to create a JWE decryption function but having trouble determining how to use the Go Jose interface for doing so. I've factored the encryption using passphrase (I prefer a passphrase for this use case):
token := jwt.NewWithClaims(
jwt.SigningMethodHS256,
claims,
)
ss, err := token.SignedString("thisisatestpassphraserighthere")
if err != nil {
panic("COULD_NOT_GENERATE")
return
}
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
encrypter, err := jose.NewEncrypter(
jose.A128CBC_HS256,
jose.Recipient{Algorithm: jose.RSA_OAEP, Key: publicKey},
nil,
)
if err != nil {
return
}
object, err := encrypter.Encrypt([]byte(ss))
if err != nil {
errRes = s.Error(codes.Internal, err, nil)
return
}
key, err := object.CompactSerialize()
if err != nil {
errRes = s.Error(codes.Internal, err, nil)
return
}
fmt.Println(key)
The above code creates a JWT, encodes it, compacts it and returns the key. It's not however totally clear how to decrypt it with the passphrase now.
There is an example for JWE on the Jose docs: https://godoc.org/gopkg.in/square/go-jose.v2#example-Encrypter--Encrypt
So I've factored this:
object, err = jose.ParseEncrypted(Key)
if err != nil {
panic(err)
}
decrypted, err := object.Decrypt(...)
Inside the ellipses I'm not sure what to put though. I can't seem to determine how to pass in a key based on passphrase.
I was doing a few things wrong it seems. First of all rsa.GenerateKey uses a randomized value. This was totally wrong :-p the following is how you can encrypt a JWT into a JWE using a token:
rcpt := jose.Recipient{
Algorithm: jose.PBES2_HS256_A128KW,
Key: "mypassphrase",
PBES2Count: 4096,
PBES2Salt: []byte{ your salt... },
}
enc, err := jose.NewEncrypter(jose.A128CBC_HS256, rcpt, nil)
if err != nil {
panic("oops")
}
jewPlaintextToken, err := enc.Encrypt(jwtToken)
if err != nil {
panic("oops")
}
key, err := object.CompactSerialize()
if err != nil {
panic("oops")
}
This is how you decrypt:
// Decrypt the receive key
jwe, err := jose.ParseEncrypted(jewPlaintextToken)
if err != nil {
panic("oops")
}
decryptedKey, err := jwe.Decrypt("mypassphrase")
if err != nil {
panic("oops")
}
If anyone sees any major problems/security issues with this method, please mention it.
Inside the ellipses I'm not sure what to put though. I can't seem to determine how to pass in a key based on passphrase.
From the JWE example in the documentation, you must pass the private key. See the below part for decryption
https://godoc.org/gopkg.in/square/go-jose.v2#JSONWebEncryption.Decrypt
// Generate a public/private key pair to use for this example.
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// Parse the serialized, encrypted JWE object. An error would indicate that
// the given input did not represent a valid message.
object, err = ParseEncrypted(serialized)
if err != nil {
panic(err)
}
// Now we can decrypt and get back our original plaintext. An error here
// would indicate the the message failed to decrypt, e.g. because the auth
// tag was broken or the message was tampered with.
decrypted, err := object.Decrypt(privateKey)
if err != nil {
panic(err)
}
fmt.Printf(string(decrypted))

unstable decryption, sometimes got cipher: message authentication failed

I'm trying to create E2E Encryption for my software, but the decryption are very unstable, sometime can successfully decrypt, sometime got cipher: message authentication failed, here's my encrypt & decrypt code
func Encrypt(data []byte, passphrase string) ([]byte, error) {
// create aes.NewCipher from hashed md5 passphrase
block, _ := aes.NewCipher([]byte(createHash(passphrase)))
// NewGCM returns the given 128-bit, block cipher wrapped in
// Galois Counter Mode with the standard nonce length.
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
// initialize slice with length of nonce that must be passed to Seal and Open.
nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}
ciphertext := gcm.Seal(nonce, nonce, data, nil)
return ciphertext, nil
}
func Decrypt(data []byte, passphrase string) ([]byte, error) {
// create md5 byte slice
key := []byte(createHash(passphrase))
// just `reverse` algorithm with passphrase until return
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
the encrypted binary value are transferred via http :
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
decrypt, err := Decrypt(body, r.Passphrase)
what i already try is to check, is ioutil.ReadAll read content correctly, or something wrong with decryptor
sorry, the problem was not in encryption/decryption, but in http server for transferring the chipertext, and already fixes now https://github.com/codenoid/GoTral-Server/commit/493c7f654753cae36f074c1c5f382953e227d295

Resources