]> Cypherpunks.ru repositories - govpn.git/blob - handshake.go
Obfuscate/randomize message nonces
[govpn.git] / handshake.go
1 /*
2 govpn -- Simple secure virtual private network daemon
3 Copyright (C) 2014-2015 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 main
20
21 import (
22         "crypto/rand"
23         "crypto/subtle"
24         "encoding/binary"
25         "fmt"
26         "net"
27         "time"
28
29         "golang.org/x/crypto/curve25519"
30         "golang.org/x/crypto/poly1305"
31         "golang.org/x/crypto/salsa20"
32         "golang.org/x/crypto/salsa20/salsa"
33         "golang.org/x/crypto/xtea"
34 )
35
36 type Handshake struct {
37         addr     *net.UDPAddr
38         lastPing time.Time
39         rNonce   *[8]byte
40         dhPriv   *[32]byte // own private DH key
41         key      *[32]byte // handshake encryption key
42         rServer  *[8]byte  // random string for authentication
43         rClient  *[8]byte
44         sServer  *[32]byte // secret string for main key calculation
45         sClient  *[32]byte
46 }
47
48 func KeyFromSecrets(server, client []byte) *[32]byte {
49         k := new([32]byte)
50         for i := 0; i < 32; i++ {
51                 k[i] = server[i] ^ client[i]
52         }
53         return k
54 }
55
56 func NewNonceCipher(key *[32]byte) *xtea.Cipher {
57         nonceKey := make([]byte, 16)
58         salsa20.XORKeyStream(nonceKey, make([]byte, 32), make([]byte, 8), key)
59         ciph, err := xtea.NewCipher(nonceKey)
60         if err != nil {
61                 panic(err)
62         }
63         return ciph
64 }
65
66 // Check if it is valid handshake-related message
67 // Minimal size and last 16 zero bytes
68 func isValidHandshakePkt(pkt []byte) bool {
69         if len(pkt) < 24 {
70                 return false
71         }
72         for i := len(pkt) - poly1305.TagSize; i < len(pkt); i++ {
73                 if pkt[i] != '\x00' {
74                         return false
75                 }
76         }
77         return true
78 }
79
80 func (h *Handshake) rNonceNext() []byte {
81         nonce := make([]byte, 8)
82         nonceCurrent, _ := binary.Uvarint(h.rNonce[:])
83         binary.PutUvarint(nonce, nonceCurrent+1)
84         return nonce
85 }
86
87 func dhPrivGen() *[32]byte {
88         dh := new([32]byte)
89         if _, err := rand.Read(dh[:]); err != nil {
90                 panic("Can not read random for DH private key")
91         }
92         return dh
93 }
94
95 func dhKeyGen(priv, pub *[32]byte) *[32]byte {
96         key := new([32]byte)
97         curve25519.ScalarMult(key, priv, pub)
98         salsa.HSalsa20(key, new([16]byte), key, &salsa.Sigma)
99         return key
100 }
101
102 func HandshakeStart(conn *net.UDPConn, addr *net.UDPAddr, key *[32]byte) *Handshake {
103         state := Handshake{}
104         state.addr = addr
105         state.lastPing = time.Now()
106
107         state.dhPriv = dhPrivGen()
108         dhPub := new([32]byte)
109         curve25519.ScalarBaseMult(dhPub, state.dhPriv)
110
111         state.rNonce = new([8]byte)
112         if _, err := rand.Read(state.rNonce[:]); err != nil {
113                 panic("Can not read random for handshake nonce")
114         }
115         enc := make([]byte, 32)
116         salsa20.XORKeyStream(enc, dhPub[:], state.rNonce[:], key)
117
118         if _, err := conn.WriteTo(
119                 append(state.rNonce[:],
120                         append(enc, make([]byte, poly1305.TagSize)...)...), addr); err != nil {
121                 panic(err)
122         }
123         return &state
124 }
125
126 func (h *Handshake) Server(noncediff uint64, conn *net.UDPConn, key *[32]byte, data []byte) *Peer {
127         switch len(data) {
128         case 56: // R + ENC(PSK, dh_client_pub) + NULLs
129                 fmt.Print("[HS1]")
130                 if h.rNonce != nil {
131                         fmt.Print("[S?]")
132                         return nil
133                 }
134
135                 // Generate private DH key
136                 h.dhPriv = dhPrivGen()
137                 dhPub := new([32]byte)
138                 curve25519.ScalarBaseMult(dhPub, h.dhPriv)
139
140                 // Decrypt remote public key and compute shared key
141                 dec := new([32]byte)
142                 salsa20.XORKeyStream(dec[:], data[8:8+32], data[:8], key)
143                 h.key = dhKeyGen(h.dhPriv, dec)
144
145                 // Compute nonce and encrypt our public key
146                 h.rNonce = new([8]byte)
147                 copy(h.rNonce[:], data[:8])
148
149                 encPub := make([]byte, 32)
150                 salsa20.XORKeyStream(encPub, dhPub[:], h.rNonceNext(), key)
151
152                 // Generate R* and encrypt them
153                 h.rServer = new([8]byte)
154                 if _, err := rand.Read(h.rServer[:]); err != nil {
155                         panic("Can not read random for handshake random key")
156                 }
157                 h.sServer = new([32]byte)
158                 if _, err := rand.Read(h.sServer[:]); err != nil {
159                         panic("Can not read random for handshake shared key")
160                 }
161                 encRs := make([]byte, 8+32)
162                 salsa20.XORKeyStream(encRs, append(h.rServer[:], h.sServer[:]...), h.rNonce[:], h.key)
163
164                 // Send that to client
165                 if _, err := conn.WriteTo(
166                         append(encPub,
167                                 append(encRs, make([]byte, poly1305.TagSize)...)...), h.addr); err != nil {
168                         panic(err)
169                 }
170                 fmt.Print("[OK]")
171         case 64: // ENC(K, RS + RC + SC) + NULLs
172                 fmt.Print("[HS3]")
173                 if (h.rNonce == nil) || (h.rClient != nil) {
174                         fmt.Print("[S?]")
175                         return nil
176                 }
177
178                 // Decrypt Rs compare rServer
179                 decRs := make([]byte, 8+8+32)
180                 salsa20.XORKeyStream(decRs, data[:8+8+32], h.rNonceNext(), h.key)
181                 if res := subtle.ConstantTimeCompare(decRs[:8], h.rServer[:]); res != 1 {
182                         fmt.Print("[rS?]")
183                         return nil
184                 }
185
186                 // Send final answer to client
187                 enc := make([]byte, 8)
188                 salsa20.XORKeyStream(enc, decRs[8:8+8], make([]byte, 8), h.key)
189                 if _, err := conn.WriteTo(append(enc, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
190                         panic(err)
191                 }
192
193                 // Switch peer
194                 peer := Peer{
195                         addr:      h.addr,
196                         nonceOur:  noncediff + 0,
197                         nonceRecv: noncediff + 0,
198                         key:       KeyFromSecrets(h.sServer[:], decRs[8+8:]),
199                 }
200                 peer.nonceCipher = NewNonceCipher(peer.key)
201                 fmt.Print("[OK]")
202                 return &peer
203         default:
204                 fmt.Print("[HS?]")
205         }
206         return nil
207 }
208
209 func (h *Handshake) Client(noncediff uint64, conn *net.UDPConn, key *[32]byte, data []byte) *Peer {
210         switch len(data) {
211         case 88: // ENC(PSK, dh_server_pub) + ENC(K, RS + SS) + NULLs
212                 fmt.Print("[HS2]")
213                 if h.key != nil {
214                         fmt.Print("[S?]")
215                         return nil
216                 }
217
218                 // Decrypt remote public key and compute shared key
219                 dec := new([32]byte)
220                 salsa20.XORKeyStream(dec[:], data[:32], h.rNonceNext(), key)
221                 h.key = dhKeyGen(h.dhPriv, dec)
222
223                 // Decrypt Rs
224                 decRs := make([]byte, 8+32)
225                 salsa20.XORKeyStream(decRs, data[32:32+8+32], h.rNonce[:], h.key)
226                 h.rServer = new([8]byte)
227                 copy(h.rServer[:], decRs[:8])
228                 h.sServer = new([32]byte)
229                 copy(h.sServer[:], decRs[8:])
230
231                 // Generate R* and encrypt them
232                 h.rClient = new([8]byte)
233                 if _, err := rand.Read(h.rClient[:]); err != nil {
234                         panic("Can not read random for handshake random key")
235                 }
236                 h.sClient = new([32]byte)
237                 if _, err := rand.Read(h.sClient[:]); err != nil {
238                         panic("Can not read random for handshake shared key")
239                 }
240                 encRs := make([]byte, 8+8+32)
241                 salsa20.XORKeyStream(encRs,
242                         append(h.rServer[:],
243                                 append(h.rClient[:], h.sClient[:]...)...), h.rNonceNext(), h.key)
244
245                 // Send that to server
246                 if _, err := conn.WriteTo(append(encRs, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
247                         panic(err)
248                 }
249                 fmt.Print("[OK]")
250         case 24: // ENC(K, RC) + NULLs
251                 fmt.Print("[HS4]")
252                 if h.key == nil {
253                         fmt.Print("[S?]")
254                         return nil
255                 }
256
257                 // Decrypt rClient
258                 dec := make([]byte, 8)
259                 salsa20.XORKeyStream(dec, data[:8], make([]byte, 8), h.key)
260                 if res := subtle.ConstantTimeCompare(dec, h.rClient[:]); res != 1 {
261                         fmt.Print("[rC?]")
262                         return nil
263                 }
264
265                 // Switch peer
266                 peer := Peer{
267                         addr:      h.addr,
268                         nonceOur:  noncediff + 1,
269                         nonceRecv: noncediff + 0,
270                         key:       KeyFromSecrets(h.sServer[:], h.sClient[:]),
271                 }
272                 peer.nonceCipher = NewNonceCipher(peer.key)
273                 fmt.Print("[OK]")
274                 return &peer
275         default:
276                 fmt.Print("[HS?]")
277         }
278         return nil
279 }