So I'm pretty new to golang and i'm struggling to get a working example going of encrypting some text with openpgp and decrypting it again.
Here is what I have so far: (https://gist.github.com/93750a142d3de4e8fdd2.git)
package main
import (
"log"
"bytes"
"code.google.com/p/go.crypto/openpgp"
"encoding/base64"
"io/ioutil"
"os"
)
// create gpg keys with
// $ gpg --gen-key
// ensure you correct paths and passphrase
const mysecretstring = "this is so very secret!"
const secretKeyring = "/Users/stuart-warren/.gnupg/secring.gpg"
const publicKeyring = "/Users/stuart-warren/.gnupg/pubring.gpg"
const passphrase = "1234"
func main() {
log.Printf("Secret: ", mysecretstring)
log.Printf("Secret Keyring: ", secretKeyring)
log.Printf("Public Keyring: ", publicKeyring)
log.Printf("Passphrase: ", passphrase)
// Read in public key
keyringFileBuffer, _ := os.Open(publicKeyring)
defer keyringFileBuffer.Close()
entitylist, _ := openpgp.ReadKeyRing(keyringFileBuffer)
// encrypt string
buf := new(bytes.Buffer)
w, _ := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
w.Write([]byte(mysecretstring))
// Encode to base64
bytesp, _ := ioutil.ReadAll(buf)
encstr := base64.StdEncoding.EncodeToString(bytesp)
// Output encrypted/encoded string
log.Printf("Encrypted Secret: ", encstr)
// Here is where I would transfer the encrypted string to someone else
// but we'll just decrypt it in the same code
// init some vars
var entity2 *openpgp.Entity
var entitylist2 openpgp.EntityList
// Open the private key file
keyringFileBuffer2, _ := os.Open(secretKeyring)
defer keyringFileBuffer2.Close()
entitylist2, _ = openpgp.ReadKeyRing(keyringFileBuffer2)
entity2 = entitylist2[0]
// Get the passphrase and read the private key.
// Have not touched the encrypted string yet
passphrasebyte := []byte(passphrase)
log.Printf("Decrypting private key using passphrase")
entity2.PrivateKey.Decrypt(passphrasebyte)
for _, subkey := range entity2.Subkeys {
subkey.PrivateKey.Decrypt(passphrasebyte)
}
log.Printf("Finished decrypting private key using passphrase")
// Decode the base64 string
dec, _ := base64.StdEncoding.DecodeString(encstr)
// Decrypt it with the contents of the private key
md, _ := openpgp.ReadMessage(bytes.NewBuffer(dec), entitylist2, nil, nil)
bytess, _ := ioutil.ReadAll(md.UnverifiedBody)
decstr := string(bytess)
// should be done
log.Printf("Decrypted Secret: ", decstr)
}
This is based off of https://github.com/jyap808/jaeger
When I run it, it seems to partially work, but only outputs some of the characters of the original string... Changing the original string causes some very weird issues.
2014/09/07 22:59:38 Secret: %!(EXTRA string=this is so very secret!)
2014/09/07 22:59:38 Secret Keyring: %!(EXTRA string=/Users/stuart-warren/.gnupg/secring.gpg)
2014/09/07 22:59:38 Public Keyring: %!(EXTRA string=/Users/stuart-warren/.gnupg/pubring.gpg)
2014/09/07 22:59:38 Passphrase: %!(EXTRA string=1234)
2014/09/07 22:59:38 Encrypted Secret: %!(EXTRA string=wcBMA5a76vUxixWPAQgAOkrt/LQ3u++VbJ/20egxCUzMqcMYtq+JXL7SqbB5S1KrgHhGd8RHUmxy2h45hOLcAt+kfvSz0EJ/EsCmwnbP6HRPEqiMLt6XaVS26Rr9HQHPpRBZkqnwAP0EmlYNnF5zjnU5xTcEOyyr7EYhEgDv0Ro1FQkaCL2xdBhDCXs4EdQsjVrcECWOt0KgbCWs+N/0cEdeyHwodkaDgJ7NMq/pPuviaRu4JHCIxMiyz8yhOCHOM+bI80KsJesjGrgbjnGDfJUZNYDBNc8PqzfC39lB2MBrn/w07thJxvjbep39R0u2C4eEcroTRLB+t9i4fJNiVpoSclYRSZXm5OsYYv/XwtLgAeRZ07lFEsGoHSbqGLUnHFFw4Svk4FPgCuGVpOCS4vYiisDg+ORYj8dpu/Z3gSlVJ6mhSr7H4J3i9vItRuBx4WUB4HHgmQ==)
2014/09/07 22:59:38 Decrypting private key using passphrase
2014/09/07 22:59:38 Finished decrypting private key using passphrase
2014/09/07 22:59:38 Decrypted Secret: %!(EXTRA string=this)
Clearly there is something I'm not understanding, so would appreciate any assistance given.
A reminder that security is unusually treacherous territory, and if there's a way to call on other well-tested code even more of your toplevel task than just what Go's OpenPGP package is handling for you, consider it. It's good that at least low-level details are outsourced to openpgp
because they're nasty and so so easy to get wrong. But tiny mistakes at any level can make crypto features worse than useless; if there's a way to write less security-critical code, that's one of the best things anyone can do for security.
On the specific question: you have to Close()
the writer to get everything flushed out (a trait OpenPGP's writer shares with, say, compress/gzip
's).
Unrelated changes: the way you're printing things is a better fit log.Println
, which just lets you pass a bunch of values you want printed with spaces in between (like, say, Python print
), rather than needing format specifiers like "%s"
or "%d"
. (The "EXTRA" in your initial output is what Go's Printf
emits when you pass more things than you had format specifiers for.) It's also best practice to check errors (I dropped if err != nil
s where I saw a need, but inelegantly and without much thought, and I may not have gotten all the calls) and to run go fmt
on your code.
Again, I can't testify to the seaworthiness of this code or anything like that. But now it round-trips all the text. I wound up with:
package main
import (
"bytes"
"code.google.com/p/go.crypto/openpgp"
"encoding/base64"
"io/ioutil"
"log"
"os"
)
// create gpg keys with
// $ gpg --gen-key
// ensure you correct paths and passphrase
const mysecretstring = "this is so very secret!"
const prefix, passphrase = "/Users/stuart-warren/", "1234"
const secretKeyring = prefix + ".gnupg/secring.gpg"
const publicKeyring = prefix + ".gnupg/pubring.gpg"
func encTest() error {
log.Println("Secret:", mysecretstring)
log.Println("Secret Keyring:", secretKeyring)
log.Println("Public Keyring:", publicKeyring)
log.Println("Passphrase:", passphrase)
// Read in public key
keyringFileBuffer, _ := os.Open(publicKeyring)
defer keyringFileBuffer.Close()
entitylist, err := openpgp.ReadKeyRing(keyringFileBuffer)
if err != nil {
return err
}
// encrypt string
buf := new(bytes.Buffer)
w, err := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
if err != nil {
return err
}
_, err = w.Write([]byte(mysecretstring))
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
// Encode to base64
bytesp, err := ioutil.ReadAll(buf)
if err != nil {
return err
}
encstr := base64.StdEncoding.EncodeToString(bytesp)
// Output encrypted/encoded string
log.Println("Encrypted Secret:", encstr)
// Here is where I would transfer the encrypted string to someone else
// but we'll just decrypt it in the same code
// init some vars
var entity2 *openpgp.Entity
var entitylist2 openpgp.EntityList
// Open the private key file
keyringFileBuffer2, err := os.Open(secretKeyring)
if err != nil {
return err
}
defer keyringFileBuffer2.Close()
entitylist2, err = openpgp.ReadKeyRing(keyringFileBuffer2)
if err != nil {
return err
}
entity2 = entitylist2[0]
// Get the passphrase and read the private key.
// Have not touched the encrypted string yet
passphrasebyte := []byte(passphrase)
log.Println("Decrypting private key using passphrase")
entity2.PrivateKey.Decrypt(passphrasebyte)
for _, subkey := range entity2.Subkeys {
subkey.PrivateKey.Decrypt(passphrasebyte)
}
log.Println("Finished decrypting private key using passphrase")
// Decode the base64 string
dec, err := base64.StdEncoding.DecodeString(encstr)
if err != nil {
return err
}
// Decrypt it with the contents of the private key
md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entitylist2, nil, nil)
if err != nil {
return err
}
bytess, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
return err
}
decstr := string(bytess)
// should be done
log.Println("Decrypted Secret:", decstr)
return nil
}
func main() {
err := encTest()
if err != nil {
log.Fatal(err)
}
}