]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/verifier.go
Add common cypherpunks.ru prefix for govpn Go package names
[govpn.git] / src / cypherpunks.ru / govpn / verifier.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package govpn
20
21 import (
22         "bytes"
23         "encoding/base64"
24         "errors"
25         "fmt"
26         "io/ioutil"
27         "log"
28         "strings"
29
30         "github.com/agl/ed25519"
31         "github.com/magical/argon2"
32         "golang.org/x/crypto/ssh/terminal"
33 )
34
35 const (
36         DefaultM = 1 << 12
37         DefaultT = 1 << 7
38         DefaultP = 1
39 )
40
41 type Verifier struct {
42         M   int
43         T   int
44         P   int
45         Id  *PeerId
46         Pub *[ed25519.PublicKeySize]byte
47 }
48
49 // Generate new verifier for given peer, with specified password and
50 // hashing parameters.
51 func VerifierNew(m, t, p int, id *PeerId) *Verifier {
52         return &Verifier{M: m, T: t, P: p, Id: id}
53 }
54
55 // Apply the password: create Ed25519 keypair based on it, save public
56 // key in verifier.
57 func (v *Verifier) PasswordApply(password string) *[ed25519.PrivateKeySize]byte {
58         r, err := argon2.Key([]byte(password), v.Id[:], v.T, v.P, int64(v.M), 32)
59         if err != nil {
60                 log.Fatalln("Unable to apply Argon2d", err)
61         }
62         defer SliceZero(r)
63         src := bytes.NewBuffer(r)
64         pub, prv, err := ed25519.GenerateKey(src)
65         if err != nil {
66                 log.Fatalln("Unable to generate Ed25519 keypair", err)
67         }
68         v.Pub = pub
69         return prv
70 }
71
72 // Parse either short or long verifier form.
73 func VerifierFromString(input string) (*Verifier, error) {
74         s := strings.Split(input, "$")
75         if !(len(s) != 4 || len(s) != 5) || s[1] != "argon2d" {
76                 return nil, errors.New("Invalid verifier structure")
77         }
78         var m, t, p int
79         n, err := fmt.Sscanf(s[2], "m=%d,t=%d,p=%d", &m, &t, &p)
80         if n != 3 || err != nil {
81                 return nil, errors.New("Invalid verifier parameters")
82         }
83         salt, err := base64.RawStdEncoding.DecodeString(s[3])
84         if err != nil {
85                 return nil, err
86         }
87         v := Verifier{M: m, T: t, P: p}
88         id := new([IDSize]byte)
89         copy(id[:], salt)
90         pid := PeerId(*id)
91         v.Id = &pid
92         if len(s) == 5 {
93                 pub, err := base64.RawStdEncoding.DecodeString(s[4])
94                 if err != nil {
95                         return nil, err
96                 }
97                 v.Pub = new([ed25519.PublicKeySize]byte)
98                 copy(v.Pub[:], pub)
99         }
100         return &v, nil
101 }
102
103 // Short verifier string form -- it is useful for the client.
104 // Does not include public key.
105 func (v *Verifier) ShortForm() string {
106         return fmt.Sprintf(
107                 "$argon2d$m=%d,t=%d,p=%d$%s",
108                 v.M, v.T, v.P, base64.RawStdEncoding.EncodeToString(v.Id[:]),
109         )
110 }
111
112 // Long verifier string form -- it is useful for the server.
113 // Includes public key.
114 func (v *Verifier) LongForm() string {
115         return fmt.Sprintf(
116                 "%s$%s", v.ShortForm(),
117                 base64.RawStdEncoding.EncodeToString(v.Pub[:]),
118         )
119 }
120
121 // Read the key either from text file (if path is specified), or
122 // from the terminal.
123 func KeyRead(path string) (string, error) {
124         var p []byte
125         var err error
126         var pass string
127         if path == "" {
128                 fmt.Print("Passphrase:")
129                 p, err = terminal.ReadPassword(0)
130                 fmt.Print("\n")
131                 pass = string(p)
132         } else {
133                 p, err = ioutil.ReadFile(path)
134                 pass = strings.TrimRight(string(p), "\n")
135         }
136         if err != nil {
137                 return "", err
138         }
139         if len(pass) == 0 {
140                 return "", errors.New("Empty passphrase submitted")
141         }
142         return pass, err
143 }