From 24c1f3f0e712b1da20fc579b1ac44280baaa2406 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 8 Mar 2018 18:24:33 +0800 Subject: [PATCH] not fin --- libs/flag.go | 29 ++++++++ main.go | 164 +++++++++++++++++++++++++++++++++++++++------- pgpcrypt/crypt.go | 79 ++++++++++++++++++++++ pgpcrypt/keys.go | 30 +++++++++ tools/tools.go | 50 ++++++++++++++ 5 files changed, 328 insertions(+), 24 deletions(-) create mode 100644 libs/flag.go create mode 100644 pgpcrypt/crypt.go create mode 100644 pgpcrypt/keys.go create mode 100644 tools/tools.go diff --git a/libs/flag.go b/libs/flag.go new file mode 100644 index 0000000..9b97ea0 --- /dev/null +++ b/libs/flag.go @@ -0,0 +1,29 @@ +package libs + +import ( + "flag" +) + +// Flags - flag values struct +type Flags struct { + Help bool + Decrypt bool + Encrypt bool + SrcFile string + DstFile string + KeyFile string + Override bool + Password string +} + +// RegFlag - Register flag to main +func RegFlag(f *Flags) { + flag.BoolVar(&f.Help, "h", false, "show usage help") + flag.BoolVar(&f.Decrypt, "d", false, "decrypt file") + flag.BoolVar(&f.Encrypt, "e", false, "encrypt file") + flag.StringVar(&f.SrcFile, "i", "", "input source `file path`") + flag.StringVar(&f.DstFile, "o", "", "output `file path`") + flag.StringVar(&f.KeyFile, "k", "", "key `file path`") + flag.BoolVar(&f.Override, "y", false, "if output file exists override") + flag.StringVar(&f.Password, "p", "", "private key password") +} diff --git a/main.go b/main.go index 7e70138..7d9425e 100644 --- a/main.go +++ b/main.go @@ -1,45 +1,161 @@ package main import ( - "fmt" + "flag" "io" "log" "os" "path" + "git.trj.tw/root/go-pgp-tool/pgpcrypt" "golang.org/x/crypto/openpgp" + + "git.trj.tw/root/go-pgp-tool/libs" + "git.trj.tw/root/go-pgp-tool/tools" ) +var ( + flags *libs.Flags +) + +func init() { + flags = new(libs.Flags) + libs.RegFlag(flags) + flag.Parse() +} + // args [0] is this func main() { - if len(os.Args) < 3 { - log.Fatal("encrypt keyPath filePath") + // check flags value + if !flags.Encrypt && !flags.Decrypt { + showUsage() + return + } + if flags.Decrypt && flags.Encrypt { + showUsage() + return + } + if len(flags.KeyFile) == 0 { + log.Fatal("please input KeyFile path") + } + if len(flags.SrcFile) == 0 { + log.Fatal("please input SrcFile path") + } + if len(flags.DstFile) == 0 { + log.Fatal("please input DstFile path") } - keyPath := os.Args[1] - filePath := os.Args[2] - wd, err := os.Getwd() + // check file exists + if !tools.CheckExists(flags.KeyFile, false) { + log.Fatal("KeyFile not exists") + } + if !tools.CheckExists(flags.SrcFile, false) { + log.Fatal("SrcFile not exists") + } + dir := path.Dir(flags.DstFile) + if !tools.CheckExists(dir, true) { + log.Fatal("DstFile parent directory not exists") + } + if !flags.Override && tools.CheckExists(flags.DstFile, false) { + log.Fatal("DstFile has Exists if override add flag -y ") + } + + // go to decrypt file + if flags.Decrypt { + decryptAction() + } + if flags.Encrypt { + // encryptAction() + encrypt() + } +} + +func decryptAction() { + // open key file + keyFile, err := os.Open(flags.KeyFile) + handleError(err) + defer keyFile.Close() + + keys, err := pgpcrypt.ReadKeyFile(keyFile) + handleError(err) + if len(keys) == 0 { + log.Fatal("key file not validate") + } + + srcFile, err := os.Open(flags.SrcFile) + handleError(err) + + var dstFile *os.File + if tools.CheckExists(flags.DstFile, false) { + dstFile, err = os.Open(flags.DstFile) + handleError(err) + defer dstFile.Close() + dstStat, err := dstFile.Stat() + handleError(err) + err = dstFile.Truncate(dstStat.Size()) + handleError(err) + } else { + dstFile, err = os.Create(flags.DstFile) + handleError(err) + defer dstFile.Close() + } + + key := keys[0] + err = pgpcrypt.Decrypt(key, flags.Password, srcFile, dstFile) + handleError(err) +} + +func encryptAction() { + // open key file + keyFile, err := os.Open(flags.KeyFile) + handleError(err) + defer keyFile.Close() + + keys, err := pgpcrypt.ReadKeyFile(keyFile) + handleError(err) + if len(keys) == 0 { + log.Fatal("key file not validate") + } + + srcFile, err := os.Open(flags.SrcFile) + handleError(err) + + // encBytes, err := pgpcrypt.EncryptBytes(keys, srcFile) + // handleError(err) + + // fmt.Println("bytes ::: ", len(encBytes)) + + // var dstFile *os.File + // if tools.CheckExists(flags.DstFile, false) { + // dstFile, err = os.Open(flags.DstFile) + // handleError(err) + // defer dstFile.Close() + // dstStat, err := dstFile.Stat() + // handleError(err) + // err = dstFile.Truncate(dstStat.Size()) + // handleError(err) + // } else { + dstFile, err := os.Create(flags.DstFile) + handleError(err) + defer dstFile.Close() + // } + + err = pgpcrypt.Encrypt(keys, srcFile, dstFile) + handleError(err) +} + +func handleError(err error) { if err != nil { log.Fatal(err) } - - keyPath = path.Join(wd, keyPath) - filePath = path.Join(wd, filePath) - - if _, err := os.Stat(keyPath); err != nil && !os.IsExist(err) { - fmt.Println(err) - log.Fatal("key file not exists") - } - - if _, err := os.Stat(filePath); err != nil && !os.IsExist(err) { - log.Fatal("key file not exists") - } - - encrypt(keyPath, filePath) } -func encrypt(pubKey, srcPath string) { - keyFile, err := os.Open(pubKey) +func showUsage() { + flag.Usage() +} + +func encrypt() { + keyFile, err := os.Open(flags.KeyFile) if err != nil { log.Fatal(err) } @@ -54,7 +170,7 @@ func encrypt(pubKey, srcPath string) { keyList = append(keyList, keys...) - distFile, err := os.Create("./dist.pgp") + distFile, err := os.Create(flags.DstFile) if err != nil { log.Fatal(err) } @@ -62,7 +178,7 @@ func encrypt(pubKey, srcPath string) { // distBuf := new(bytes.Buffer) - srcFile, err := os.Open(srcPath) + srcFile, err := os.Open(flags.SrcFile) if err != nil { log.Fatal(err) } diff --git a/pgpcrypt/crypt.go b/pgpcrypt/crypt.go new file mode 100644 index 0000000..6b6ff72 --- /dev/null +++ b/pgpcrypt/crypt.go @@ -0,0 +1,79 @@ +package pgpcrypt + +import ( + "bytes" + "io" + "io/ioutil" + "time" + + "golang.org/x/crypto/openpgp" +) + +// Encrypt - pgp encrypt func +func Encrypt(key openpgp.EntityList, src io.Reader, dst io.Writer) error { + fileHint := &openpgp.FileHints{} + fileHint.IsBinary = true + fileHint.ModTime = time.Now() + + encWriter, err := openpgp.Encrypt(dst, key, nil, fileHint, nil) + if err != nil { + return err + } + + _, err = io.Copy(encWriter, src) + if err != nil { + return err + } + + return nil +} + +// EncryptBytes - +func EncryptBytes(key openpgp.EntityList, src io.Reader) ([]byte, error) { + buf := new(bytes.Buffer) + + fileHint := &openpgp.FileHints{} + fileHint.IsBinary = true + + encWriter, err := openpgp.Encrypt(buf, key, nil, fileHint, nil) + if err != nil { + return nil, err + } + + _, err = io.Copy(encWriter, src) + if err != nil { + return nil, err + } + + encBytes, err := ioutil.ReadAll(buf) + if err != nil { + return nil, err + } + + return encBytes, nil +} + +// Decrypt - pgp decrypt func +func Decrypt(key *openpgp.Entity, keyPassword string, src io.Reader, dst io.Writer) error { + // decode private key + passphraseByte := []byte(keyPassword) + key.PrivateKey.Decrypt(passphraseByte) + for _, sub := range key.Subkeys { + sub.PrivateKey.Decrypt(passphraseByte) + } + + var keyList openpgp.EntityList + keyList = append(keyList, key) + + md, err := openpgp.ReadMessage(src, keyList, nil, nil) + if err != nil { + return err + } + + _, err = io.Copy(dst, md.UnverifiedBody) + if err != nil { + return err + } + + return nil +} diff --git a/pgpcrypt/keys.go b/pgpcrypt/keys.go new file mode 100644 index 0000000..9fa9f1a --- /dev/null +++ b/pgpcrypt/keys.go @@ -0,0 +1,30 @@ +package pgpcrypt + +import ( + "io" + + "golang.org/x/crypto/openpgp" +) + +// ReadKeyFile - read key from file +func ReadKeyFile(r io.Reader) (openpgp.EntityList, error) { + keys, err := openpgp.ReadArmoredKeyRing(r) + if err != nil { + keys, err = openpgp.ReadKeyRing(r) + if err != nil { + return nil, err + } + } + + return keys, nil +} + +// CombineKeys - combine key +func CombineKeys(keys ...openpgp.EntityList) openpgp.EntityList { + var keyList openpgp.EntityList + for _, key := range keys { + keyList = append(keyList, key...) + } + + return keyList +} diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..1f3c93d --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,50 @@ +package tools + +import ( + "os" + "path" + "runtime" + "strings" +) + +// ParsePath - parse file path to absPath +func ParsePath(wd, dst string) string { + if []rune(dst)[0] == '~' { + home := UserHomeDir() + if len(home) > 0 { + dst = strings.Replace(dst, "~", home, -1) + } + } + + if path.IsAbs(dst) { + dst = path.Clean(dst) + return dst + } + + str := path.Join(wd, dst) + str = path.Clean(str) + return str +} + +// UserHomeDir - get user home directory +func UserHomeDir() string { + env := "HOME" + if runtime.GOOS == "windows" { + env = "USERPROFILE" + } else if runtime.GOOS == "plan9" { + env = "home" + } + return os.Getenv(env) +} + +// CheckExists - check file exists +func CheckExists(filePath string, allowDir bool) bool { + stat, err := os.Stat(filePath) + if err != nil && !os.IsExist(err) { + return false + } + if !allowDir && stat.IsDir() { + return false + } + return true +}