Skip to content

Instantly share code, notes, and snippets.

@charger
Created March 3, 2023 08:47
Show Gist options
  • Save charger/4b054f90fb9fa648177a9355418c4685 to your computer and use it in GitHub Desktop.
Save charger/4b054f90fb9fa648177a9355418c4685 to your computer and use it in GitHub Desktop.
Example how encrypt/decrypt text with private GPG key using password stored in a file (to not store password in source code), and encode/decode with Base64Url.
package main
import (
"bytes"
"encoding/base64"
"fmt"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/packet"
"io"
"io/ioutil"
"os"
"time"
)
const pubKey = "/path/to/public.asc"
const secretKey = "/path/to/secret.asc"
const passwdFileName = "/path/to/passphrase.txt"
//TODO: open keys once when starting app
func decodeAndDecryptWithTime(message []byte) ([]byte, float64, error) {
var st = time.Now()
bts, err := decodeAndDecrypt(message)
return bts, time.Now().Sub(st).Seconds(), err
}
func decodeAndDecrypt(encodedEncrypted []byte) ([]byte, error) {
//decrypt from Base64Url
var encryptedBytes []byte
encryptedBytes, err := base64.URLEncoding.DecodeString(string(encodedEncrypted))
if err != nil {
return nil, err
}
// Read in public key
var entity2 *openpgp.Entity
var entitylist2 openpgp.EntityList
// read private key
keyringFileBuffer2, err := os.Open(secretKey)
if err != nil {
return nil, err
}
defer func() {
_ = keyringFileBuffer2.Close()
}()
entitylist2, err = openpgp.ReadArmoredKeyRing(keyringFileBuffer2)
if err != nil {
return nil, err
}
entity2 = entitylist2[0]
// Get the passphrase and read the open private key.
passwd, err := readPasswdFile(passwdFileName)
if err != nil {
return nil, err
}
err = entity2.PrivateKey.Decrypt(passwd)
if err != nil {
return nil, err
}
for _, subkey := range entity2.Subkeys {
err = subkey.PrivateKey.Decrypt(passwd)
if err != nil {
return nil, err
}
}
decryptedBytes, err := decrypt(entitylist2, encryptedBytes)
if err != nil {
return nil, err
}
return decryptedBytes, nil
}
func readPasswdFile(fileName string) ([]byte, error) {
passwd, err := ioutil.ReadFile(fileName)
if err != nil {
return nil, err
}
passwd = bytes.TrimRight(passwd, "\n")
return passwd, nil
}
func encryptAndEncodeWithTime(message []byte) ([]byte, float64, error) {
var st = time.Now()
bts, err := encryptAndEncode(message)
return bts, time.Now().Sub(st).Seconds(), err
}
func encryptAndEncode(message []byte) ([]byte, error) {
// Read in public key
recipient, err := readEntity(pubKey)
if err != nil {
return nil, err
}
// read private key
signer, err := readEntity(secretKey)
if err != nil {
return nil, err
}
passwd, err := readPasswdFile(passwdFileName)
if err != nil {
return nil, err
}
err = signer.PrivateKey.Decrypt(passwd)
if err != nil {
return nil, err
}
r := bytes.NewReader(message)
w := bytes.Buffer{}
err = encrypt([]*openpgp.Entity{recipient}, signer, r, &w)
if err != nil {
return nil, err
}
encoded := base64.URLEncoding.EncodeToString(w.Bytes())
return []byte(encoded), nil
}
func readEntity(name string) (*openpgp.Entity, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
defer func(f *os.File) {
err := f.Close()
if err != nil {
fmt.Printf("Error closing a file %s: %v", name, err)
}
}(f)
block, err := armor.Decode(f)
if err != nil {
return nil, err
}
return openpgp.ReadEntity(packet.NewReader(block.Body))
}
func encrypt(recipients []*openpgp.Entity, signer *openpgp.Entity, r io.Reader, w io.Writer) error {
wc, err := openpgp.Encrypt(w, recipients, signer, &openpgp.FileHints{IsBinary: true}, nil)
if err != nil {
return err
}
if _, err := io.Copy(wc, r); err != nil {
return err
}
return wc.Close()
}
func decrypt(keyring openpgp.KeyRing, encrypted []byte) ([]byte, error) {
md, err := openpgp.ReadMessage(bytes.NewReader(encrypted), keyring, nil, nil)
if err != nil {
return nil, err
}
decryptedBytes, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
return nil, err
}
return decryptedBytes, nil
}
@charger
Copy link
Author

charger commented Aug 5, 2023

@charger Is there a way that encryptAndSign() , decryptAndVerify() way

Sorry, I don't get your question.

@SanchaiPengMos
Copy link

Hi @charger How do I encrypt and decrypt files?
Thanks.

@ismailzakky
Copy link

hi @charger can you please give me any example to decrypt from sign and encrypted gpg file to plaintext?
currently i facing this issue right now

@charger
Copy link
Author

charger commented Oct 21, 2024

hi @charger can you please give me any example to decrypt from sign and encrypted gpg file to plaintext? currently i facing this issue right now

Sorry for late reply. I belive, you need use decodeAndDecrypt. Path to keys provided as hardcode already so need to provide only array of bytes (your encrypted message), and receive array of bytes, which can be casted to string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment