2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2017 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/blake2b"
33 // IDSize is size a GoVPN peer ID must be
34 const IDSize = 128 / 8
36 // PeerID is identifier of a single GoVPN peer (client)
37 type PeerID [IDSize]byte
39 // String return a string from a peer ID
40 func (id PeerID) String() string {
41 return base64.RawStdEncoding.EncodeToString(id[:])
44 // MarshalJSON return a JSON string from a peer ID
45 func (id PeerID) MarshalJSON() ([]byte, error) {
46 return []byte(`"` + id.String() + `"`), nil
49 // MACAndTimeSync is a single peer MAC and timesync
50 type MACAndTimeSync struct {
56 // MACCache cache all MACAndTimeSync for peers allowed to connect
57 type MACCache struct {
58 cache map[PeerID]*MACAndTimeSync
62 // NewMACCache return a new MACCache instance
63 func NewMACCache() *MACCache {
64 return &MACCache{cache: make(map[PeerID]*MACAndTimeSync)}
67 // Update remove disappeared keys, add missing ones with initialized MACs.
68 func (mc *MACCache) Update(peers *map[PeerID]*PeerConf) {
70 for pid := range mc.cache {
71 if _, exists := (*peers)[pid]; !exists {
72 log.Println("Cleaning key:", pid)
76 for pid, pc := range *peers {
77 if _, exists := mc.cache[pid]; exists {
78 mc.cache[pid].ts = pc.TimeSync
80 log.Println("Adding key", pid)
81 mac, err := blake2b.New256(pid[:])
85 mc.cache[pid] = &MACAndTimeSync{
94 // AddTimeSync XOR timestamp with data if timeSync > 0
95 func AddTimeSync(ts int, data []byte) {
99 buf := make([]byte, 8)
100 binary.BigEndian.PutUint64(buf, uint64(time.Now().Unix()/int64(ts)*int64(ts)))
101 for i := 0; i < 8; i++ {
106 // Find try to find peer's identity (that equals to MAC)
107 // by taking first blocksize sized bytes from data at the beginning
108 // as plaintext and last bytes as cyphertext.
109 func (mc *MACCache) Find(data []byte) *PeerID {
113 buf := make([]byte, 8)
114 sum := make([]byte, 32)
116 for pid, mt := range mc.cache {
118 AddTimeSync(mt.ts, buf)
124 if subtle.ConstantTimeCompare(sum[len(sum)-8:], data[len(data)-8:]) == 1 {