2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
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.
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.
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/>.
30 "golang.org/x/crypto/curve25519"
31 "golang.org/x/crypto/poly1305"
32 "golang.org/x/crypto/salsa20"
33 "golang.org/x/crypto/salsa20/salsa"
34 "golang.org/x/crypto/xtea"
37 type Handshake struct {
42 dhPriv *[32]byte // own private DH key
43 key *[KeySize]byte // handshake encryption key
44 rServer *[8]byte // random string for authentication
46 sServer *[32]byte // secret string for main key calculation
50 func keyFromSecrets(server, client []byte) *[KeySize]byte {
52 for i := 0; i < 32; i++ {
53 k[i] = server[i] ^ client[i]
58 // Check if it is valid handshake-related message.
59 // Minimal size and last 16 zero bytes.
60 func IsValidHandshakePkt(pkt []byte) bool {
64 for i := len(pkt) - poly1305.TagSize; i < len(pkt); i++ {
72 func (h *Handshake) rNonceNext() []byte {
73 nonce := make([]byte, 8)
74 nonceCurrent, _ := binary.Uvarint(h.rNonce[:])
75 binary.PutUvarint(nonce, nonceCurrent+1)
79 func dhPrivGen() *[32]byte {
81 if _, err := rand.Read(dh[:]); err != nil {
82 panic("Can not read random for DH private key")
87 func dhKeyGen(priv, pub *[32]byte) *[32]byte {
89 curve25519.ScalarMult(key, priv, pub)
90 salsa.HSalsa20(key, new([16]byte), key, &salsa.Sigma)
94 // Create new handshake state.
95 func HandshakeNew(addr *net.UDPAddr) *Handshake {
103 // Start handshake's procedure from the client.
104 // It is the entry point for starting the handshake procedure.
105 // You have to specify outgoing conn address, remote's addr address,
106 // our own identification and an encryption key. First handshake packet
107 // will be sent immediately.
108 func HandshakeStart(conn *net.UDPConn, addr *net.UDPAddr, id *PeerId, key *[32]byte) *Handshake {
109 state := HandshakeNew(addr)
111 state.dhPriv = dhPrivGen()
112 dhPub := new([32]byte)
113 curve25519.ScalarBaseMult(dhPub, state.dhPriv)
115 state.rNonce = new([8]byte)
116 if _, err := rand.Read(state.rNonce[:]); err != nil {
117 panic("Can not read random for handshake nonce")
119 enc := make([]byte, 32)
120 salsa20.XORKeyStream(enc, dhPub[:], state.rNonce[:], key)
122 ciph, err := xtea.NewCipher(id[:])
126 rEnc := make([]byte, xtea.BlockSize)
127 ciph.Encrypt(rEnc, state.rNonce[:])
129 data := append(state.rNonce[:], enc...)
130 data = append(data, rEnc...)
131 data = append(data, '\x00')
132 data = append(data, make([]byte, poly1305.TagSize)...)
134 if _, err := conn.WriteTo(data, addr); err != nil {
140 // Process handshake message on the server side.
141 // This function is intended to be called on server's side.
142 // Our outgoing conn connection and received data are required.
143 // If this is the final handshake message, then new Peer object
144 // will be created and used as a transport. If no mutually
145 // authenticated Peer is ready, then return nil.
146 func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
148 case 65: // R + ENC(PSK, dh_client_pub) + xtea(ID, R) + NULL + NULLs
150 log.Println("Invalid handshake stage from", h.addr)
154 // Try to determine client's ID
155 id := IDsCache.Find(data[:8], data[8+32:8+32+8])
157 log.Println("Unknown identity from", h.addr)
160 key := KeyRead(path.Join(PeersPath, id.String(), "key"))
163 // Generate private DH key
164 h.dhPriv = dhPrivGen()
165 dhPub := new([32]byte)
166 curve25519.ScalarBaseMult(dhPub, h.dhPriv)
168 // Decrypt remote public key and compute shared key
170 salsa20.XORKeyStream(dec[:], data[8:8+32], data[:8], key)
171 h.key = dhKeyGen(h.dhPriv, dec)
173 // Compute nonce and encrypt our public key
174 h.rNonce = new([8]byte)
175 copy(h.rNonce[:], data[:8])
177 encPub := make([]byte, 32)
178 salsa20.XORKeyStream(encPub, dhPub[:], h.rNonceNext(), key)
180 // Generate R* and encrypt them
181 h.rServer = new([8]byte)
182 if _, err := rand.Read(h.rServer[:]); err != nil {
183 panic("Can not read random for handshake random key")
185 h.sServer = new([32]byte)
186 if _, err := rand.Read(h.sServer[:]); err != nil {
187 panic("Can not read random for handshake shared key")
189 encRs := make([]byte, 8+32)
190 salsa20.XORKeyStream(encRs, append(h.rServer[:], h.sServer[:]...), h.rNonce[:], h.key)
192 // Send that to client
193 if _, err := conn.WriteTo(
195 append(encRs, make([]byte, poly1305.TagSize)...)...), h.addr); err != nil {
198 h.LastPing = time.Now()
199 case 64: // ENC(K, RS + RC + SC) + NULLs
200 if (h.rNonce == nil) || (h.rClient != nil) {
201 log.Println("Invalid handshake stage from", h.addr)
205 // Decrypted Rs compare rServer
206 decRs := make([]byte, 8+8+32)
207 salsa20.XORKeyStream(decRs, data[:8+8+32], h.rNonceNext(), h.key)
208 if subtle.ConstantTimeCompare(decRs[:8], h.rServer[:]) != 1 {
209 log.Println("Invalid server's random number with", h.addr)
213 // Send final answer to client
214 enc := make([]byte, 8)
215 salsa20.XORKeyStream(enc, decRs[8:8+8], make([]byte, 8), h.key)
216 if _, err := conn.WriteTo(append(enc, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
221 peer := newPeer(h.addr, h.Id, 0, keyFromSecrets(h.sServer[:], decRs[8+8:]))
222 h.LastPing = time.Now()
225 log.Println("Invalid handshake message from", h.addr)
230 // Process handshake message on the client side.
231 // This function is intended to be called on client's side.
232 // Our outgoing conn connection, authentication key and received data
233 // are required. Client does not work with identities, as he is the
234 // only one, so key is a requirement.
235 // If this is the final handshake message, then new Peer object
236 // will be created and used as a transport. If no mutually
237 // authenticated Peer is ready, then return nil.
238 func (h *Handshake) Client(conn *net.UDPConn, key *[KeySize]byte, data []byte) *Peer {
240 case 88: // ENC(PSK, dh_server_pub) + ENC(K, RS + SS) + NULLs
242 log.Println("Invalid handshake stage from", h.addr)
246 // Decrypt remote public key and compute shared key
248 salsa20.XORKeyStream(dec[:], data[:32], h.rNonceNext(), key)
249 h.key = dhKeyGen(h.dhPriv, dec)
252 decRs := make([]byte, 8+32)
253 salsa20.XORKeyStream(decRs, data[32:32+8+32], h.rNonce[:], h.key)
254 h.rServer = new([8]byte)
255 copy(h.rServer[:], decRs[:8])
256 h.sServer = new([32]byte)
257 copy(h.sServer[:], decRs[8:])
259 // Generate R* and encrypt them
260 h.rClient = new([8]byte)
261 if _, err := rand.Read(h.rClient[:]); err != nil {
262 panic("Can not read random for handshake random key")
264 h.sClient = new([32]byte)
265 if _, err := rand.Read(h.sClient[:]); err != nil {
266 panic("Can not read random for handshake shared key")
268 encRs := make([]byte, 8+8+32)
269 salsa20.XORKeyStream(encRs,
271 append(h.rClient[:], h.sClient[:]...)...), h.rNonceNext(), h.key)
273 // Send that to server
274 if _, err := conn.WriteTo(append(encRs, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
277 h.LastPing = time.Now()
278 case 24: // ENC(K, RC) + NULLs
280 log.Println("Invalid handshake stage from", h.addr)
285 dec := make([]byte, 8)
286 salsa20.XORKeyStream(dec, data[:8], make([]byte, 8), h.key)
287 if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 {
288 log.Println("Invalid client's random number with", h.addr)
293 peer := newPeer(h.addr, h.Id, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
294 h.LastPing = time.Now()
297 log.Println("Invalid handshake message from", h.addr)