-
-
Save stuart-warren/93750a142d3de4e8fdd2 to your computer and use it in GitHub Desktop.
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(secretString string) (string, error) { | |
log.Println("Secret to hide:", secretString) | |
log.Println("Public Keyring:", publicKeyring) | |
// 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 | |
bytes, err := ioutil.ReadAll(buf) | |
if err != nil { | |
return "", err | |
} | |
encStr := base64.StdEncoding.EncodeToString(bytes) | |
// Output encrypted/encoded string | |
log.Println("Encrypted Secret:", encStr) | |
return encStr, nil | |
} | |
func decTest(encString string) (string, error) { | |
log.Println("Secret Keyring:", secretKeyring) | |
log.Println("Passphrase:", passphrase) | |
// init some vars | |
var entity *openpgp.Entity | |
var entityList openpgp.EntityList | |
// Open the private key file | |
keyringFileBuffer, err := os.Open(secretKeyring) | |
if err != nil { | |
return "", err | |
} | |
defer keyringFileBuffer.Close() | |
entityList, err = openpgp.ReadKeyRing(keyringFileBuffer) | |
if err != nil { | |
return "", err | |
} | |
entity = entityList[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") | |
entity.PrivateKey.Decrypt(passphraseByte) | |
for _, subkey := range entity.Subkeys { | |
subkey.PrivateKey.Decrypt(passphraseByte) | |
} | |
log.Println("Finished decrypting private key using passphrase") | |
// Decode the base64 string | |
dec, err := base64.StdEncoding.DecodeString(encString) | |
if err != nil { | |
return "", err | |
} | |
// Decrypt it with the contents of the private key | |
md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entityList, nil, nil) | |
if err != nil { | |
return "", err | |
} | |
bytes, err := ioutil.ReadAll(md.UnverifiedBody) | |
if err != nil { | |
return "", err | |
} | |
decStr := string(bytes) | |
return decStr, nil | |
} | |
func main() { | |
encStr, err := encTest(mySecretString) | |
if err != nil { | |
log.Fatal(err) | |
} | |
decStr, err := decTest(encStr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// should be done | |
log.Println("Decrypted Secret:", decStr) | |
} |
use openpgp.ReadArmoredKeyRing instead of openpgp.ReadKeyRing if you exported your gpg keys with --armor
thanks mates, now it finally works for me too..
If you have created your keyring with gnupg >=v2 you need to export the secret keys e.g. with
$ gpg --no-default-keyring --keyring ./ring.gpg --export-secret-keys > secret-key.gpg
$ file secret-key.gpg
secret-key.gpg: PGP Secret Key - 2048b created on Thu Jan 9 01:46:30 2020 - RSA (Encrypt or Sign) e=65537 hashed AES with 128-bit key Salted&Iterated S2K SHA-1
🤦♂️
I believe the url has changed for the openpgp package to golang.org/x/crypto/openpgp
Awesome code snippet! Only comment was for anyone referencing this code to decrypt something other than a string, such as a big encrypted file. It would be safer and might save you a ton of time debugging if you read in the decrypted string using _, err := ioutil.copy(decryptWriter, md.UnverifiedBody)
instead of bytes, err := ioutil.ReadAll(md.UnverifiedBody)
Thanks, this gist works! I had struggled a bit with generation of secring.gpg
and pubring.gpg
, though.
To generate throwaway keys for experiments, following commands can be used generate a new key in .gnupg
as subdirectory of the current directory, and .gnupg/secring.gpg
and .gnupg/pubring.gpg
keyrings:
gpg --gen-key --homedir .gnupg
gpg --no-default-keyring --homedir ./.gnupg/ --export-secret-keys > ./.gnupg/secring.gpg
gpg --no-default-keyring --homedir ./.gnupg/ --export > ./.gnupg/pubring.gpg
Thanks, how about if I want to support dual keys?
Keys should be in binary NOT in base64, otherwise you'll get
tag byte does not have MSB set
error.