tChange program to generic encrypt/decrypt tool - safe-go - Unnamed repository; edit this file 'description' to name the repository.
 (HTM) git clone git://git.z3bra.org/safe-go.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 7c3738080e10f66d9b3892e6ce13cfe8c6fba4e0
 (DIR) parent e42736b586fc5a5eef31959a7800af18e9e44b6b
 (HTM) Author: Willy Goiffon <contact@z3bra.org>
       Date:   Wed, 14 Sep 2022 10:13:03 +0200
       
       Change program to generic encrypt/decrypt tool
       
       Diffstat:
         M go.mod                              |       3 ++-
         M go.sum                              |       6 ++++--
         M safe.go                             |      92 +++++++++++++++++--------------
       
       3 files changed, 56 insertions(+), 45 deletions(-)
       ---
 (DIR) diff --git a/go.mod b/go.mod
       t@@ -5,6 +5,7 @@ go 1.19
        require (
                github.com/netfoundry/secretstream v0.1.2
                golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
       +        golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
        )
        
       -require golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
       +require golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
 (DIR) diff --git a/go.sum b/go.sum
       t@@ -7,6 +7,8 @@ golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0
        golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
        golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
        golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
       -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
       -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
       +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
       +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
       +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
       +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
        golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 (DIR) diff --git a/safe.go b/safe.go
       t@@ -1,21 +1,18 @@
        package main
        
        import (
       +        "crypto/rand"
                "flag"
                "fmt"
                "io"
                "log"
                "os"
        
       +        "golang.org/x/term"
                "golang.org/x/crypto/argon2"
                "github.com/netfoundry/secretstream"
        )
        
       -type Safe struct {
       -        key  []byte
       -        salt []byte
       -}
       -
        const (
                BUFSIZ = 8192
        
       t@@ -25,55 +22,51 @@ const (
                argon2id_threads          = 1
                argon2id_salt_len         = 16
                xchacha20poly1305_key_len = 32
       -        xchacha20poly1305_iv_len  = 24
       +        xchacha20poly1305_iv_len  = 16
        )
        
        func usage() {
       -        fmt.Printf("usage: %s [-hr] [-s safe] [[-af] entry]\n", os.Args[0])
       +        fmt.Printf("usage: %s [-hde] [-s salt] [-p password] [file]\n", os.Args[0])
                os.Exit(2)
        }
        
       -func readsalt(secret string, safe *Safe) {
       -        f, err := os.Open(secret)
       +func readsalt(file string, salt *[]byte) {
       +        f, err := os.Open(file)
                if err != nil {
                        log.Fatal(err)
                }
                defer f.Close()
        
       -        safe.salt = make([]byte, argon2id_salt_len)
       -        s := io.NewSectionReader(f, 0, argon2id_salt_len)
       -
       -        _, err = s.Read(safe.salt)
       +        _, err = f.Read(*salt)
                if err != nil {
                        log.Fatal(err)
                }
        }
        
       -func deriv(pw []byte, s *Safe) {
       -        s.key = make([]byte, xchacha20poly1305_key_len)
       -        s.key = argon2.IDKey(pw, s.salt,
       +func deriv(pw []byte, key *[]byte, salt []byte) {
       +        *key = argon2.IDKey(pw, salt,
                        argon2id_time_cost,
                        argon2id_memory_cost,
                        argon2id_threads,
                        xchacha20poly1305_key_len)
        }
        
       -func encrypt(secret string, safe *Safe) {
       +func encrypt(secret string, key []byte, salt []byte) {
                var tag byte
                buf := make([]byte, BUFSIZ) 
        
       -        enc, nonce, err := secretstream.NewEncryptor(safe.key)
       +        enc, nonce, err := secretstream.NewEncryptor(key)
                if err != nil {
                        log.Fatal(err)
                }
        
       -        f, err := os.OpenFile(secret, os.O_CREATE|os.O_WRONLY, 0600)
       +        f, err := os.OpenFile(secret, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
                if err != nil {
                        log.Fatal(err)
                }
                defer f.Close()
        
       -        f.Write(safe.salt)
       +        f.Write(salt)
                if err != nil {
                        log.Fatal(err)
                }
       t@@ -105,7 +98,7 @@ func encrypt(secret string, safe *Safe) {
                }
        }
        
       -func decrypt(secret string, safe *Safe) {
       +func decrypt(secret string, key []byte) {
                buf := make([]byte, BUFSIZ + secretstream.StreamABytes)
                header := make([]byte, secretstream.StreamHeaderBytes)
        
       t@@ -121,7 +114,7 @@ func decrypt(secret string, safe *Safe) {
                        log.Fatal(err)
                }
        
       -        dec, err := secretstream.NewDecryptor(safe.key, header)
       +        dec, err := secretstream.NewDecryptor(key, header)
                if err != nil {
                        log.Fatal(err)
                }
       t@@ -146,15 +139,15 @@ func decrypt(secret string, safe *Safe) {
        }
        
        func main() {
       -        var safe Safe
       -
       -        var store string
       -        var aflag, fflag, rflag bool
       -
       -        flag.StringVar(&store, "s", ".secrets", "Set safe store location")
       -        flag.BoolVar(&aflag, "a", false, "Add a secret to the safe")
       -        flag.BoolVar(&fflag, "f", false, "Force writing secret (implies -a)")
       -        flag.BoolVar(&rflag, "r", false, "Save password in a running agent")
       +        var err error
       +        var key, salt, pass []byte
       +        var saltfile, password string 
       +        var dflag, eflag bool
       +
       +        flag.StringVar(&saltfile, "s", "", "Read salt from file")
       +        flag.StringVar(&password, "p", "", "Password to derivate key from")
       +        flag.BoolVar(&eflag, "e", true, "encrypt input (default)")
       +        flag.BoolVar(&dflag, "d", false, "decrypt input")
                flag.Usage = usage
                flag.Parse()
        
       t@@ -163,23 +156,38 @@ func main() {
                        usage()
                }
        
       -        err := os.Chdir(store)
       +        if len(password) == 0 {
       +        tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0644)
                if err != nil {
                        log.Fatal(err)
       -
       +        }
       +        defer tty.Close()
       +        fmt.Fprint(tty, "password:")
       +        pass, _ = term.ReadPassword(int(tty.Fd()))
       +        fmt.Fprintln(tty, "")
       +        } else {
       +                pass = []byte(password)
                }
        
       -        //fmt.Printf("password:")
       -        //password, _ := bufio.NewReader(os.Stdin).ReadString('\n')
       -
       -        // read salt from master entry
       -        readsalt("master", &safe)
       +        // read salt from the given file, ir generate a ramdom one
       +        salt = make([]byte, argon2id_salt_len)
       +        if len(saltfile) > 0 {
       +                readsalt(saltfile, &salt)
       +        } else if dflag {
       +                readsalt(args[0], &salt)
       +        } else {
       +                _, err = rand.Read(salt)
       +                if err != nil {
       +                        log.Fatal(err)
       +                }
       +        }
        
       -        deriv([]byte("azerty"), &safe)
       +        key = make([]byte, xchacha20poly1305_key_len)
       +        deriv(pass, &key, salt)
        
       -        if !aflag {
       -                decrypt(args[0], &safe)
       +        if dflag {
       +                decrypt(args[0], key)
                } else {
       -                encrypt(args[0], &safe)
       +                encrypt(args[0], key, salt)
                }
        }