RSA Key Export and Import - go

I'm currently trying to export my created keys and than importing them to use them.
But if I run my code I get the following error:
panic: x509: only RSA and ECDSA public keys supported
goroutine 1 [running]:
main.main()
/path/to/project/src/main.go:19 +0x3bd
This is my current code:
// Create key
key, _ := rsa.GenerateKey(rand.Reader, 2048)
// Message to encrypt
message := "hi stackoverflow"
priv := x509.MarshalPKCS1PrivateKey(key)
pub, err := x509.MarshalPKIXPublicKey(key.PublicKey)
if err != nil {
panic(err)
}
private, err := x509.ParsePKCS1PrivateKey(priv)
if err != nil {
panic(err)
return
}
public, err := x509.ParsePKIXPublicKey(pub)
if err != nil {
return
}
encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, public.(*rsa.PublicKey), []byte(message))
if err != nil {
panic(err)
}
dencrypted, err := rsa.DecryptPKCS1v15(rand.Reader, private, encrypted)
if err != nil {
panic(err)
}
fmt.Println(string(dencrypted))
(I researched like the hole internet but didn't found something, maybe I used a wrong search term.)

When I run this, I get the panic on MarshalPKIXPublicKey (not ParsePKIXPublicKey as you were suggesting in comment above).
The problem is that the function accepts a *rsa.PublicKey and you're passing a plain rsa.PublicKey.
This works for me: pub, err := x509.MarshalPKIXPublicKey(&key.PublicKey).

Related

Getting Cipher Message Authentication Failed

I am creating a middleware function to decrypt the request body of an api call but cannot seem to get it working. The body is encrypted and then base64 encoded before the request is made. Any help would be appreciated.
My curent function code:
ciphertext, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err.Error())
}
ciphertext = decodeBase64(string(ciphertext))
block, err := aes.NewCipher(keyString)
if err != nil {
panic(err.Error())
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
nonce := make([]byte, aesgcm.NonceSize())
clearStuff := make([]byte, len(ciphertext))
plaintext, err := aesgcm.Open(clearStuff, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}
fmt.Println(string(plaintext))
The key is:
var keyString = []byte("ECB518652A170880555136EA1F9752D6")
The error im getting is:
cipher: message authentication failed []
I'm pretty sure that the issue is stemming from ciphertext but I haven't been able to find a solution to the problem. I found a working solution here, but its using the seal to decrypt and that won't be possible in my case. So how can I get this done?

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

Decrypting a non ASCII armored PGP file in Go

Is it possible to decrypt binary .PGP file with Go's "golang.org/x/crypto/openpgp" library?
The following code works with an armored ASCII encoded file but throws EOF error with a binary PGP file. Is there a similar function to armor.Decode() that allows for the binary file to be decrypted?
func DecryptFile(encryptedFilePath string, decryptedFilePath string) error {
pubKey := decodePublicKey()
privKey := decodePrivateKey()
entity := createEntityFromKeys(pubKey, privKey)
file := readFile(encryptedFilePath)
block, err := armor.Decode(file)
if err != nil {
log.Printf("Error reading OpenPGP Armor: %s", err)
return err
}
if block.Type != "Message" {
log.Println("Invalid message type")
return err
}
var entityList openpgp.EntityList
entityList = append(entityList, entity)
messageDetails, err := openpgp.ReadMessage(block.Body, entityList, nil, nil)
if err != nil {
log.Printf("Error reading message: %s", err)
return err
}
compressed, err := gzip.NewReader(messageDetails.UnverifiedBody)
if err != nil {
log.Printf("Invalid compression level: %s", err)
return err
}
defer compressed.Close()
buffer := bytes.NewBuffer(nil)
n, err := io.Copy(buffer, compressed)
if err != nil {
log.Printf("Error reading encrypted file: %s", err)
return err
}
err = ioutil.WriteFile(decryptedFilePath, buffer.Bytes(), 0644)
if err != nil {
log.Println(err)
return err
}
log.Printf("Decrypted %d bytes\n", n)
return nil
}
I encountered the same exact problem with PGP, also got EOF on my first trial.
The encrypted file is in binary(.pgp)
The private/public key in key ring armored file(.asc) like this:
----BEGIN PGP PUBLIC KEY BLOCK-----
-----END PGP PRIVATE KEY BLOCK-----
Here is the code that I use:
keyRing, err := os.Open("keyArmoredFile.asc")
if err != nil {
log.Fatal(err)
}
entityList, err := openpgp.ReadArmoredKeyRing(keyRing)
if err != nil {
log.Fatal(err)
}
entity := entityList[0]
passphraseByte := []byte("password")
err = entity.PrivateKey.Decrypt(passphraseByte)
if err != nil {
log.Fatal(err)
}
for _, subkey := range entity.Subkeys {
subkey.PrivateKey.Decrypt(passphraseByte)
}
encryptedContent, err := os.Open("encryptedFile.pgp")
if err != nil {
log.Fatal(err)
}
md, err := openpgp.ReadMessage(encryptedContent, entityList, nil, nil)
if err != nil {
log.Fatal(err)}
bytes, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
log.Fatal(err)
}
// decryption result
decStr := string(bytes)
Reference:
https://gist.github.com/stuart-warren/93750a142d3de4e8fdd2

Golang crypto: encrypted file not prefixed with IV

I am using an IV in cipher.NewOFB, but my encrypted file never gets prefixed with it. I followed the golang examples at https://golang.org/pkg/crypto/cipher/, but can't seem to figure out why the prefix isn't being considered.
Does anyone see what the problem is?
func generateRandomIV(length int) []byte {
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
return iv
}
func encryptFile(filename, keystring string) error {
readFile, err := os.Open(filename)
iv := generateRandomIV(aes.BlockSize)
outFile, err := os.OpenFile(filename+".enc", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
panic(err)
}
defer readFile.Close()
defer outFile.Close()
key := []byte(keystring)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
fmt.Println("IV:", iv)
writer := &cipher.StreamWriter{S: cipher.NewOFB(block, iv), W: outFile}
if _, err := io.Copy(writer, readFile); err != nil {
return err
}
return nil
}
Add the IV prefix yourself or pre-share the IV. If you prefix it you will have the remove it and apply it on decryption.
How an IV is shared is not part of the encryption standard, it is a developer choice. Prefixing the IV is common but not required or the only way, it is however a good choice.

Resources