]> Cypherpunks.ru repositories - govpn.git/blobdiff - src/cypherpunks.ru/govpn/identify.go
Add time synchronization requirement option
[govpn.git] / src / cypherpunks.ru / govpn / identify.go
index 0583921e668c0a604650abaaed45ccef708405e2..f85631b01839639b8bf981572f4c8b6db106c984 100644 (file)
@@ -21,8 +21,10 @@ package govpn
 import (
        "crypto/subtle"
        "encoding/base64"
+       "encoding/binary"
        "log"
        "sync"
+       "time"
 
        "golang.org/x/crypto/xtea"
 )
@@ -41,43 +43,56 @@ func (id PeerId) MarshalJSON() ([]byte, error) {
        return []byte(`"` + id.String() + `"`), nil
 }
 
+type CipherAndTimeSync struct {
+       c *xtea.Cipher
+       t int
+}
+
 type CipherCache struct {
-       c map[PeerId]*xtea.Cipher
+       c map[PeerId]*CipherAndTimeSync
        l sync.RWMutex
 }
 
-func NewCipherCache(peerIds []PeerId) *CipherCache {
-       cc := CipherCache{c: make(map[PeerId]*xtea.Cipher, len(peerIds))}
-       cc.Update(peerIds)
-       return &cc
+func NewCipherCache() *CipherCache {
+       return &CipherCache{c: make(map[PeerId]*CipherAndTimeSync)}
 }
 
 // Remove disappeared keys, add missing ones with initialized ciphers.
-func (cc *CipherCache) Update(peerIds []PeerId) {
-       available := make(map[PeerId]struct{})
-       for _, peerId := range peerIds {
-               available[peerId] = struct{}{}
-       }
+func (cc *CipherCache) Update(peers *map[PeerId]*PeerConf) {
        cc.l.Lock()
-       for k, _ := range cc.c {
-               if _, exists := available[k]; !exists {
-                       log.Println("Cleaning key:", k)
-                       delete(cc.c, k)
+       for pid, _ := range cc.c {
+               if _, exists := (*peers)[pid]; !exists {
+                       log.Println("Cleaning key:", pid)
+                       delete(cc.c, pid)
                }
        }
-       for peerId, _ := range available {
-               if _, exists := cc.c[peerId]; !exists {
-                       log.Println("Adding key", peerId)
-                       cipher, err := xtea.NewCipher(peerId[:])
+       for pid, pc := range *peers {
+               if _, exists := cc.c[pid]; exists {
+                       cc.c[pid].t = pc.TimeSync
+               } else {
+                       log.Println("Adding key", pid)
+                       cipher, err := xtea.NewCipher(pid[:])
                        if err != nil {
                                panic(err)
                        }
-                       cc.c[peerId] = cipher
+                       cc.c[pid] = &CipherAndTimeSync{cipher, pc.TimeSync}
                }
        }
        cc.l.Unlock()
 }
 
+// If timeSync > 0, then XOR timestamp with the data.
+func AddTimeSync(ts int, data []byte) {
+       if ts == 0 {
+               return
+       }
+       buf := make([]byte, 8)
+       binary.BigEndian.PutUint64(buf, uint64(time.Now().Unix()/int64(ts)*int64(ts)))
+       for i := 0; i < 8; i++ {
+               data[i] ^= buf[i]
+       }
+}
+
 // Try to find peer's identity (that equals to an encryption key)
 // by taking first blocksize sized bytes from data at the beginning
 // as plaintext and last bytes as cyphertext.
@@ -87,8 +102,9 @@ func (cc *CipherCache) Find(data []byte) *PeerId {
        }
        buf := make([]byte, xtea.BlockSize)
        cc.l.RLock()
-       for pid, cipher := range cc.c {
-               cipher.Decrypt(buf, data[len(data)-xtea.BlockSize:])
+       for pid, ct := range cc.c {
+               ct.c.Decrypt(buf, data[len(data)-xtea.BlockSize:])
+               AddTimeSync(ct.t, buf)
                if subtle.ConstantTimeCompare(buf, data[:xtea.BlockSize]) == 1 {
                        ppid := PeerId(pid)
                        cc.l.RUnlock()