From: Sergey Matveev Date: Sun, 11 Sep 2016 13:12:54 +0000 (+0300) Subject: Replace Argon2 with Balloon hashing X-Git-Tag: 6.0^2 X-Git-Url: http://www.git.cypherpunks.ru/?p=govpn.git;a=commitdiff_plain;h=f9209136cff0331fc2293f25061971f6c77ff213 Replace Argon2 with Balloon hashing * We should use Argon2i, instead of Argon2d. Current implementation was Argon2i and did not support d-one. * Other Argon2i implementations on Go exists, but they implements not the latest Argon2 1.3 version. * Argon2 is not so trivial to rewrite from scratch. * Used argon2 library contained testing-library import, that added -test related flags to the command line. * Argon2i has some cryptoanalysis, showing it is not so perfect as expected. So all the issues above are mitigated by replacing this hashing function with much more simpler Balloon hashing written from scratch. Simplicity wins. --- diff --git a/.gitmodules b/.gitmodules index 27bf6b5..bb2b1f8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,12 +7,12 @@ [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 [submodule "src/github.com/go-yaml/yaml"] path = src/github.com/go-yaml/yaml url = https://github.com/go-yaml/yaml.git +[submodule "src/cypherpunks.ru/balloon"] + path = src/cypherpunks.ru/balloon + url = git://git.cypherpunks.ru/balloon.git diff --git a/VERSION b/VERSION index f9ce5a9..e0ea36f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.10 +6.0 diff --git a/doc/developer.texi b/doc/developer.texi index f2fe00e..e147f7e 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -16,7 +16,8 @@ Pay attention how to get @ref{Sources, development source code}. @item DH elliptic-curve point encoding for public keys @url{http://elligator.cr.yp.to/, Elligator}. @item Verifier password hashing algorithm - @url{https://password-hashing.net/#argon2, Argon2d}. + @url{https://crypto.stanford.edu/balloon/, Balloon hashing} based + on BLAKE2b-256. @item Encryptionless confidentiality preserving encoding @url{http://people.csail.mit.edu/rivest/chaffing-980701.txt, Chaffing-and-Winnowing} (two Poly1305 MACs for each bit of message) diff --git a/doc/example.texi b/doc/example.texi index 5f28a7f..4831772 100644 --- a/doc/example.texi +++ b/doc/example.texi @@ -23,14 +23,14 @@ example: @verbatim client% ./utils/newclient.sh Alice Passphrase: -Your client verifier is: $argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg +Your client verifier is: $balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg Place the following YAML configuration entry on the server's side: Alice: up: /path/to/up.sh iface: or TAP interface name - verifier: $argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 + verifier: $balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 @end verbatim @strong{Prepare the server}. Add this entry to @file{peers.yaml} @@ -39,7 +39,7 @@ configuration file: @verbatim Alice: iface: tap10 - verifier: $argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 + verifier: $balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 @end verbatim @strong{Prepare network on GNU/Linux IPv4 server}: @@ -71,7 +71,7 @@ client% ip route add 128/1 via 172.16.0.1 @strong{Run client daemon itself}: @verbatim client% govpn-client \ - -verifier '$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg' \ + -verifier '$balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg' \ -iface tap10 \ -remote 192.168.0.1:1194 @end verbatim @@ -89,7 +89,7 @@ client% ifconfig tap10 client% ifconfig tap10 inet6 fc00::2/96 up client% route -6 add default fc00::1 client% govpn-client \ - -verifier '$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg' \ + -verifier '$balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg' \ -iface tap10 \ -remote "[fe80::1%me0]":1194 @end verbatim diff --git a/doc/installation.texi b/doc/installation.texi index 39e901d..01ac54b 100644 --- a/doc/installation.texi +++ b/doc/installation.texi @@ -28,7 +28,6 @@ Included required libraries: @item @code{github.com/bigeagle/water} @tab GNU/Linux @tab BSD 3-Clause @item @code{github.com/dchest/blake2b} @tab All @tab CC0 1.0 @item @code{github.com/go-yaml/yaml} @tab All @tab LGPLv3 and MIT -@item @code{github.com/magical/argon2} @tab All @tab BSD 2-Clause @item @code{golang.org/x/crypto} @tab All @tab BSD 3-Clause @end multitable diff --git a/doc/news.ru.texi b/doc/news.ru.texi index 38d0336..47ba43b 100644 --- a/doc/news.ru.texi +++ b/doc/news.ru.texi @@ -1,6 +1,18 @@ @node Новости @section Новости +@node Релиз 6.0 +@subsection Релиз 6.0 +@itemize +@item Argon2d заменён на Balloon хэширование. Найденные Argon2 +библиотеки, написанные полностью на Go, имеют различные проблемы. Более +того, Argon2i должен был быть использован вместо Argon2d, но у него есть +возможные @url{http://eprint.iacr.org/2016/027, криптографические +недостатки}. Поэтому он заменён на гораздо более простое (и, похоже, +даже криптографически лучшее) +@url{https://crypto.stanford.edu/balloon/, Balloon хэширование}. +@end itemize + @node Релиз 5.10 @subsection Релиз 5.10 @itemize diff --git a/doc/news.texi b/doc/news.texi index 58b6d12..631c594 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -3,6 +3,17 @@ See also this page @ref{Новости, on russian}. +@node Release 6.0 +@section Release 6.0 +@itemize +@item Argon2d is replaced with Balloon hashing. Found Argon2 libraries +written on pure Go have various problems. Moreover Argon2i should be +used instead, but it has some possible +@url{http://eprint.iacr.org/2016/027, cryptographic defects}. So it is +replaced with much more simpler (and seems even cryptographically +better) @url{https://crypto.stanford.edu/balloon/, Balloon hashing}. +@end itemize + @node Release 5.10 @section Release 5.10 @itemize diff --git a/doc/server.texi b/doc/server.texi index 0d44b79..325d317 100644 --- a/doc/server.texi +++ b/doc/server.texi @@ -34,7 +34,7 @@ stargrave: <-- Peer human readable name noise: No <-- OPTIONAL noise enabler cpr: 64 <-- OPTIONAL constant packet rate, KiB/sec encless: No <-- OPTIONAL Encryptionless mode - verifier: $argon2d... <-- verifier received from client + verifier: $baloon... <-- verifier received from client [...] @end verbatim @@ -63,25 +63,25 @@ creation: @verbatim % ./utils/newclient.sh Alice [...] -Your client verifier is: $argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg +Your client verifier is: $balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg Place the following YAML configuration entry on the server's side: Alice: up: /path/to/up.sh iface: or TAP interface name - verifier: $argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 + verifier: $balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 @end verbatim Example configuration file: @verbatim stargrave: iface: tap0 - verifier: $argon2d$m=4096,t=128,p=1$VMirzcshcHuG2V4jhUsEjw$X5fC07L8k61h3S1Oro/rC76+m0oGDTA9Bq+aWJ1uOgY + verifier: $balloon$s=32768,t=16,p=2$VMirzcshcHuG2V4jhUsEjw$X5fC07L8k61h3S1Oro/rC76+m0oGDTA9Bq+aWJ1uOgY slow: iface: tap1 encless: Yes mtu: 9000 cpr: 384 - verifier: $argon2d$m=4096,t=128,p=1$YbIA5garDqCOhtI/2EZVNg$gOo5vcEGynmpeepNscwclicfZsWxzgYFRLbgG21EZ1U + verifier: $balloon$s=32768,t=16,p=2$YbIA5garDqCOhtI/2EZVNg$gOo5vcEGynmpeepNscwclicfZsWxzgYFRLbgG21EZ1U @end verbatim diff --git a/doc/sources.texi b/doc/sources.texi index 4f4b438..778a786 100644 --- a/doc/sources.texi +++ b/doc/sources.texi @@ -27,6 +27,5 @@ repositories will be unavailable (they are seldom updated): @item @code{github.com/bigeagle/water} @tab @url{git://git.cypherpunks.ru/water.git} @item @code{github.com/dchest/blake2b} @tab @url{git://git.cypherpunks.ru/blake2b.git} @item @code{github.com/go-yaml/yaml} @tab @url{git://git.cypherpunks.ru/yaml.git} -@item @code{github.com/magical/argon2} @tab @url{git://git.cypherpunks.ru/argon2.git} @item @code{golang.org/x/crypto} @tab @url{git://git.cypherpunks.ru/crypto.git} @end multitable diff --git a/doc/thanks.texi b/doc/thanks.texi index eebdedd..0a6757c 100644 --- a/doc/thanks.texi +++ b/doc/thanks.texi @@ -9,6 +9,7 @@ Thanks for contributions and suggestions to: @item @url{https://www.cs.columbia.edu/~smb/papers/aeke.pdf, Augmented Encrypted Key Exchange}: a Password-Based Protocol Secure Against Dictionary Attacks and Password File Compromise @copyright{} Steven M. Belloving, Michael Merrit. @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, Password Hashing Competition for Argon2}. +@item @url{https://crypto.stanford.edu/balloon/, Balloon hashing}. @item @url{http://people.csail.mit.edu/rivest/chaffing-980701.txt, Chaffing and Winnowing: Confidentiality without Encryption} @copyright{} Ronald L. Rivest @item @email{wzyboy@@wzyboy.org, Zhuoyun Wei} for @url{https://aur.archlinux.org/packages/govpn/, AUR} port maintaining and his documentation related fixes. @end itemize diff --git a/doc/verifier.texi b/doc/verifier.texi index 7efdf07..ecf98ad 100644 --- a/doc/verifier.texi +++ b/doc/verifier.texi @@ -6,8 +6,8 @@ Verifier is created using @command{govpn-verifier} utility. @verbatim % govpn-verifier Passphrase:[hello world] -$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 -$argon2d$m=4096,t=128,p=1$bwR5VjeCYIQaa8SeaI3rqg +$balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 +$balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg @end verbatim First line is the verifier for the server side. Second line is for the @@ -18,7 +18,7 @@ You can check passphrase against verifier by specifying @option{-verifier} option with the path to verifier file: @verbatim -% govpn-verifier -verifier '$argon2d...' +% govpn-verifier -verifier '$balloon...' Passphrase:[hello world] true @end verbatim diff --git a/doc/verifierstruct.texi b/doc/verifierstruct.texi index 792506d..b199d72 100644 --- a/doc/verifierstruct.texi +++ b/doc/verifierstruct.texi @@ -6,17 +6,18 @@ dictionary attacks and can not be used for authentication (only its verifying). @verbatim -SOURCE = Argon2d(m, t, p, SALT=PeerId, PASSWORD) +SOURCE = Balloon(PASSWORD, SALT=PeerId, sCost, tCost, pJobs) PUB, PRIV = Ed25519.Generate(SOURCE) @end verbatim +Balloon hashing uses BLAKE2b-256 hash. Space cost (sCost), time cost +(tCost) and number of parallel jobs (pJobs) are specific to Balloon +implementation. + Verifier is serialized representation of public data above: @verbatim -$argon2d$m=m,t=t,p=p$Base64(SALT)$Base64(PUB) +$balloon$s=s,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. diff --git a/src/cypherpunks.ru/balloon b/src/cypherpunks.ru/balloon new file mode 160000 index 0000000..9e7f630 --- /dev/null +++ b/src/cypherpunks.ru/balloon @@ -0,0 +1 @@ +Subproject commit 9e7f63092012aa91a6690d93f00f5bc476e4d3b5 diff --git a/src/cypherpunks.ru/govpn/cmd/govpn-verifier/main.go b/src/cypherpunks.ru/govpn/cmd/govpn-verifier/main.go index 16f7847..a83f9d1 100644 --- a/src/cypherpunks.ru/govpn/cmd/govpn-verifier/main.go +++ b/src/cypherpunks.ru/govpn/cmd/govpn-verifier/main.go @@ -32,9 +32,9 @@ import ( var ( 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") + sOpt = flag.Int("s", govpn.DefaultS, "Balloon space cost") + tOpt = flag.Int("t", govpn.DefaultT, "Balloon time cost") + pOpt = flag.Int("p", govpn.DefaultP, "Balloon parallel jobs") egdPath = flag.String("egd", "", "Optional path to EGD socket") version = flag.Bool("version", false, "Print version information") warranty = flag.Bool("warranty", false, "Print warranty information") @@ -63,7 +63,7 @@ func main() { log.Fatalln(err) } pid := govpn.PeerId(*id) - v := govpn.VerifierNew(*mOpt, *tOpt, *pOpt, &pid) + v := govpn.VerifierNew(*sOpt, *tOpt, *pOpt, &pid) v.PasswordApply(key) fmt.Println(v.LongForm()) fmt.Println(v.ShortForm()) diff --git a/src/cypherpunks.ru/govpn/verifier.go b/src/cypherpunks.ru/govpn/verifier.go index 15955e7..b68063b 100644 --- a/src/cypherpunks.ru/govpn/verifier.go +++ b/src/cypherpunks.ru/govpn/verifier.go @@ -28,19 +28,20 @@ import ( "os" "strings" + "cypherpunks.ru/balloon" "github.com/agl/ed25519" - "github.com/magical/argon2" + "github.com/dchest/blake2b" "golang.org/x/crypto/ssh/terminal" ) const ( - DefaultM = 1 << 12 - DefaultT = 1 << 7 - DefaultP = 1 + DefaultS = 1 << 20 / 32 + DefaultT = 1 << 4 + DefaultP = 2 ) type Verifier struct { - M int + S int T int P int Id *PeerId @@ -49,17 +50,14 @@ type Verifier struct { // 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} +func VerifierNew(s, t, p int, id *PeerId) *Verifier { + return &Verifier{S: s, 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) - } + r := balloon.H(blake2b.New256, []byte(password), v.Id[:], v.S, v.T, v.P) defer SliceZero(r) src := bytes.NewBuffer(r) pub, prv, err := ed25519.GenerateKey(src) @@ -72,26 +70,26 @@ func (v *Verifier) PasswordApply(password string) *[ed25519.PrivateKeySize]byte // Parse either short or long verifier form. func VerifierFromString(input string) (*Verifier, error) { - s := strings.Split(input, "$") - if len(s) < 4 || s[1] != "argon2d" { + ss := strings.Split(input, "$") + if len(ss) < 4 || ss[1] != "balloon" { 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) + 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 { return nil, errors.New("Invalid verifier parameters") } - salt, err := base64.RawStdEncoding.DecodeString(s[3]) + salt, err := base64.RawStdEncoding.DecodeString(ss[3]) if err != nil { return nil, err } - v := Verifier{M: m, T: t, P: p} + v := Verifier{S: s, 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 len(ss) == 5 { + pub, err := base64.RawStdEncoding.DecodeString(ss[4]) if err != nil { return nil, err } @@ -105,8 +103,8 @@ func VerifierFromString(input string) (*Verifier, error) { // 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[:]), + "$balloon$s=%d,t=%d,p=%d$%s", + v.S, v.T, v.P, base64.RawStdEncoding.EncodeToString(v.Id[:]), ) } diff --git a/src/github.com/magical/argon2 b/src/github.com/magical/argon2 deleted file mode 160000 index 190e3cf..0000000 --- a/src/github.com/magical/argon2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 190e3cf208e185668db6aa048e4985b7b7b4d890 diff --git a/utils/makedist.sh b/utils/makedist.sh index 7c1240a..96dfb60 100755 --- a/utils/makedist.sh +++ b/utils/makedist.sh @@ -11,7 +11,6 @@ repos=" src/github.com/bigeagle/water src/github.com/dchest/blake2b src/github.com/go-yaml/yaml - src/github.com/magical/argon2 src/golang.org/x/crypto " for repo in $repos; do