-
-
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) | |
} |
Keys should be in binary NOT in base64, otherwise you'll get tag byte does not have MSB set
error.
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?
"code.google.com/p/go.crypto/openpgp"
changed to
"golang.org/x/crypto/openpgp"