]> Cypherpunks.ru repositories - govpn.git/blobdiff - src/cypherpunks.ru/govpn/verifier.go
Refactor govpn common package
[govpn.git] / src / cypherpunks.ru / govpn / verifier.go
index d5976ec8529aa059222219e809055bb8c2018153..00ba6322eae8d640ccde58860a503631a8d30596 100644 (file)
@@ -21,28 +21,30 @@ package govpn
 import (
        "bytes"
        "encoding/base64"
-       "errors"
        "fmt"
        "hash"
        "io/ioutil"
-       "log"
        "os"
        "strings"
        "syscall"
 
-       "cypherpunks.ru/balloon"
        "github.com/agl/ed25519"
+       "github.com/pkg/errors"
        "golang.org/x/crypto/blake2b"
        "golang.org/x/crypto/ssh/terminal"
+
+       "cypherpunks.ru/balloon"
 )
 
 const (
-       // DefaultS is default Balloon space cost
+       // DefaultS default Balloon space cost
        DefaultS = 1 << 20 / 32
-       // DefaultT is default Balloon time cost
+       // DefaultT default Balloon time cost
        DefaultT = 1 << 4
-       // DefaultP is default Balloon number of jobs
+       // DefaultP default Balloon number of job
        DefaultP = 2
+
+       wrapDecodeString = "base64.RawStdEncoding.DecodeString"
 )
 
 // Verifier is used to authenticate a peer
@@ -60,26 +62,30 @@ func VerifierNew(s, t, p int, id *PeerID) *Verifier {
        return &Verifier{S: s, T: t, P: p, ID: id}
 }
 
-func blake2bKeyless() hash.Hash {
-       h, err := blake2b.New256(nil)
+// PasswordApply applies the password: create Ed25519 keypair based on it,
+// saves public key in verifier.
+func (v *Verifier) PasswordApply(password string) (*[ed25519.PrivateKeySize]byte, error) {
+       // TODO: there is an extremely weird bug, `balloon.H` panic if I the `hash.Hash`
+       // outside the `hasher` function.
+       var err error
+       hasher := func() hash.Hash {
+               var nilHash hash.Hash
+               nilHash, err = blake2b.New256(nil)
+               return nilHash
+       }
+       r := balloon.H(hasher, []byte(password), v.ID[:], v.S, v.T, v.P)
        if err != nil {
-               panic(err)
+               return nil, errors.Wrap(err, wrapBlake2bNew256)
        }
-       return h
-}
 
-// PasswordApply applies the password: create Ed25519 keypair based on it,
-// saves public key in verifier.
-func (v *Verifier) PasswordApply(password string) *[ed25519.PrivateKeySize]byte {
-       r := balloon.H(blake2bKeyless, []byte(password), v.ID[:], v.S, v.T, v.P)
        defer SliceZero(r)
        src := bytes.NewBuffer(r)
        pub, prv, err := ed25519.GenerateKey(src)
        if err != nil {
-               log.Fatalln("Unable to generate Ed25519 keypair", err)
+               return nil, errors.Wrap(err, "ed25519.GenerateKey")
        }
        v.Pub = pub
-       return prv
+       return prv, nil
 }
 
 // VerifierFromString parses either short or long verifier form.
@@ -90,12 +96,15 @@ func VerifierFromString(input string) (*Verifier, error) {
        }
        var s, t, p int
        n, err := fmt.Sscanf(ss[2], "s=%d,t=%d,p=%d", &s, &t, &p)
-       if n != 3 || err != nil {
+       if err != nil {
+               return nil, errors.Wrap(err, "fmt.Sscanf")
+       }
+       if n != 3 {
                return nil, errors.New("Invalid verifier parameters")
        }
        salt, err := base64.RawStdEncoding.DecodeString(ss[3])
        if err != nil {
-               return nil, err
+               return nil, errors.Wrap(err, wrapDecodeString)
        }
        v := Verifier{S: s, T: t, P: p}
        id := new([IDSize]byte)
@@ -105,7 +114,7 @@ func VerifierFromString(input string) (*Verifier, error) {
        if len(ss) == 5 {
                pub, err := base64.RawStdEncoding.DecodeString(ss[4])
                if err != nil {
-                       return nil, err
+                       return nil, errors.Wrap(err, wrapDecodeString)
                }
                v.Pub = new([ed25519.PublicKeySize]byte)
                copy(v.Pub[:], pub)
@@ -134,23 +143,33 @@ func (v *Verifier) LongForm() string {
 // KeyRead reads the key either from text file (if path is specified), or
 // from the terminal.
 func KeyRead(path string) (string, error) {
+       const (
+               emptyString       = ""
+               wrapOsStderrWrite = "os.Stderr.Write"
+       )
        var p []byte
        var err error
        var pass string
-       if path == "" {
-               os.Stderr.Write([]byte("Passphrase:"))
+       if path == emptyString {
+               if _, err = os.Stderr.Write([]byte("Passphrase:")); err != nil {
+                       return emptyString, errors.Wrap(err, wrapOsStderrWrite)
+               }
                p, err = terminal.ReadPassword(int(uintptr(syscall.Stdin)))
-               os.Stderr.Write([]byte("\n"))
+               if err != nil {
+                       return emptyString, errors.Wrap(err, "terminal.ReadPassword")
+               }
+               if _, err = os.Stderr.Write([]byte("\n")); err != nil {
+                       return emptyString, errors.Wrap(err, wrapOsStderrWrite)
+               }
                pass = string(p)
        } else {
-               p, err = ioutil.ReadFile(path)
+               if p, err = ioutil.ReadFile(path); err != nil {
+                       return emptyString, errors.Wrap(err, "ioutil.ReadFile")
+               }
                pass = strings.TrimRight(string(p), "\n")
        }
-       if err != nil {
-               return "", err
-       }
        if len(pass) == 0 {
-               return "", errors.New("Empty passphrase submitted")
+               return emptyString, errors.New("Empty passphrase submitted")
        }
-       return pass, err
+       return pass, nil
 }