Last active
May 19, 2021 10:10
-
-
Save clementlecorre/de57fad7c88ad2658a464f2f85dafa19 to your computer and use it in GitHub Desktop.
Golang gpg encryption (crypto/openpgp)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package gpg | |
import ( | |
"errors" | |
"golang.org/x/crypto/openpgp" | |
"golang.org/x/crypto/openpgp/armor" | |
"golang.org/x/crypto/openpgp/packet" | |
"io" | |
"os" | |
"path/filepath" | |
) | |
const ( | |
defaultFileKeyExtension = ".pubkey" | |
defaultPubKeysPath = "./.keys" | |
) | |
type EncryptOption struct { | |
PubKeysPath string | |
FileToEncrypt string | |
FileKeyExtension string | |
OutputFileName string | |
} | |
type Encrypt struct { | |
EncryptOption | |
PublicKeyPath []string | |
PublicKeysEntity []*openpgp.Entity | |
sourceDataFile *os.File | |
destDataFile *os.File | |
} | |
func NewGpgEncrypt(gpgEncryptOption EncryptOption) (*Encrypt, error) { | |
gpgEncrypt := Encrypt{EncryptOption: gpgEncryptOption} | |
if gpgEncrypt.FileToEncrypt == "" { | |
return nil, errors.New("you must reference a file to encrypt") | |
} | |
if gpgEncrypt.OutputFileName == "" { | |
return nil, errors.New("you must reference a output file name") | |
} | |
if gpgEncrypt.PubKeysPath == "" { | |
gpgEncrypt.PubKeysPath = defaultPubKeysPath | |
} | |
if gpgEncrypt.FileKeyExtension == "" { | |
gpgEncrypt.FileKeyExtension = defaultFileKeyExtension | |
} | |
err := gpgEncrypt.readPublicKeys() | |
if err != nil { | |
return nil, err | |
} | |
if !gpgEncrypt.fileExists(gpgEncrypt.FileToEncrypt) { | |
return nil, errors.New("file to encrypt no found") | |
} | |
return &gpgEncrypt, nil | |
} | |
func (g *Encrypt) SetPubKeysPath(pubKeysPath string) { | |
g.PubKeysPath = pubKeysPath | |
} | |
func (g *Encrypt) SetFileToEncrypt(fileToEncrypt string) { | |
g.FileToEncrypt = fileToEncrypt | |
} | |
func (g *Encrypt) SetFileKeyExtension(fileKeyExtension string) { | |
g.FileKeyExtension = fileKeyExtension | |
} | |
func (g *Encrypt) fileExists(path string) bool { | |
_, err := os.Stat(path) | |
return !os.IsNotExist(err) | |
} | |
func (g *Encrypt) loadFiles() (*os.File, *os.File, error) { | |
var r *os.File | |
var w *os.File | |
r, err := os.Open(g.FileToEncrypt) | |
if err != nil { | |
return nil, nil, err | |
} | |
w, err = os.Create(g.OutputFileName) | |
if err != nil { | |
return nil, nil, err | |
} | |
return r, w, nil | |
} | |
func (g *Encrypt) walkPublicKey() error { | |
err := filepath.Walk(g.PubKeysPath, func(path string, info os.FileInfo, err error) error { | |
if err != nil { | |
return err | |
} | |
if info.IsDir() { | |
return nil | |
} | |
if matched, err := filepath.Match("*"+g.FileKeyExtension, filepath.Base(path)); err != nil { | |
return err | |
} else if matched { | |
g.PublicKeyPath = append(g.PublicKeyPath, path) | |
} | |
return nil | |
}) | |
if err != nil { | |
return err | |
} | |
return nil | |
} | |
func (g *Encrypt) readPublicKeys() error { | |
err := g.walkPublicKey() | |
if err != nil { | |
return err | |
} | |
for _, name := range g.PublicKeyPath { | |
entity, err := g.readPublicKey(name) | |
if err != nil { | |
return err | |
} | |
g.PublicKeysEntity = append(g.PublicKeysEntity, entity) | |
} | |
return nil | |
} | |
func (g *Encrypt) readPublicKey(name string) (*openpgp.Entity, error) { | |
f, err := os.Open(name) | |
if err != nil { | |
return nil, err | |
} | |
defer f.Close() | |
block, err := armor.Decode(f) | |
if err != nil { | |
return nil, err | |
} | |
return openpgp.ReadEntity(packet.NewReader(block.Body)) | |
} | |
func (g *Encrypt) Encrypt() error { | |
r, w, err := g.loadFiles() | |
if err != nil { | |
return err | |
} | |
defer r.Close() | |
defer w.Close() | |
wc, err := openpgp.Encrypt(w, g.PublicKeysEntity, nil, &openpgp.FileHints{IsBinary: true}, nil) | |
if err != nil { | |
return err | |
} | |
if _, err := io.Copy(wc, r); err != nil { | |
return err | |
} | |
return wc.Close() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment