From: Sergey Matveev Date: Sat, 29 Oct 2016 17:43:35 +0000 (+0300) Subject: Merge branch 'develop' X-Git-Tag: 7.0 X-Git-Url: http://www.git.cypherpunks.ru/?a=commitdiff_plain;h=refs%2Ftags%2F7.0;hp=21dee974626eb44b6c3904621dea946fef7e17fc;p=govpn.git Merge branch 'develop' --- diff --git a/.gitmodules b/.gitmodules index bb2b1f8..82df1f7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,6 @@ [submodule "src/golang.org/x/crypto"] path = src/golang.org/x/crypto url = https://go.googlesource.com/crypto -[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 diff --git a/VERSION b/VERSION index e0ea36f..4fedf1d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0 +7.0 diff --git a/doc/Makefile b/doc/Makefile index 6e2b0db..239750c 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -8,11 +8,17 @@ handshake.utxt: handshake.txt govpn.info: *.texi handshake.utxt $(MAKEINFO) -o govpn.info index.texi +CSS != cat style.css + govpn.html: *.texi handshake.utxt rm -f govpn.html/*.html $(MAKEINFO) --html \ - --css-include=style.css \ + --set-customization-variable CSS_LINES='$(CSS)' \ --set-customization-variable SHOW_TITLE=0 \ + --set-customization-variable USE_ACCESSKEY=0 \ --set-customization-variable DATE_IN_HEADER=1 \ + --set-customization-variable TOP_NODE_UP_URL=index.html \ + --set-customization-variable CLOSE_QUOTE_SYMBOL=\" \ + --set-customization-variable OPEN_QUOTE_SYMBOL=\" \ -o govpn.html index.texi cp -r .well-known govpn.html/ diff --git a/doc/about.ru.texi b/doc/about.ru.texi index b911083..0c45017 100644 --- a/doc/about.ru.texi +++ b/doc/about.ru.texi @@ -70,7 +70,7 @@ A-EKE (Diffie-Hellman Augmented Encrypted Key Exchange)). идентификатор}, невидимый третьим лицам (они анонимны для них). @item -Использует @url{https://ru.wikipedia.org/wiki/TUN/TAP, TAP} низлежащие +Использует @url{https://ru.wikipedia.org/wiki/TUN/TAP, TUN/TAP} низлежащие сетевые интерфейсы. @item diff --git a/doc/about.texi b/doc/about.texi index 59359c8..7cda5af 100644 --- a/doc/about.texi +++ b/doc/about.texi @@ -66,7 +66,7 @@ options. Clients have pre-established @ref{Identity, identity} invisible for third-parties (they are anonymous). @item -Uses @url{https://en.wikipedia.org/wiki/TAP_(network_driver), TAP} +Uses @url{https://en.wikipedia.org/wiki/TAP_(network_driver), TUN/TAP} underlying network interfaces. @item diff --git a/doc/client.texi b/doc/client.texi index 58dc74b..42b8a65 100644 --- a/doc/client.texi +++ b/doc/client.texi @@ -7,7 +7,7 @@ options client has the following ones: @table @option @item -mtu -Expected TAP interface @ref{MTU}. +Expected TUN/TAP interface @ref{MTU}. @item -proto @ref{Network, Network protocol} to use. Can be either @emph{udp} @@ -25,7 +25,7 @@ server. Address (@code{host:port} format) of remote server we need to connect to. @item -iface -TAP interface name. +TUN/TAP interface name. @item -verifier Our client's @ref{Verifier}. diff --git a/doc/developer.texi b/doc/developer.texi index e147f7e..15e8780 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -5,16 +5,16 @@ Pay attention how to get @ref{Sources, development source code}. @table @asis @item Data encryption - @url{http://cr.yp.to/snuffle.html, Salsa20}. + @url{https://cr.yp.to/chacha.html, ChaCha20}. @item Message authentication - @url{http://cr.yp.to/mac.html, Poly1305}. + @url{https://cr.yp.to/mac.html, Poly1305}. @item Nonce and identity obfuscation @url{https://blake2.net/, BLAKE2b-MAC}. @item Password authenticated key agreement - DH-A-EKE powered by @url{http://cr.yp.to/ecdh.html, Curve25519} - and @url{http://ed25519.cr.yp.to/, Ed25519}. + DH-A-EKE powered by @url{https://cr.yp.to/ecdh.html, Curve25519} + and @url{https://ed25519.cr.yp.to/, Ed25519}. @item DH elliptic-curve point encoding for public keys - @url{http://elligator.cr.yp.to/, Elligator}. + @url{https://elligator.cr.yp.to/, Elligator}. @item Verifier password hashing algorithm @url{https://crypto.stanford.edu/balloon/, Balloon hashing} based on BLAKE2b-256. @@ -25,7 +25,7 @@ Pay attention how to get @ref{Sources, development source code}. @url{http://theory.lcs.mit.edu/~cis/pubs/rivest/fusion.ps, All-Or-Nothing-Transformed} (based on @url{http://cseweb.ucsd.edu/~mihir/papers/oaep.html, OAEP} using - Salsa20 with BLAKE2b-256 based + ChaCha20 with BLAKE2b-256 based @url{http://crypto.stanford.edu/~dabo/abstracts/saep.html, SAEP+} checksums) data with 128-bits of feeded random. @item Packet overhead diff --git a/doc/download.texi b/doc/download.texi index 6fe34f2..31977c6 100644 --- a/doc/download.texi +++ b/doc/download.texi @@ -5,9 +5,13 @@ You can obtain releases source code prepared tarballs from the links below (or use @url{https://sourceforge.net/projects/govpn/files/, Sourceforge mirror}). Do not forget to check tarball @ref{Integrity, integrity}. -@multitable {XXXXX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} +@multitable {XXXXX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} @headitem Version @tab Size @tab Tarball @tab SHA256 checksum +@item @ref{Release 6.0, 6.0} @tab 310 KiB +@tab @url{download/govpn-6.0.tar.xz, link} @url{download/govpn-6.0.tar.xz.sig, sign} +@tab @code{3ACAE3B9 884F3260 38FCA9CE 6A309DF6 71BE6386 1FB2058B C79AE7DC 2A1A1811} + @item @ref{Release 5.10, 5.10} @tab 316 KiB @tab @url{download/govpn-5.10.tar.xz, link} @url{download/govpn-5.10.tar.xz.sig, sign} @tab @code{BC624265 CFCDA8CE 1C1BBF9D 016683C5 0EC6CBA5 AECCF33D 93FCA4E5 D52098BD} diff --git a/doc/encless.texi b/doc/encless.texi index 6d694b2..9513d6c 100644 --- a/doc/encless.texi +++ b/doc/encless.texi @@ -8,7 +8,7 @@ some countries forbids usage of encryption (but again not the authentication). GoVPN provides special encryptionless mode of operation. In this mode it -replaces Salsa20 function used for confidentiality with rather +replaces ChaCha20 function used for confidentiality with rather well-known @url{http://people.csail.mit.edu/rivest/chaffing-980701.txt, Chaffing-and-Winnowing} (CnW) technology. This is rather traffic and resource hungry algorithm, so we use it after diff --git a/doc/example.texi b/doc/example.texi index 4831772..688898a 100644 --- a/doc/example.texi +++ b/doc/example.texi @@ -9,7 +9,7 @@ WiFi-reachable gateway. @item You want to create virtual encrypted and authenticated 172.16.0/24 network and use it as a default transport. @item Assume that outgoing GoVPN packets can be fragmented, so we do not -bother configuring MTU of TAP interfaces. For better performance just +bother configuring MTU of TUN/TAP interfaces. For better performance just lower it and check that no fragmentation of outgoing UDP packets occurs. @end itemize @@ -29,7 +29,7 @@ Place the following YAML configuration entry on the server's side: Alice: up: /path/to/up.sh - iface: or TAP interface name + iface: or TUN/TAP interface name verifier: $balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 @end verbatim diff --git a/doc/installation.texi b/doc/installation.texi index 01ac54b..1443d7f 100644 --- a/doc/installation.texi +++ b/doc/installation.texi @@ -26,7 +26,6 @@ Included required libraries: @headitem Library @tab Platform @tab Licence @item @code{github.com/agl/ed25519} @tab All @tab BSD 3-Clause @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{golang.org/x/crypto} @tab All @tab BSD 3-Clause @end multitable diff --git a/doc/integrity.texi b/doc/integrity.texi index ff692ff..b9bc1a1 100644 --- a/doc/integrity.texi +++ b/doc/integrity.texi @@ -23,9 +23,10 @@ public key fingerprint. @item @verbatim -% gpg --auto-key-locate pka --locate-keys releases at govpn dot info +% gpg --keyserver hkp://keys.gnupg.net/ --recv-keys 0xF2F59045FFE2F4A1 % gpg --auto-key-locate dane --locate-keys releases at govpn dot info % gpg --auto-key-locate wkd --locate-keys releases at govpn dot info +% gpg --auto-key-locate pka --locate-keys releases at govpn dot info @end verbatim @item diff --git a/doc/mtu.texi b/doc/mtu.texi index c11cef9..00aa7e7 100644 --- a/doc/mtu.texi +++ b/doc/mtu.texi @@ -2,7 +2,7 @@ @subsection Maximum Transmission Unit MTU option tells what maximum transmission unit is expected to get from -TAP interface. It is per-user configuration. Incoming packets of bigger +TUN/TAP interface. It is per-user configuration. Incoming packets of bigger sizes (including the padding byte) will be ignored. If either @ref{Noise, noise}, @ref{Encless, encryptionless mode} or @ref{CPR} are enabled, then all outgoing packets are filled up to that MTU value. diff --git a/doc/news.ru.texi b/doc/news.ru.texi index 47ba43b..81c3139 100644 --- a/doc/news.ru.texi +++ b/doc/news.ru.texi @@ -1,6 +1,16 @@ @node Новости @section Новости +@node Релиз 7.0 +@subsection Релиз 7.0 +@itemize +@item (X)Salsa20 заменён на ChaCha20. Теоретически он должен быть +быстрее и более безопасным. Это несовместимое с предыдущими версиями +клиента изменение! +@item Возможность использовать TUN-интерфейсы под GNU/Linux. FreeBSD без +изменений уже поддерживала эту возможность. +@end itemize + @node Релиз 6.0 @subsection Релиз 6.0 @itemize diff --git a/doc/news.texi b/doc/news.texi index 631c594..5a6db8f 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -3,6 +3,15 @@ See also this page @ref{Новости, on russian}. +@node Release 7.0 +@section Release 7.0 +@itemize +@item (X)Salsa20 is replaced with ChaCha20. Theoretically it should be +faster and more secure. Previous versions are not compatible with it! +@item Ability to use TUN-interfaces under GNU/Linux. FreeBSD has already +supported them without any modifications. +@end itemize + @node Release 6.0 @section Release 6.0 @itemize diff --git a/doc/scripts.texi b/doc/scripts.texi index 7b2e3c0..69848a0 100644 --- a/doc/scripts.texi +++ b/doc/scripts.texi @@ -11,7 +11,7 @@ their execution: Remote peer's address. In client mode it is server's address. @item GOVPN_IFACE -TAP interface name. In server mode this can be empty: that means that +TUN/TAP interface name. In server mode this can be empty: that means that script must output its name as the first line to stdout. @end table diff --git a/doc/server.texi b/doc/server.texi index 325d317..b3e9ac7 100644 --- a/doc/server.texi +++ b/doc/server.texi @@ -25,7 +25,7 @@ Configuration file is YAML file with following example structure: @verbatim stargrave: <-- Peer human readable name - iface: tap10 <-- OPTIONAL TAP interface name + iface: tap10 <-- OPTIONAL TUN/TAP interface name mtu: 1515 <-- OPTIONAL overriden MTU up: ./stargrave-up.sh <-- OPTIONAL up-script down: ./stargrave-down.sh <-- OPTIONAL down-script @@ -40,7 +40,7 @@ stargrave: <-- Peer human readable name At least one of either @code{iface} or @code{up} must be specified. If you specify @code{iface}, then it will be forcefully used to determine -what TAP interface will be used. If it is not specified, then +what TUN/TAP interface will be used. If it is not specified, then up-@ref{Scripts, script} must output interface's name to stdout (first output line). @@ -69,7 +69,7 @@ Place the following YAML configuration entry on the server's side: Alice: up: /path/to/up.sh - iface: or TAP interface name + iface: or TUN/TAP interface name verifier: $balloon$s=32768,t=16,p=2$bwR5VjeCYIQaa8SeaI3rqg$KCNIqfS4DGsBTtVytamAzcISgrlEWvNxan1UfBrFu10 @end verbatim diff --git a/doc/sources.texi b/doc/sources.texi index 778a786..e7a1375 100644 --- a/doc/sources.texi +++ b/doc/sources.texi @@ -25,7 +25,6 @@ repositories will be unavailable (they are seldom updated): @item @code{cypherpunks.ru/govpn} @tab @url{https://github.com/stargrave/govpn.git} @item @code{github.com/agl/ed25519} @tab @url{git://git.cypherpunks.ru/ed25519.git} @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{golang.org/x/crypto} @tab @url{git://git.cypherpunks.ru/crypto.git} @end multitable diff --git a/doc/style.css b/doc/style.css index 19806be..dc94af9 100644 --- a/doc/style.css +++ b/doc/style.css @@ -1,17 +1,10 @@ + diff --git a/doc/timeout.texi b/doc/timeout.texi index 89dd5b0..2cb5201 100644 --- a/doc/timeout.texi +++ b/doc/timeout.texi @@ -8,7 +8,7 @@ dead. Timeout option should be synchronized both for server and client. If there were no packets at all during fourth part of timeout, then special heartbeat packet is sent. So VPN connection should be alive all -the time, even if there is no traffic in corresponding TAP interfaces. +the time, even if there is no traffic in corresponding TUN/TAP interfaces. @strong{Beware}: this consumes traffic. Stale peers and handshake states are cleaned up every timeout period. diff --git a/doc/transport.texi b/doc/transport.texi index 8123225..e5f5abb 100644 --- a/doc/transport.texi +++ b/doc/transport.texi @@ -2,7 +2,7 @@ @section Transport protocol @verbatim - NONCE = 64bit(MAC(MAC_KEY, SERIAL)) + NONCE = 64bit(ZEROS) || 64bit(MAC(MAC_KEY, SERIAL)) PAYLOAD = DATA || PAD [|| ZEROS] CIPHERTEXT = ENCRYPT(KEY, NONCE, PAYLOAD) TAG = AUTH(AUTH_KEY, CIPHERTEXT || NONCE) @@ -13,16 +13,16 @@ CIPHERTEXT = ENCRYPT(KEY, NONCE, PAYLOAD) client (to server) messages, evens for server (to client) messages. @code{MAC} is BLAKE2b-MAC used to obfuscate @code{SERIAL}. MAC's key -@code{MAC_KEY} is the first 256-bit of Salsa20's output with established +@code{MAC_KEY} is the first 256-bit of ChaCha20's output with established common key and zero nonce (message nonces start from 1). @verbatim MAC_KEY = 256bit(ENCRYPT(KEY, 0)) @end verbatim -@code{ENCRYPT} is Salsa20 stream cipher, with established session +@code{ENCRYPT} is ChaCha20 stream cipher, with established session @code{KEY} and obfuscated @code{SERIAL} used as a nonce. 512 bit of -Salsa20's output is ignored and only remaining is XORed with ther data, +ChaCha20's output is ignored and only remaining is XORed with ther data, encrypting it. @code{DATA} is padded using ISO/IEC 7816-4 format (@code{PAD} (0x80 @@ -30,7 +30,7 @@ byte) with optional @code{ZEROS} following), to fill up packet to conceal payload packet length. @code{AUTH} is Poly1305 authentication function. First 256 bits of -Salsa20's output are used as a one-time key for @code{AUTH}. +ChaCha20's output are used as a one-time key for @code{AUTH}. @verbatim AUTH_KEY = 256bit(ENCRYPT(KEY, NONCE)) diff --git a/doc/user.texi b/doc/user.texi index b27b356..34a93c3 100644 --- a/doc/user.texi +++ b/doc/user.texi @@ -5,7 +5,7 @@ Announcements about updates and new releases can be found in @ref{Contacts, contacts}. GoVPN is split into two pieces: @ref{Client} and @ref{Server}. Each of -them work on top of @ref{Network, UDP/TCP} and TAP virtual network +them work on top of @ref{Network, UDP/TCP} and TUN/TAP virtual network interfaces. GoVPN is just a tunnelling of Ethernet frames, nothing less, nothing more. All you IP-related network management is not touched by VPN at all. You can automate it using up and down shell scripts. diff --git a/src/chacha20 b/src/chacha20 new file mode 120000 index 0000000..95f85aa --- /dev/null +++ b/src/chacha20 @@ -0,0 +1 @@ +golang.org/x/crypto/chacha20poly1305/internal/chacha20 \ No newline at end of file diff --git a/src/cypherpunks.ru/govpn/aont/oaep.go b/src/cypherpunks.ru/govpn/aont/oaep.go index 35d92fe..4b780ba 100644 --- a/src/cypherpunks.ru/govpn/aont/oaep.go +++ b/src/cypherpunks.ru/govpn/aont/oaep.go @@ -30,7 +30,7 @@ along with this program. If not, see . // package PKG: // // PKG = P1 || P2 -// P1 = Salsa20(key=r, nonce=0x00, 0x00) XOR (M || BLAKE2b(r || M)) +// P1 = ChaCha20(key=r, nonce=0x00, 0x00) XOR (M || BLAKE2b(r || M)) // P2 = BLAKE2b(P1) XOR r package aont @@ -38,8 +38,8 @@ import ( "crypto/subtle" "errors" - "github.com/dchest/blake2b" - "golang.org/x/crypto/salsa20" + "chacha20" + "golang.org/x/crypto/blake2b" ) const ( @@ -48,7 +48,7 @@ const ( ) var ( - dummyNonce []byte = make([]byte, 8) + dummyNonce *[16]byte = new([16]byte) ) // Encode the data, produce AONT package. Data size will be larger than @@ -56,13 +56,16 @@ var ( func Encode(r *[RSize]byte, in []byte) ([]byte, error) { out := make([]byte, len(in)+HSize+RSize) copy(out, in) - h := blake2b.New256() + h, err := blake2b.New256(nil) + if err != nil { + return nil, err + } h.Write(r[:]) h.Write(in) copy(out[len(in):], h.Sum(nil)) - salsaKey := new([32]byte) - copy(salsaKey[:], r[:]) - salsa20.XORKeyStream(out, out, dummyNonce, salsaKey) + chachaKey := new([32]byte) + copy(chachaKey[:], r[:]) + chacha20.XORKeyStream(out, out, dummyNonce, chachaKey) h.Reset() h.Write(out[:len(in)+32]) for i, b := range h.Sum(nil)[:RSize] { @@ -77,16 +80,19 @@ func Decode(in []byte) ([]byte, error) { if len(in) < HSize+RSize { return nil, errors.New("Too small input buffer") } - h := blake2b.New256() + h, err := blake2b.New256(nil) + if err != nil { + return nil, err + } h.Write(in[:len(in)-RSize]) - salsaKey := new([32]byte) + chachaKey := new([32]byte) for i, b := range h.Sum(nil)[:RSize] { - salsaKey[i] = b ^ in[len(in)-RSize+i] + chachaKey[i] = b ^ in[len(in)-RSize+i] } h.Reset() - h.Write(salsaKey[:RSize]) + h.Write(chachaKey[:RSize]) out := make([]byte, len(in)-RSize) - salsa20.XORKeyStream(out, in[:len(in)-RSize], dummyNonce, salsaKey) + chacha20.XORKeyStream(out, in[:len(in)-RSize], dummyNonce, chachaKey) h.Write(out[:len(out)-HSize]) if subtle.ConstantTimeCompare(h.Sum(nil), out[len(out)-HSize:]) != 1 { return nil, errors.New("Invalid checksum") diff --git a/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go b/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go index c7b04a7..36ff72a 100644 --- a/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go +++ b/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go @@ -34,7 +34,7 @@ import ( 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") + ifaceName = flag.String("iface", "tap0", "TUN/TAP network interface") verifierRaw = flag.String("verifier", "", "Verifier") keyPath = flag.String("key", "", "Path to passphrase file") upPath = flag.String("up", "", "Path to up-script") @@ -42,7 +42,7 @@ var ( 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", govpn.MTUDefault, "MTU of TAP interface") + mtu = flag.Int("mtu", govpn.MTUDefault, "MTU of TUN/TAP interface") timeoutP = flag.Int("timeout", 60, "Timeout seconds") timeSync = flag.Int("timesync", 0, "Time synchronization requirement") noreconnect = flag.Bool("noreconnect", false, "Disable reconnection after timeout") @@ -127,7 +127,7 @@ func main() { tap, err = govpn.TAPListen(*ifaceName, *mtu) if err != nil { - log.Fatalln("Can not listen on TAP interface:", err) + log.Fatalln("Can not listen on TUN/TAP interface:", err) } if *stats != "" { diff --git a/src/cypherpunks.ru/govpn/cnw/cnw.go b/src/cypherpunks.ru/govpn/cnw/cnw.go index 931a0d1..c5d41a6 100644 --- a/src/cypherpunks.ru/govpn/cnw/cnw.go +++ b/src/cypherpunks.ru/govpn/cnw/cnw.go @@ -34,11 +34,11 @@ along with this program. If not, see . // one is over "0". If bit value is 1, then first is taken over "0" and // second is over "1". // -// Poly1305 uses 256-bit one-time key. We generate it using XSalsa20 for +// Poly1305 uses 256-bit one-time key. We generate it using ChaCha20 for // for the whole byte at once (16 MACs). // -// MACKey1, MACKey2, ... = XSalsa20(authKey, nonce, 0x00...) -// nonce = prefix || 0x00... || big endian byte number +// MACKey1, MACKey2, ... = ChaCha20(authKey, nonce, 0x00...) +// nonce = prefix || big endian byte number package cnw import ( @@ -46,8 +46,8 @@ import ( "encoding/binary" "errors" + "chacha20" "golang.org/x/crypto/poly1305" - "golang.org/x/crypto/salsa20" ) const ( @@ -65,15 +65,15 @@ func zero(in []byte) { func Chaff(authKey *[32]byte, noncePrfx, in []byte) []byte { out := make([]byte, len(in)*EnlargeFactor) keys := make([]byte, 8*64) - nonce := make([]byte, 24) + nonce := new([16]byte) copy(nonce[:8], noncePrfx) var i int var v byte tag := new([16]byte) macKey := new([32]byte) for n, b := range in { - binary.BigEndian.PutUint64(nonce[16:], uint64(n)) - salsa20.XORKeyStream(keys, keys, nonce, authKey) + binary.BigEndian.PutUint64(nonce[8:], uint64(n)) + chacha20.XORKeyStream(keys, keys, nonce, authKey) for i = 0; i < 8; i++ { v = (b >> uint8(i)) & 1 copy(macKey[:], keys[64*i:64*i+32]) @@ -104,7 +104,7 @@ func Winnow(authKey *[32]byte, noncePrfx, in []byte) ([]byte, error) { } out := make([]byte, len(in)/EnlargeFactor) keys := make([]byte, 8*64) - nonce := make([]byte, 24) + nonce := new([16]byte) copy(nonce[:8], noncePrfx) var i int var v byte @@ -116,8 +116,8 @@ func Winnow(authKey *[32]byte, noncePrfx, in []byte) ([]byte, error) { var is11 bool var is10 bool for n := 0; n < len(out); n++ { - binary.BigEndian.PutUint64(nonce[16:], uint64(n)) - salsa20.XORKeyStream(keys, keys, nonce, authKey) + binary.BigEndian.PutUint64(nonce[8:], uint64(n)) + chacha20.XORKeyStream(keys, keys, nonce, authKey) v = 0 for i = 0; i < 8; i++ { copy(macKey[:], keys[64*i:64*i+32]) diff --git a/src/cypherpunks.ru/govpn/encless.go b/src/cypherpunks.ru/govpn/encless.go index f9d9bbf..bd42f1d 100644 --- a/src/cypherpunks.ru/govpn/encless.go +++ b/src/cypherpunks.ru/govpn/encless.go @@ -35,7 +35,7 @@ const ( // encryption nor steganography) over All-Or-Nothing-Transformed data. // nonce is 64-bit nonce. Output data will be EnclessEnlargeSize larger. // It also consumes 64-bits of entropy. -func EnclessEncode(authKey *[32]byte, nonce, in []byte) ([]byte, error) { +func EnclessEncode(authKey *[32]byte, nonce *[16]byte, in []byte) ([]byte, error) { r := new([aont.RSize]byte) var err error if _, err = io.ReadFull(Rand, r[:]); err != nil { @@ -46,7 +46,7 @@ func EnclessEncode(authKey *[32]byte, nonce, in []byte) ([]byte, error) { return nil, err } out := append( - cnw.Chaff(authKey, nonce, aonted[:aont.RSize]), + cnw.Chaff(authKey, nonce[8:], aonted[:aont.RSize]), aonted[aont.RSize:]..., ) SliceZero(aonted[:aont.RSize]) @@ -54,10 +54,10 @@ func EnclessEncode(authKey *[32]byte, nonce, in []byte) ([]byte, error) { } // Decode EnclessEncode-ed data. -func EnclessDecode(authKey *[32]byte, nonce, in []byte) ([]byte, error) { +func EnclessDecode(authKey *[32]byte, nonce *[16]byte, in []byte) ([]byte, error) { var err error winnowed, err := cnw.Winnow( - authKey, nonce, in[:aont.RSize*cnw.EnlargeFactor], + authKey, nonce[8:], in[:aont.RSize*cnw.EnlargeFactor], ) if err != nil { return nil, err diff --git a/src/cypherpunks.ru/govpn/encless_test.go b/src/cypherpunks.ru/govpn/encless_test.go index 1f9fece..fc00d27 100644 --- a/src/cypherpunks.ru/govpn/encless_test.go +++ b/src/cypherpunks.ru/govpn/encless_test.go @@ -35,9 +35,9 @@ func init() { } func TestEnclessSymmetric(t *testing.T) { - nonce := make([]byte, 8) + nonce := new([16]byte) f := func(pktNum uint64, in []byte) bool { - binary.BigEndian.PutUint64(nonce, pktNum) + binary.BigEndian.PutUint64(nonce[8:], pktNum) encoded, err := EnclessEncode(testKey, nonce, in) if err != nil { return false @@ -54,9 +54,9 @@ func TestEnclessSymmetric(t *testing.T) { } func BenchmarkEnclessEncode(b *testing.B) { - nonce := make([]byte, 8) + nonce := new([16]byte) data := make([]byte, 128) - io.ReadFull(Rand, nonce) + io.ReadFull(Rand, nonce[8:]) io.ReadFull(Rand, data) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -65,9 +65,9 @@ func BenchmarkEnclessEncode(b *testing.B) { } func BenchmarkEnclessDecode(b *testing.B) { - nonce := make([]byte, 8) + nonce := new([16]byte) data := make([]byte, 128) - io.ReadFull(Rand, nonce) + io.ReadFull(Rand, nonce[8:]) io.ReadFull(Rand, data) encoded, _ := EnclessEncode(testKey, nonce, data) b.ResetTimer() diff --git a/src/cypherpunks.ru/govpn/handshake.go b/src/cypherpunks.ru/govpn/handshake.go index 9c536b3..a3ef2b5 100644 --- a/src/cypherpunks.ru/govpn/handshake.go +++ b/src/cypherpunks.ru/govpn/handshake.go @@ -25,11 +25,11 @@ import ( "log" "time" + "chacha20" "github.com/agl/ed25519" "github.com/agl/ed25519/extra25519" - "github.com/dchest/blake2b" + "golang.org/x/crypto/blake2b" "golang.org/x/crypto/curve25519" - "golang.org/x/crypto/salsa20" ) const ( @@ -44,7 +44,7 @@ type Handshake struct { Conf *PeerConf dsaPubH *[ed25519.PublicKeySize]byte key *[32]byte - rNonce *[RSize]byte + rNonce *[16]byte dhPriv *[32]byte // own private DH key rServer *[RSize]byte // random string for authentication rClient *[RSize]byte @@ -88,10 +88,10 @@ func (h *Handshake) Zero() { } } -func (h *Handshake) rNonceNext(count uint64) []byte { - nonce := make([]byte, RSize) - nonceCurrent, _ := binary.Uvarint(h.rNonce[:]) - binary.PutUvarint(nonce, nonceCurrent+count) +func (h *Handshake) rNonceNext(count uint64) *[16]byte { + nonce := new([16]byte) + nonceCurrent, _ := binary.Uvarint(h.rNonce[8:]) + binary.PutUvarint(nonce[8:], nonceCurrent+count) return nonce } @@ -136,7 +136,10 @@ func idTag(id *PeerId, timeSync int, data []byte) []byte { enc := make([]byte, 8) copy(enc, data) AddTimeSync(timeSync, enc) - mac := blake2b.NewMAC(8, id[:]) + mac, err := blake2b.New256(id[:]) + if err != nil { + panic(err) + } mac.Write(enc) mac.Sum(enc[:0]) return enc @@ -150,8 +153,8 @@ func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake { var dhPubRepr *[32]byte state.dhPriv, dhPubRepr = dhKeypairGen() - state.rNonce = new([RSize]byte) - if _, err := io.ReadFull(Rand, state.rNonce[:]); err != nil { + state.rNonce = new([16]byte) + if _, err := io.ReadFull(Rand, state.rNonce[8:]); err != nil { log.Fatalln("Error reading random for nonce:", err) } var enc []byte @@ -163,15 +166,15 @@ func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake { copy(enc, dhPubRepr[:]) if conf.Encless { var err error - enc, err = EnclessEncode(state.dsaPubH, state.rNonce[:], enc) + enc, err = EnclessEncode(state.dsaPubH, state.rNonce, enc) if err != err { panic(err) } } else { - salsa20.XORKeyStream(enc, enc, state.rNonce[:], state.dsaPubH) + chacha20.XORKeyStream(enc, enc, state.rNonce, state.dsaPubH) } - data := append(state.rNonce[:], enc...) - data = append(data, idTag(state.Conf.Id, state.Conf.TimeSync, state.rNonce[:])...) + data := append(state.rNonce[8:], enc...) + data = append(data, idTag(state.Conf.Id, state.Conf.TimeSync, state.rNonce[8:])...) state.conn.Write(data) return state } @@ -185,15 +188,15 @@ func (h *Handshake) Server(data []byte) *Peer { // R + ENC(H(DSAPub), R, El(CDHPub)) + IDtag if h.rNonce == nil && ((!h.Conf.Encless && len(data) >= 48) || (h.Conf.Encless && len(data) == EnclessEnlargeSize+h.Conf.MTU)) { - h.rNonce = new([RSize]byte) - copy(h.rNonce[:], data[:RSize]) + h.rNonce = new([16]byte) + copy(h.rNonce[8:], data[:RSize]) // Decrypt remote public key cDHRepr := new([32]byte) if h.Conf.Encless { out, err := EnclessDecode( h.dsaPubH, - h.rNonce[:], + h.rNonce, data[RSize:len(data)-8], ) if err != nil { @@ -202,7 +205,7 @@ func (h *Handshake) Server(data []byte) *Peer { } copy(cDHRepr[:], out) } else { - salsa20.XORKeyStream(cDHRepr[:], data[RSize:RSize+32], h.rNonce[:], h.dsaPubH) + chacha20.XORKeyStream(cDHRepr[:], data[RSize:RSize+32], h.rNonce, h.dsaPubH) } // Generate DH keypair @@ -225,7 +228,7 @@ func (h *Handshake) Server(data []byte) *Peer { } } else { encPub = make([]byte, 32) - salsa20.XORKeyStream(encPub, dhPubRepr[:], h.rNonceNext(1), h.dsaPubH) + chacha20.XORKeyStream(encPub, dhPubRepr[:], h.rNonceNext(1), h.dsaPubH) } // Generate R* and encrypt them @@ -247,12 +250,12 @@ func (h *Handshake) Server(data []byte) *Peer { } copy(encRs, append(h.rServer[:], h.sServer[:]...)) if h.Conf.Encless { - encRs, err = EnclessEncode(h.key, h.rNonce[:], encRs) + encRs, err = EnclessEncode(h.key, h.rNonce, encRs) if err != nil { panic(err) } } else { - salsa20.XORKeyStream(encRs, encRs, h.rNonce[:], h.key) + chacha20.XORKeyStream(encRs, encRs, h.rNonce, h.key) } // Send that to client @@ -279,7 +282,7 @@ func (h *Handshake) Server(data []byte) *Peer { dec = dec[:RSize+RSize+SSize+ed25519.SignatureSize] } else { dec = make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) - salsa20.XORKeyStream( + chacha20.XORKeyStream( dec, data[:RSize+RSize+SSize+ed25519.SignatureSize], h.rNonceNext(1), @@ -311,7 +314,7 @@ func (h *Handshake) Server(data []byte) *Peer { panic(err) } } else { - salsa20.XORKeyStream(enc, enc, h.rNonceNext(2), h.key) + chacha20.XORKeyStream(enc, enc, h.rNonceNext(2), h.key) } h.conn.Write(append(enc, idTag(h.Conf.Id, h.Conf.TimeSync, enc)...)) @@ -356,7 +359,7 @@ func (h *Handshake) Client(data []byte) *Peer { } copy(sDHRepr[:], tmp[:32]) } else { - salsa20.XORKeyStream(sDHRepr[:], data[:32], h.rNonceNext(1), h.dsaPubH) + chacha20.XORKeyStream(sDHRepr[:], data[:32], h.rNonceNext(1), h.dsaPubH) } // Compute shared key @@ -368,11 +371,7 @@ func (h *Handshake) Client(data []byte) *Peer { h.rServer = new([RSize]byte) h.sServer = new([SSize]byte) if h.Conf.Encless { - tmp, err = EnclessDecode( - h.key, - h.rNonce[:], - data[len(data)/2:len(data)-8], - ) + tmp, err = EnclessDecode(h.key, h.rNonce, data[len(data)/2:len(data)-8]) if err != nil { log.Println("Unable to decode packet from", h.addr, err) return nil @@ -381,7 +380,7 @@ func (h *Handshake) Client(data []byte) *Peer { copy(h.sServer[:], tmp[RSize:RSize+SSize]) } else { decRs := make([]byte, RSize+SSize) - salsa20.XORKeyStream(decRs, data[SSize:SSize+RSize+SSize], h.rNonce[:], h.key) + chacha20.XORKeyStream(decRs, data[SSize:SSize+RSize+SSize], h.rNonce, h.key) copy(h.rServer[:], decRs[:RSize]) copy(h.sServer[:], decRs[RSize:]) } @@ -413,7 +412,7 @@ func (h *Handshake) Client(data []byte) *Peer { panic(err) } } else { - salsa20.XORKeyStream(enc, enc, h.rNonceNext(1), h.key) + chacha20.XORKeyStream(enc, enc, h.rNonceNext(1), h.key) } // Send that to server @@ -435,7 +434,7 @@ func (h *Handshake) Client(data []byte) *Peer { dec = dec[:RSize] } else { dec = make([]byte, RSize) - salsa20.XORKeyStream(dec, data[:RSize], h.rNonceNext(2), h.key) + chacha20.XORKeyStream(dec, data[:RSize], h.rNonceNext(2), h.key) } if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 { log.Println("Invalid client's random number with", h.addr) diff --git a/src/cypherpunks.ru/govpn/identity.go b/src/cypherpunks.ru/govpn/identity.go index 4dc74ee..ece2dfc 100644 --- a/src/cypherpunks.ru/govpn/identity.go +++ b/src/cypherpunks.ru/govpn/identity.go @@ -27,7 +27,7 @@ import ( "sync" "time" - "github.com/dchest/blake2b" + "golang.org/x/crypto/blake2b" ) const ( @@ -73,8 +73,12 @@ func (mc *MACCache) Update(peers *map[PeerId]*PeerConf) { mc.cache[pid].ts = pc.TimeSync } else { log.Println("Adding key", pid) + mac, err := blake2b.New256(pid[:]) + if err != nil { + panic(err) + } mc.cache[pid] = &MACAndTimeSync{ - mac: blake2b.NewMAC(8, pid[:]), + mac: mac, ts: pc.TimeSync, } } diff --git a/src/cypherpunks.ru/govpn/peer.go b/src/cypherpunks.ru/govpn/peer.go index 5a620a9..22c893c 100644 --- a/src/cypherpunks.ru/govpn/peer.go +++ b/src/cypherpunks.ru/govpn/peer.go @@ -28,16 +28,16 @@ import ( "sync/atomic" "time" - "github.com/dchest/blake2b" + "chacha20" + "golang.org/x/crypto/blake2b" "golang.org/x/crypto/poly1305" - "golang.org/x/crypto/salsa20" ) const ( NonceSize = 8 NonceBucketSize = 256 TagSize = poly1305.TagSize - // S20BS is Salsa20's internal blocksize in bytes + // S20BS is ChaCha20's internal blocksize in bytes S20BS = 64 // Maximal amount of bytes transfered with single key (4 GiB) MaxBytesPerKey uint64 = 1 << 32 @@ -51,8 +51,11 @@ const ( func newNonces(key *[32]byte, i uint64) chan *[NonceSize]byte { macKey := make([]byte, 32) - salsa20.XORKeyStream(macKey, make([]byte, 32), make([]byte, 8), key) - mac := blake2b.NewMAC(NonceSize, macKey) + chacha20.XORKeyStream(macKey, make([]byte, 32), new([16]byte), key) + mac, err := blake2b.New256(macKey) + if err != nil { + panic(err) + } nonces := make(chan *[NonceSize]byte, NonceBucketSize*3) go func() { for { @@ -105,6 +108,7 @@ type Peer struct { bufR []byte tagR *[TagSize]byte keyAuthR *[SSize]byte + nonceR *[16]byte pktSizeR int // UDP-related @@ -123,6 +127,7 @@ type Peer struct { bufT []byte tagT *[TagSize]byte keyAuthT *[SSize]byte + nonceT *[16]byte frameT []byte noncesT chan *[NonceSize]byte } @@ -198,7 +203,9 @@ func newPeer(isClient bool, addr string, conn io.Writer, conf *PeerConf, key *[S tagR: new([TagSize]byte), tagT: new([TagSize]byte), keyAuthR: new([SSize]byte), + nonceR: new([16]byte), keyAuthT: new([SSize]byte), + nonceT: new([16]byte), } if isClient { @@ -268,22 +275,19 @@ func (p *Peer) EthProcess(data []byte) { } copy(p.frameT[len(p.frameT)-NonceSize:], (<-p.noncesT)[:]) var out []byte + copy(p.nonceT[8:], p.frameT[len(p.frameT)-NonceSize:]) if p.Encless { var err error - out, err = EnclessEncode( - p.key, - p.frameT[len(p.frameT)-NonceSize:], - p.frameT[:len(p.frameT)-NonceSize], - ) + out, err = EnclessEncode(p.key, p.nonceT, p.frameT[:len(p.frameT)-NonceSize]) if err != nil { panic(err) } out = append(out, p.frameT[len(p.frameT)-NonceSize:]...) } else { - salsa20.XORKeyStream( + chacha20.XORKeyStream( p.bufT[:S20BS+len(p.frameT)-NonceSize], p.bufT[:S20BS+len(p.frameT)-NonceSize], - p.frameT[len(p.frameT)-NonceSize:], + p.nonceT, p.key, ) copy(p.keyAuthT[:], p.bufT[:SSize]) @@ -305,13 +309,10 @@ func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool { } var out []byte p.BusyR.Lock() + copy(p.nonceR[8:], data[len(data)-NonceSize:]) if p.Encless { var err error - out, err = EnclessDecode( - p.key, - data[len(data)-NonceSize:], - data[:len(data)-NonceSize], - ) + out, err = EnclessDecode(p.key, p.nonceR, data[:len(data)-NonceSize]) if err != nil { p.FramesUnauth++ p.BusyR.Unlock() @@ -322,10 +323,10 @@ func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool { p.bufR[i] = 0 } copy(p.bufR[S20BS:], data[TagSize:]) - salsa20.XORKeyStream( + chacha20.XORKeyStream( p.bufR[:S20BS+len(data)-TagSize-NonceSize], p.bufR[:S20BS+len(data)-TagSize-NonceSize], - data[len(data)-NonceSize:], + p.nonceR, p.key, ) copy(p.keyAuthR[:], p.bufR[:SSize]) diff --git a/src/cypherpunks.ru/govpn/tap.go b/src/cypherpunks.ru/govpn/tap.go index 8a44575..9010c55 100644 --- a/src/cypherpunks.ru/govpn/tap.go +++ b/src/cypherpunks.ru/govpn/tap.go @@ -58,7 +58,7 @@ func NewTAP(ifaceName string, mtu int) (*TAP, error) { bufZ = !bufZ n, err = tap.dev.Read(buf) if err != nil { - panic("Reading TAP:" + err.Error()) + panic("Reading TUN/TAP:" + err.Error()) } tap.Sink <- buf[:n] } diff --git a/src/cypherpunks.ru/govpn/tap_linux.go b/src/cypherpunks.ru/govpn/tap_linux.go index fb9df56..8c5e883 100644 --- a/src/cypherpunks.ru/govpn/tap_linux.go +++ b/src/cypherpunks.ru/govpn/tap_linux.go @@ -9,10 +9,15 @@ package govpn import ( "io" + "strings" "github.com/bigeagle/water" ) func newTAPer(ifaceName string) (io.ReadWriter, error) { - return water.NewTAP(ifaceName) + if strings.HasPrefix(ifaceName, "tap") { + return water.NewTAP(ifaceName) + } else { + return water.NewTUN(ifaceName) + } } diff --git a/src/cypherpunks.ru/govpn/verifier.go b/src/cypherpunks.ru/govpn/verifier.go index b68063b..832fafe 100644 --- a/src/cypherpunks.ru/govpn/verifier.go +++ b/src/cypherpunks.ru/govpn/verifier.go @@ -23,6 +23,7 @@ import ( "encoding/base64" "errors" "fmt" + "hash" "io/ioutil" "log" "os" @@ -30,7 +31,7 @@ import ( "cypherpunks.ru/balloon" "github.com/agl/ed25519" - "github.com/dchest/blake2b" + "golang.org/x/crypto/blake2b" "golang.org/x/crypto/ssh/terminal" ) @@ -54,10 +55,18 @@ 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) + if err != nil { + panic(err) + } + return h +} + // Apply the password: create Ed25519 keypair based on it, save public // key in verifier. func (v *Verifier) PasswordApply(password string) *[ed25519.PrivateKeySize]byte { - r := balloon.H(blake2b.New256, []byte(password), v.Id[:], v.S, v.T, v.P) + 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) diff --git a/src/github.com/dchest/blake2b b/src/github.com/dchest/blake2b deleted file mode 160000 index 3c8c640..0000000 --- a/src/github.com/dchest/blake2b +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3c8c640cd7bea3ca78209d812b5854442ab92fed diff --git a/src/golang.org/x/crypto b/src/golang.org/x/crypto index 0e31b18..b2fa06b 160000 --- a/src/golang.org/x/crypto +++ b/src/golang.org/x/crypto @@ -1 +1 @@ -Subproject commit 0e31b188fd38db611d4fbab7de9373a95f36aae5 +Subproject commit b2fa06b6af4b7c9bfeb8569ab7b17f04550717bf diff --git a/utils/makedist.sh b/utils/makedist.sh index 96dfb60..f890c3a 100755 --- a/utils/makedist.sh +++ b/utils/makedist.sh @@ -7,9 +7,9 @@ release=$1 git clone . $tmp/govpn-$release repos=" + src/cypherpunks.ru/balloon src/github.com/agl/ed25519 src/github.com/bigeagle/water - src/github.com/dchest/blake2b src/github.com/go-yaml/yaml src/golang.org/x/crypto " @@ -26,11 +26,11 @@ golang.org/x/crypto/CONTRIBUTORS golang.org/x/crypto/LICENSE golang.org/x/crypto/PATENTS golang.org/x/crypto/README +golang.org/x/crypto/blake2b +golang.org/x/crypto/chacha20poly1305/internal/chacha20 golang.org/x/crypto/curve25519 golang.org/x/crypto/poly1305 -golang.org/x/crypto/salsa20 golang.org/x/crypto/ssh/terminal -golang.org/x/crypto/xtea EOF tar cfCI - src $tmp/includes | tar xfC - $tmp rm -fr src/golang.org @@ -87,13 +87,13 @@ heartbeating, rehandshaking, real-time statistics. Ability to work through UDP, TCP and HTTP proxies. IPv4/IPv6-compatibility. GNU/Linux and FreeBSD support. -----------------8<-----------------8<-----------------8<---------------- +------------------------ >8 ------------------------ The main improvements for that release are: $(git cat-file -p $release | sed -n '6,/^.*BEGIN/p' | sed '$d') -----------------8<-----------------8<-----------------8<---------------- +------------------------ >8 ------------------------ GoVPN's home page is: http://www.govpn.info/ also available as Tor hidden service: http://2wir2p7ibeu72jk3.onion/ @@ -133,13 +133,13 @@ GoVPN это простой демон виртуальных частных с реального времени. Возможность работы поверх UDP, TCP и HTTP прокси. Совместимость с IPv4 и IPv6. Поддержка GNU/Linux и FreeBSD. -----------------8<-----------------8<-----------------8<---------------- +------------------------ >8 ------------------------ Основные усовершенствования в этом релизе: $(git cat-file -p $release | sed -n '6,/^.*BEGIN/p' | sed '$d') -----------------8<-----------------8<-----------------8<---------------- +------------------------ >8 ------------------------ Домашняя страница GoVPN: http://www.govpn.info/ также доступна как скрытый сервис Tor: http://2wir2p7ibeu72jk3.onion/ diff --git a/utils/newclient.sh b/utils/newclient.sh index aebc975..98957ef 100755 --- a/utils/newclient.sh +++ b/utils/newclient.sh @@ -26,6 +26,6 @@ Place the following YAML configuration entry on the server's side: $username: up: /path/to/up.sh - iface: or TAP interface name + iface: or TUN/TAP interface name verifier: $verifierS EOF