[submodule "src/golang.org/x/crypto"]
path = src/golang.org/x/crypto
url = https://go.googlesource.com/crypto
+[submodule "src/github.com/magical/argon2"]
+ path = src/github.com/magical/argon2
+ url = https://github.com/magical/argon2.git
+[submodule "src/github.com/dchest/blake2b"]
+ path = src/github.com/dchest/blake2b
+ url = https://github.com/dchest/blake2b.git
Encrypted Key Exchange)).
@item
Несбалансированные аутентификационные токены устойчивые к внесетевым
-(offline) атакам по словарю. Злоумышленник не может замаскироваться под
+(offline) атакам по словарю. Используют усиленный по CPU и памяти
+алгоритм хэширования. Злоумышленник не может замаскироваться под
клиента даже скомпрометировав базу данных токенов сервера.
@item
Зашифрованный и аутентифицируемый транспортный протокол передачи данных
Exchange)).
@item
@ref{Verifier structure, Augmented authentication tokens} resistant to
-offline dictionary attacks. An attacker can not masquerade a client
-even with server passphrase verifiers compromising.
+offline dictionary attacks. They use CPU and memory hardened hashing
+algorithm. An attacker can not masquerade a client even with server
+passphrase verifiers compromising.
@item
Encrypted and authenticated @ref{Transport, payload transport}
with 128-bit @ref{Developer, security margin} state-of-the-art
@item -iface
TAP interface name.
-@item -id
-Our client's @ref{Identity} (hexadecimal string).
+@item -verifier
+Our client's @ref{Verifier}.
@item -key
Path to the file with the passphrase. See @ref{Verifier} for
and @url{http://ed25519.cr.yp.to/, Ed25519}.
@item DH elliptic-curve point encoding for public keys
@url{http://elligator.cr.yp.to/, Elligator}.
-@item Key derivation function for verifier generation
-@url{https://en.wikipedia.org/wiki/PBKDF2, PBKDF2} based on
-@url{https://en.wikipedia.org/wiki/SHA-2, SHA-512}.
+@item Verifier password hashing algorithm
+@url{https://password-hashing.net/#argon2, Argon2d}.
@item Packet overhead
26 bytes per packet.
@item Handshake overhead
@strong{Install}. At first you must @ref{Installation, install} this
software: download, @ref{Integrity, check the signature}, compile.
-@strong{Prepare the client}. Generate client's identity and verifier for
-Alice as an example:
+@strong{Prepare the client}. Generate client's verifier for Alice as an
+example:
+
@verbatim
client% ./utils/newclient.sh Alice
Enter passphrase:
-Your id is: 7012df29deee2170594119df5091d4a2
+Your client verifier is: $argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg
Place the following JSON configuration entry on the server's side:
- "7012df29deee2170594119df5091d4a2": {
- "name": "Alice",
+ "Alice": {
"up": "/path/to/up.sh",
- "verifier": "fb43255ca3fe5bd884e364e5eae0cd37ad14774930a027fd38d8938fd0b57425"
+ "verifier": "$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10"
}
Verifier was generated with:
./utils/storekey.sh /tmp/passphrase
- govpn-verifier -id 7012df29deee2170594119df5091d4a2 -key /tmp/passphrase
+ govpn-verifier -key /tmp/passphrase
@end verbatim
@strong{Prepare the server}. Add this entry to @code{peers.json}
@example
client% govpn-client \
-key key.txt \
- -id 906e34b98750c4f686d6c5489508763c \
+ -verifier '$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg' \
-iface tap10 \
-remote 192.168.0.1:1194 \
-mtu 1472
client% route -6 add default fc00::1
client% govpn-client \
-key key.txt \
- -id 906e34b98750c4f686d6c5489508763c \
+ -verifier '$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg' \
-iface tap10 \
-remote "[fe80::1%me0]":1194
@end example
Client's identity is 128-bit string. It is not secret, so can be
transmitted and stored in the clear. However handshake applies PRP on it
-to make DPI and deanonymization much harder to success.
-
-@example
-% ./utils/newclient.sh doesnotmatter
-Your id is: 7012df29deee2170594119df5091d4a2
-@end example
-
-@code{7012df29deee2170594119df5091d4a2} is client's identity.
+to make DPI and deanonymization much harder to success. It is used as a
+salt in verifier.
@headitem Library @tab Platform @tab Licence
@item @code{golang.org/x/crypto} @tab All @tab BSD 3-Clause
@item @code{github.com/agl/ed25519} @tab All @tab BSD 3-Clause
+@item @code{github.com/dchest/blake2b} @tab All @tab CC0 1.0
+@item @code{github.com/magical/argon2} @tab All @tab BSD 2-Clause
@item @code{github.com/bigeagle/water} @tab GNU/Linux @tab BSD 3-Clause
@end multitable
@table @strong
+@item Release 4.1
+@itemize
+@item @url{https://password-hashing.net/#argon2, Argon2d} is used instead
+of PBKDF2 for password verifier hashing.
+@item Client's identity is stored inside the verifier, so it simplifies
+server-side configuration and the code.
+@end itemize
+
@item Release 4.0
@itemize
@item Handshake messages can be noised: their messages lengths are
entropy source.
Passphrases are entered directly by the human on the client side. Server
-side stores previously shared so-called @ref{Verifier}. Verifier contains
-dictionary attack resistant password derivative. Attacker can not use it
-to act as a client.
+side stores previously shared so-called @ref{Verifier, verifier}. Verifier
+contains dictionary attack resistant password derivative. Attacker can not
+use it to act as a client.
We use password (passphrase) authentication, so overall security fully
depends on its strength. You @strong{should} use long, high-entropy
passphrases. Also remember to keep passphrase in temporary file and read
-it securely as described in @ref{Verifier}.
+it securely as described in @ref{Verifier, verifier}.
@item
You must @strong{never} use the same key for multiple clients.
@verbatim
{
- "9b40701bdaf522f2b291cb039490312": { <-- Peer identifier
- "name": "stargrave", <-- OPTIONAL human readable name
+ "stargrave": { <-- Peer human readable name
"up": "./stargrave-up.sh", <-- up-script
"down": "./stargrave-down.sh", <-- OPTIONAL down-script
"timeout": 60, <-- OPTIONAL overriden timeout
(default: false)
"cpr": 64, <-- OPTIONAL constant packet
rate in KiB/sec
- "verifier": "2c15bbdffc73193bea56db412bce1143c68ccbdaa9e2eade53a684497646a685"
+ "verifier": "$argon2d..." <-- verifier received from client
},
[...]
}
@end verbatim
-See @ref{Verifier} for its description.
-
up-script executes each time connection with the client is established.
Its @emph{stdout} output must contain TAP interface name as the first
line. This script can be simple @code{echo tap10}, or maybe more
@verbatim
% ./utils/newclient.sh Alice
[...]
-Your id is: 7012df29deee2170594119df5091d4a2
+Your client verifier is: $argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg
Place the following JSON configuration entry on the server's side:
- "906e34b98750c4f686d6c5489508763c": {
- "name": "Alice",
+ "Alice": {
"up": "/path/to/up.sh",
- "verifier": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "verifier": "$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10"
}
[...]
@end verbatim
@item @url{http://ed25519.cr.yp.to/, Ed25519: high-speed high-security signatures}.
@item @email{watsonbladd@@gmail.com, Watson Ladd} for suggestion of
@url{http://elligator.cr.yp.to/, Elligator} encoding.
+@item @url{https://password-hashing.net/#argon2, PHC for Argon2}.
@end itemize
@unnumbered TODO
@itemize
-@item Use Argon2:
-@url{https://password-hashing.net/, Password Hashing Competition}
-winner, instead of PBKDF2.
@item Ability to tunnel only specified TCP connections, without full
featured VPN solution. Similar to ssh -R.
@item Randomize ports usage.
@example
% utils/storekey.sh mypass.txt
Enter passphrase:[hello world]
-% govpn-verifier -id 9da9bf91112d0e4483c135b12d5b48de -key mypass.txt
-210e3878542828901a3af9b4aa00b004de530410eef5c1ba2ffb6d04504371b2
+% govpn-verifier -key mypass.txt
+$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10
+$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg
@end example
-Store @code{210...1b2} string on the server's side in corresponding
+First line is the verifier for the server side. Second line is for the
+client -- it lacks generated public key. However you can server's one
+on the client side too.
+
+Store @code{$argon2d...u10} string on the server's side in corresponding
@code{verifier} configuration file's field.
You can check passphrase against verifier by specifying @code{-verifier}
option with the path to verifier file:
@example
-% govpn-verifier -id 9da9bf91112d0e4483c135b12d5b48de -key mypass.txt -verifier verifier
+% govpn-verifier -key mypass.txt -verifier '$argon2d...'
true
@end example
its verifying).
@verbatim
-SOURCE = PBKDF2(SALT=PeerId, PASSWORD, 1<<16, SHA512)
+SOURCE = Argon2d(m, t, p, SALT=PeerId, PASSWORD)
PUB, PRIV = Ed25519.Generate(SOURCE)
@end verbatim
-Verifier is @code{PUB} public key of Ed25519 generated from the PBKDF2
-of the passphrase in hexadecimal encoding. @code{PeerId} is used as a
-128-bit salt. Server stores and knows only verifier. Client can compute
-the whole keypair every time he makes handshake.
+Verifier is serialized representation of public data above:
+@verbatim
+$argon2d$m=m,t=t,p=p$Base64(SALT)$Base64(PUB)
+@end verbatim
+
+m, t and p parameters are Argon2d-specific: memory, iterations and
+parallelizm parameters.
+
+Server stores and knows only verifier. Client can compute the whole
+keypair every time he makes handshake.
--- /dev/null
+Subproject commit 3c8c640cd7bea3ca78209d812b5854442ab92fed
--- /dev/null
+Subproject commit 82d59eb7dab9a6268371a8c6de2100a2c7357bc6
)
var (
- remoteAddr = flag.String("remote", "", "Remote server address")
- proto = flag.String("proto", "udp", "Protocol to use: udp or tcp")
- ifaceName = flag.String("iface", "tap0", "TAP network interface")
- IDRaw = flag.String("id", "", "Client identification")
- keyPath = flag.String("key", "", "Path to passphrase file")
- upPath = flag.String("up", "", "Path to up-script")
- downPath = flag.String("down", "", "Path to down-script")
- stats = flag.String("stats", "", "Enable stats retrieving on host:port")
- proxyAddr = flag.String("proxy", "", "Use HTTP proxy on host:port")
- proxyAuth = flag.String("proxy-auth", "", "user:password Basic proxy auth")
- mtu = flag.Int("mtu", 1452, "MTU for outgoing packets")
- timeoutP = flag.Int("timeout", 60, "Timeout seconds")
- noisy = flag.Bool("noise", false, "Enable noise appending")
- cpr = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate")
- egdPath = flag.String("egd", "", "Optional path to EGD socket")
+ remoteAddr = flag.String("remote", "", "Remote server address")
+ proto = flag.String("proto", "udp", "Protocol to use: udp or tcp")
+ ifaceName = flag.String("iface", "tap0", "TAP network interface")
+ verifierRaw = flag.String("verifier", "", "Verifier")
+ keyPath = flag.String("key", "", "Path to passphrase file")
+ upPath = flag.String("up", "", "Path to up-script")
+ downPath = flag.String("down", "", "Path to down-script")
+ stats = flag.String("stats", "", "Enable stats retrieving on host:port")
+ proxyAddr = flag.String("proxy", "", "Use HTTP proxy on host:port")
+ proxyAuth = flag.String("proxy-auth", "", "user:password Basic proxy auth")
+ mtu = flag.Int("mtu", 1452, "MTU for outgoing packets")
+ timeoutP = flag.Int("timeout", 60, "Timeout seconds")
+ noisy = flag.Bool("noise", false, "Enable noise appending")
+ cpr = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate")
+ egdPath = flag.String("egd", "", "Optional path to EGD socket")
conf *govpn.PeerConf
tap *govpn.TAP
govpn.MTU = *mtu
- id, err := govpn.IDDecode(*IDRaw)
- if err != nil {
- log.Fatalln(err)
- }
-
if *egdPath != "" {
log.Println("Using", *egdPath, "EGD")
govpn.EGDInit(*egdPath)
}
- pub, priv := govpn.NewVerifier(id, govpn.StringFromFile(*keyPath))
+ verifier, err := govpn.VerifierFromString(*verifierRaw)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ priv := verifier.PasswordApply(govpn.StringFromFile(*keyPath))
conf = &govpn.PeerConf{
- Id: id,
- Timeout: time.Second * time.Duration(timeout),
- Noise: *noisy,
- CPR: *cpr,
- DSAPub: pub,
- DSAPriv: priv,
+ Id: verifier.Id,
+ Timeout: time.Second * time.Duration(timeout),
+ Noise: *noisy,
+ CPR: *cpr,
+ Verifier: verifier,
+ DSAPriv: priv,
}
- idsCache = govpn.NewCipherCache([]govpn.PeerId{*id})
+ idsCache = govpn.NewCipherCache([]govpn.PeerId{*verifier.Id})
log.Println(govpn.VersionGet())
tap, err = govpn.TAPListen(*ifaceName)
package main
import (
- "encoding/hex"
"encoding/json"
"io/ioutil"
"log"
"time"
- "github.com/agl/ed25519"
-
"govpn"
)
}
confs := make(map[govpn.PeerId]*govpn.PeerConf, len(*confsRaw))
- for peerIdRaw, pc := range *confsRaw {
- peerId, err := govpn.IDDecode(peerIdRaw)
+ for name, pc := range *confsRaw {
+ verifier, err := govpn.VerifierFromString(pc.VerifierRaw)
if err != nil {
- log.Fatalln("Invalid peer ID:", peerIdRaw, err)
+ log.Fatalln("Unable to decode the key:", err.Error(), pc.VerifierRaw)
}
conf := govpn.PeerConf{
- Id: peerId,
- Name: pc.Name,
- Up: pc.Up,
- Down: pc.Down,
- Noise: pc.Noise,
- CPR: pc.CPR,
+ Verifier: verifier,
+ Id: verifier.Id,
+ Name: name,
+ Up: pc.Up,
+ Down: pc.Down,
+ Noise: pc.Noise,
+ CPR: pc.CPR,
}
if pc.TimeoutInt <= 0 {
pc.TimeoutInt = govpn.TimeoutDefault
}
conf.Timeout = time.Second * time.Duration(pc.TimeoutInt)
-
- if len(pc.Verifier) != ed25519.PublicKeySize*2 {
- log.Fatalln("Verifier must be 64 hex characters long")
- }
- keyDecoded, err := hex.DecodeString(string(pc.Verifier))
- if err != nil {
- log.Fatalln("Unable to decode the key:", err.Error(), pc.Verifier)
- }
- conf.DSAPub = new([ed25519.PublicKeySize]byte)
- copy(conf.DSAPub[:], keyDecoded)
-
- confs[*peerId] = &conf
+ confs[*verifier.Id] = &conf
}
return confs
}
package main
import (
+ "crypto/rand"
"crypto/subtle"
- "encoding/hex"
"flag"
"fmt"
"log"
)
var (
- IDRaw = flag.String("id", "", "Client identification")
- keyPath = flag.String("key", "", "Path to passphrase file")
- verifierPath = flag.String("verifier", "", "Optional path to verifier")
+ keyPath = flag.String("key", "", "Path to passphrase file")
+ verifier = flag.String("verifier", "", "Optional verifier")
+ mOpt = flag.Int("m", govpn.DefaultM, "Argon2d memory parameter (KiBs)")
+ tOpt = flag.Int("t", govpn.DefaultT, "Argon2d iteration parameter")
+ pOpt = flag.Int("p", govpn.DefaultP, "Argon2d parallelizm parameter")
)
func main() {
flag.Parse()
- id, err := govpn.IDDecode(*IDRaw)
- if err != nil {
- log.Fatalln(err)
- }
- pub, _ := govpn.NewVerifier(id, govpn.StringFromFile(*keyPath))
- if *verifierPath == "" {
- fmt.Println(hex.EncodeToString(pub[:]))
- } else {
- verifier, err := hex.DecodeString(govpn.StringFromFile(*verifierPath))
- if err != nil {
- log.Fatalln("Can not decode verifier:", err)
+ if *verifier == "" {
+ id := new([govpn.IDSize]byte)
+ if _, err := rand.Read(id[:]); err != nil {
+ log.Fatalln(err)
}
- fmt.Println(subtle.ConstantTimeCompare(verifier[:], pub[:]) == 1)
+ pid := govpn.PeerId(*id)
+ v := govpn.VerifierNew(*mOpt, *tOpt, *pOpt, &pid)
+ v.PasswordApply(govpn.StringFromFile(*keyPath))
+ fmt.Println(v.LongForm())
+ fmt.Println(v.ShortForm())
+ return
+ }
+ v, err := govpn.VerifierFromString(*verifier)
+ if err != nil {
+ log.Fatalln("Can not decode verifier", err)
}
+ pub := *v.Pub
+ v.PasswordApply(govpn.StringFromFile(*keyPath))
+ fmt.Println(subtle.ConstantTimeCompare(v.Pub[:], pub[:]) == 1)
}
)
type PeerConf struct {
- Id *PeerId `json:"-"`
- Name string `json:"name"`
- Up string `json:"up"`
- Down string `json:"down"`
- TimeoutInt int `json:"timeout"`
- Timeout time.Duration `json:"-"`
- Noise bool `json:"noise"`
- CPR int `json:"cpr"`
- Verifier string `json:"verifier"`
+ Id *PeerId `json:"-"`
+ Name string `json:"name"`
+ Up string `json:"up"`
+ Down string `json:"down"`
+ TimeoutInt int `json:"timeout"`
+ Timeout time.Duration `json:"-"`
+ Noise bool `json:"noise"`
+ CPR int `json:"cpr"`
+ VerifierRaw string `json:"verifier"`
// This is passphrase verifier
- DSAPub *[ed25519.PublicKeySize]byte `json:"-"`
+ Verifier *Verifier
// This field exists only on client's side
DSAPriv *[ed25519.PrivateKeySize]byte `json:"-"`
}
Conf: conf,
}
state.dsaPubH = new([ed25519.PublicKeySize]byte)
- copy(state.dsaPubH[:], state.Conf.DSAPub[:])
+ copy(state.dsaPubH[:], state.Conf.Verifier.Pub[:])
HApply(state.dsaPubH)
return &state
}
}
sign := new([ed25519.SignatureSize]byte)
copy(sign[:], dec[RSize+RSize+SSize:])
- if !ed25519.Verify(h.Conf.DSAPub, h.key[:], sign) {
+ if !ed25519.Verify(h.Conf.Verifier.Pub, h.key[:], sign) {
log.Println("Invalid signature from", h.addr)
return nil
}
import (
"crypto/subtle"
"encoding/hex"
- "errors"
"log"
"sync"
return hex.EncodeToString(id[:])
}
-// Decode identification string.
-// It must be 32 hexadecimal characters long.
-func IDDecode(raw string) (*PeerId, error) {
- if len(raw) != IDSize*2 {
- return nil, errors.New("ID must be 32 characters long")
- }
- idDecoded, err := hex.DecodeString(raw)
- if err != nil {
- return nil, errors.New("ID must contain hexadecimal characters only")
- }
- idP := new([IDSize]byte)
- copy(idP[:], idDecoded)
- id := PeerId(*idP)
- return &id, nil
-}
-
type CipherCache struct {
c map[PeerId]*xtea.Cipher
l sync.RWMutex
p.BusyR.Unlock()
return true
}
- if int(p.pktSizeR) > len(data) - MinPktLength {
+ if int(p.pktSizeR) > len(data)-MinPktLength {
return false
}
p.BytesPayloadIn += int64(p.pktSizeR)
func init() {
MTU = 1500
- peerId, _ = IDDecode("ffffffffffffffffffffffffffffffff")
+ id := new([IDSize]byte)
+ peerId := PeerId(*id)
conf = &PeerConf{
- Id: peerId,
+ Id: &peerId,
Timeout: time.Second * time.Duration(TimeoutDefault),
Noise: false,
CPR: 0,
import (
"bytes"
- "crypto/sha512"
+ "encoding/base64"
+ "errors"
+ "fmt"
"io/ioutil"
"log"
"strings"
"github.com/agl/ed25519"
- "golang.org/x/crypto/pbkdf2"
+ "github.com/magical/argon2"
)
const (
- PBKDF2Iters = 1 << 16
+ DefaultM = 1 << 12
+ DefaultT = 1 << 7
+ DefaultP = 1
)
-// Create verifier from supplied password for given PeerId.
-func NewVerifier(id *PeerId, password string) (*[ed25519.PublicKeySize]byte, *[ed25519.PrivateKeySize]byte) {
- r := pbkdf2.Key(
- []byte(password),
- id[:],
- PBKDF2Iters,
- ed25519.PrivateKeySize,
- sha512.New,
- )
+type Verifier struct {
+ M int
+ T int
+ P int
+ Id *PeerId
+ Pub *[ed25519.PublicKeySize]byte
+}
+
+// Generate new verifier for given peer, with specified password and
+// hashing parameters.
+func VerifierNew(m, t, p int, id *PeerId) *Verifier {
+ return &Verifier{M: m, T: t, P: p, Id: id}
+}
+
+// Apply the password: create Ed25519 keypair based on it, save public
+// key in verifier.
+func (v *Verifier) PasswordApply(password string) *[ed25519.PrivateKeySize]byte {
+ r, err := argon2.Key([]byte(password), v.Id[:], v.T, v.P, int64(v.M), 32)
+ if err != nil {
+ log.Fatalln("Unable to apply Argon2d", err)
+ }
defer sliceZero(r)
src := bytes.NewBuffer(r)
- pub, priv, err := ed25519.GenerateKey(src)
+ pub, prv, err := ed25519.GenerateKey(src)
if err != nil {
log.Fatalln("Unable to generate Ed25519 keypair", err)
}
- return pub, priv
+ v.Pub = pub
+ return prv
+}
+
+// Parse either short or long verifier form.
+func VerifierFromString(input string) (*Verifier, error) {
+ s := strings.Split(input, "$")
+ if !(len(s) != 4 || len(s) != 5) || s[1] != "argon2d" {
+ return nil, errors.New("Invalid verifier structure")
+ }
+ var m, t, p int
+ n, err := fmt.Sscanf(s[2], "m=%d,t=%d,p=%d", &m, &t, &p)
+ if n != 3 || err != nil {
+ return nil, errors.New("Invalid verifier parameters")
+ }
+ salt, err := base64.RawStdEncoding.DecodeString(s[3])
+ if err != nil {
+ return nil, err
+ }
+ v := Verifier{M: m, T: t, P: p}
+ id := new([IDSize]byte)
+ copy(id[:], salt)
+ pid := PeerId(*id)
+ v.Id = &pid
+ if len(s) == 5 {
+ pub, err := base64.RawStdEncoding.DecodeString(s[4])
+ if err != nil {
+ return nil, err
+ }
+ v.Pub = new([ed25519.PublicKeySize]byte)
+ copy(v.Pub[:], pub)
+ }
+ return &v, nil
+}
+
+// Short verifier string form -- it is useful for the client.
+// Does not include public key.
+func (v *Verifier) ShortForm() string {
+ return fmt.Sprintf(
+ "$argon2d$m=%d,t=%d,p=%d$%s",
+ v.M, v.T, v.P, base64.RawStdEncoding.EncodeToString(v.Id[:]),
+ )
+}
+
+// Long verifier string form -- it is useful for the server.
+// Includes public key.
+func (v *Verifier) LongForm() string {
+ return fmt.Sprintf(
+ "%s$%s", v.ShortForm(),
+ base64.RawStdEncoding.EncodeToString(v.Pub[:]),
+ )
}
// Read string from the file, trimming newline.
[ -n "$release" ]
git clone . $tmp/govpn-$release
-for repo in src/github.com/bigeagle/water src/github.com/agl/ed25519 src/golang.org/x/crypto; do
+for repo in src/github.com/bigeagle/water src/github.com/agl/ed25519 src/github.com/magical/argon2 src/github.com/dchest/blake2b src/golang.org/x/crypto; do
git clone $repo $tmp/govpn-$release/$repo
done
cd $tmp/govpn-$release
[ -n "$1" ] || {
cat <<EOF
Example script for creating new user peer for GoVPN.
-It generates random client's identity, ask for passphrase, generates
-verifier and shows you example JSON entry for server configuration.
+It asks for passphrase, generates verifier and shows you example
+JSON entry for server configuration.
Usage: $0 <username>
EOF
}
username=$1
-peerid=$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | hexdump -ve '"%02x"')
-[ $(echo -n $peerid | wc -c) = 32 ] || peerid=0"$peerid"
umask 077
passphrase=$(mktemp)
$(dirname $0)/storekey.sh $passphrase
-verifier=$(govpn-verifier -id $peerid -key $passphrase)
+verifier=$(govpn-verifier -key $passphrase)
rm -f $passphrase
+verifierS=$(echo $verifier | sed 's/^\(.*\) .*$/\1/')
+verifierC=$(echo $verifier | sed 's/^.* \(.*\)$/\1/')
echo
cat <<EOF
-Your id is: $peerid
+Your client verifier is: $verifierC
Place the following JSON configuration entry on the server's side:
- "$peerid": {
- "name": "$username",
+ "$username": {
"up": "/path/to/up.sh",
- "verifier": "$verifier"
+ "verifier": "$verifierS"
}
Verifier was generated with:
$(dirname $0)/storekey.sh /tmp/passphrase
- govpn-verifier -id $peerid -key /tmp/passphrase
+ govpn-verifier -key /tmp/passphrase
Create up.sh script that will output on the first line TAP interface
name that must be used for the peer. For example: