summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Barksdale <amatus.amongus@gmail.com>2010-10-18 18:29:12 -0700
committerDavid Barksdale <amatus.amongus@gmail.com>2010-10-18 18:29:12 -0700
commitf6445be6adb07426d0fe26f62bc2b88639f064af (patch)
tree63ff966deb05e2b77924953e3b5850584c86c921
parent3842e519d2571c3155df0d558b528fe52514ceb2 (diff)
Added CORE_PING support. Fixed AES key encoding. Now peers have connected state.
-rw-r--r--src/org/gnu/clojure/gnunet/core.clj139
-rw-r--r--src/org/gnu/clojure/gnunet/crypto.clj17
-rw-r--r--src/org/gnu/clojure/gnunet/peer.clj3
-rw-r--r--src/org/gnu/clojure/gnunet/transport.clj13
-rw-r--r--src/org/gnu/clojure/gnunet/udp.clj14
5 files changed, 135 insertions, 51 deletions
diff --git a/src/org/gnu/clojure/gnunet/core.clj b/src/org/gnu/clojure/gnunet/core.clj
index e2bbe7b..b7f476c 100644
--- a/src/org/gnu/clojure/gnunet/core.clj
+++ b/src/org/gnu/clojure/gnunet/core.clj
@@ -65,6 +65,14 @@
:peer-id peer-id
:challenge challenge}))
+(defn encode-core-pong
+ [pong]
+ (concat
+ (encode-int32 (:iv-seed pong))
+ (encode-int32 (:challenge pong))
+ (encode-int32 (:inbound-bw-limit pong))
+ (:peer-id pong)))
+
(defn derive-iv
[aes-key seed peer-id]
(derive-aes-iv aes-key
@@ -73,6 +81,15 @@
peer-id
(encode-utf8 "initialization vector"))))
+(defn derive-pong-iv
+ [aes-key seed challenge peer-id]
+ (derive-aes-iv aes-key
+ (encode-int32 seed)
+ (concat
+ peer-id
+ (encode-int32 challenge)
+ (encode-utf8 "pong initialization vector"))))
+
(defn encrypt-message
[aes-key iv message]
(let [iv-seed (take 4 message)
@@ -81,6 +98,14 @@
iv-seed
(aes-encrypt aes-key iv plaintext))))
+(defn decrypt-message
+ [aes-key iv message]
+ (let [iv-seed (take 4 message)
+ ciphertext (drop 4 message)]
+ (concat
+ iv-seed
+ (aes-decrypt aes-key iv ciphertext))))
+
(defn emit-messages!
[peer remote-peer messages]
(send (:state-agent remote-peer)
@@ -104,8 +129,9 @@
set-key {:sender-status (:status state)
:creation-time (:encrypt-key-created state)
:peer-id (:id remote-peer)
- :encrypted-key (rsa-encrypt! (:public-key peer)
- (:encrypt-key state)
+ :encrypted-key (rsa-encrypt!
+ public-key
+ (encode-aes-key (:encrypt-key state))
(:random peer))}
signed-material (encode-set-key-signed-material set-key)
signature (rsa-sign (:private-key peer) signed-material)
@@ -116,9 +142,9 @@
:challenge (:ping-challenge state)
:peer-id (:id remote-peer)}
encoded-ping (encode-core-ping ping)
- iv (derive-iv (:encrypt-key state) iv-seed (:id remote-peer))
- encrypted-ping (encrypt-message (:encrypt-key state) iv
- encoded-ping)]
+ aes-key (:encrypt-key state)
+ iv (derive-iv aes-key iv-seed (:id remote-peer))
+ encrypted-ping (encrypt-message aes-key iv encoded-ping)]
(emit-messages! peer remote-peer
[{:message-type message-type-core-set-key
:bytes encoded-set-key}
@@ -141,53 +167,88 @@
(and
(or (= status peer-status-key-received)
(= status peer-status-key-confirmed))
- (< (:creation-time set-key) decrypt-key-created)) nil
- :else set-key)))))
+ (< 0 (.compareTo decrypt-key-created (:creation-time set-key)))) nil
+ :else (when-let [decrypted-key (rsa-decrypt (:private-key peer)
+ (:encrypted-key set-key))]
+ ;; XXX: For some reason we end up with an extra 0 byte at the
+ ;; beginning of the decrypted-key when the MSB is 1.
+ (let [decrypted-key (drop (- (count decrypted-key)
+ aes-key-size 4)
+ decrypted-key)]
+ (when-let [decrypt-key (first
+ (parse-aes-key decrypted-key))]
+ (assoc set-key :decrypt-key decrypt-key)))))))))
(defn handle-set-key!
[peer remote-peer message]
(send (:state-agent remote-peer)
(fn [state]
(if-let [set-key (verify-set-key peer remote-peer state message)]
- (if-let [decrypt-key (rsa-decrypt (:private-key peer)
- (:encrypted-key set-key))]
- (let [state (assoc state :decrypt-key decrypt-key)
- decrypt-key-created (state :decrypt-key-created (Date. 0))
- creation-time (:creation-time set-key)
- state (if (= decrypt-key-created creation-time)
- state
- (conj state {:last-sequence-number-received 0
- :last-packets-bitmap 0
- :decrypt-key-created creation-time}))
- status (state :status peer-status-down)
- sender-status (:sender-status set-key)]
- (condp contains? status
- #{peer-status-down}
- (do (send-key! peer remote-peer)
- (assoc state :status peer-status-key-received))
- #{peer-status-key-sent
- peer-status-key-received}
- (do (if (and (not (= sender-status peer-status-key-received))
- (not (= sender-status peer-status-key-confirmed)))
- (send-key! peer remote-peer))
- (assoc state :status peer-status-key-received))
- #{peer-status-key-confirmed}
- (do (if (and (not (= sender-status peer-status-key-received))
- (not (= sender-status peer-status-key-confirmed)))
- (send-key! peer remote-peer))
- state)
- state))
- state)
+ (let [decrypt-key (:decrypt-key set-key)
+ state (assoc state :decrypt-key decrypt-key)
+ decrypt-key-created (:decrypt-key-created state)
+ creation-time (:creation-time set-key)
+ state (if (= decrypt-key-created creation-time)
+ state
+ (conj state {:last-sequence-number-received 0
+ :last-packets-bitmap 0
+ :decrypt-key-created creation-time}))
+ status (:status state)
+ sender-status (:sender-status set-key)]
+ (condp contains? status
+ #{peer-status-down}
+ (do (send-key! peer remote-peer)
+ (assoc state :status peer-status-key-received))
+ #{peer-status-key-sent
+ peer-status-key-received}
+ (do (if (and (not (= sender-status peer-status-key-received))
+ (not (= sender-status peer-status-key-confirmed)))
+ (send-key! peer remote-peer))
+ (assoc state :status peer-status-key-received))
+ #{peer-status-key-confirmed}
+ (do (if (and (not (= sender-status peer-status-key-received))
+ (not (= sender-status peer-status-key-confirmed)))
+ (send-key! peer remote-peer))
+ state)
+ state))
state))))
+(defn handle-core-ping!
+ [peer remote-peer message]
+ (send (:state-agent remote-peer)
+ (fn [state]
+ (when-let [decrypt-key (:decrypt-key state)]
+ (when-let [ping (first (parse-core-ping (:bytes message)))]
+ (let [iv (derive-iv decrypt-key (:iv-seed ping) (:id peer))
+ decrypted-message (decrypt-message decrypt-key iv
+ (:bytes message))]
+ (when-let [ping (first (parse-core-ping decrypted-message))]
+ (when (= (:peer-id ping) (:id peer))
+ (let [iv-seed (.nextInt (:random peer))
+ pong {:iv-seed iv-seed
+ :challenge (:challenge ping)
+ :inbound-bw-limit (:bw-in state)
+ :peer-id (:id peer)}
+ encoded-pong (encode-core-pong pong)
+ aes-key (:encrypt-key state)
+ iv (derive-pong-iv aes-key iv-seed (:challenge pong)
+ (:id remote-peer))
+ encrypted-pong (encrypt-message aes-key iv encoded-pong)]
+ (emit-messages! peer remote-peer
+ [{:message-type message-type-core-pong
+ :bytes encrypted-pong}])))))))
+ state)))
+
(defn initialize-remote-peer-state
[peer state]
(conj state
{:status peer-status-down
- :decrypt-key-created (Date. 0)
+ :decrypt-key-created (Date. (long 0))
:encrypt-key (generate-aes-key! (:random peer))
:encrypt-key-created (Date.)
- :ping-challenge (.nextInt (:random peer))}))
+ :ping-challenge (.nextInt (:random peer))
+ ;; TODO: Make this a real number
+ :bw-in 20000}))
(defn handle-receive!
[peer remote-peer message]
@@ -199,7 +260,7 @@
(condp = (:message-type message)
message-type-core-set-key (handle-set-key! peer remote-peer message)
message-type-core-encrypted-message nil
- message-type-core-ping nil
+ message-type-core-ping (handle-core-ping! peer remote-peer message)
message-type-core-pong nil
nil)
state))))
diff --git a/src/org/gnu/clojure/gnunet/crypto.clj b/src/org/gnu/clojure/gnunet/crypto.clj
index a102194..acbdca7 100644
--- a/src/org/gnu/clojure/gnunet/crypto.clj
+++ b/src/org/gnu/clojure/gnunet/crypto.clj
@@ -2,6 +2,7 @@
(:use (org.gnu.clojure.gnunet parser message primes)
clojure.contrib.monads clojure.test)
(:import java.math.BigInteger
+ java.util.zip.CRC32
(java.security KeyPairGenerator KeyFactory MessageDigest Signature)
(java.security.spec RSAKeyGenParameterSpec RSAPublicKeySpec
RSAPrivateCrtKeySpec)
@@ -64,6 +65,22 @@
(.generateSecret (SecretKeyFactory/getInstance "AES")
(SecretKeySpec. (byte-array byte-seq) "AES")))
+(defn crc32
+ [byte-seq]
+ (.getValue (doto (CRC32.) (.update (byte-array byte-seq)))))
+
+(defn encode-aes-key
+ [aes-key]
+ (concat
+ (.getEncoded aes-key)
+ (encode-int32 (crc32 (.getEncoded aes-key)))))
+
+(def parse-aes-key
+ (domonad parser-m [aes-key (items aes-key-size)
+ checksum parse-uint32
+ :when (= checksum (crc32 aes-key))]
+ (make-aes-key aes-key)))
+
(defn generate-aes-key!
[random]
(.generateKey (doto (KeyGenerator/getInstance "AES")
diff --git a/src/org/gnu/clojure/gnunet/peer.clj b/src/org/gnu/clojure/gnunet/peer.clj
index dcae622..aa51859 100644
--- a/src/org/gnu/clojure/gnunet/peer.clj
+++ b/src/org/gnu/clojure/gnunet/peer.clj
@@ -26,7 +26,8 @@
;; :decrypt-key-created (java.util.Date)
;; :encrypt-key (java.security.Key)
;; :encrypt-key-created (java.util.Date)
- ;; :ping-challenge (int) }
+ ;; :ping-challenge (int)
+ ;; :bw-in (int) }
:state-agent)
(def peer-struct (apply create-struct (concat
diff --git a/src/org/gnu/clojure/gnunet/transport.clj b/src/org/gnu/clojure/gnunet/transport.clj
index 01cde14..20bf5a0 100644
--- a/src/org/gnu/clojure/gnunet/transport.clj
+++ b/src/org/gnu/clojure/gnunet/transport.clj
@@ -289,6 +289,19 @@
(send (:transport-addresses-agent remote-peer) check-pending-validation
remote-peer pong)))))
+(defn emit-continuation!
+ [peer transport remote-peer encoded-address result]
+ (if result
+ (let [addresses ((deref (:transport-addresses-agent remote-peer))
+ (:name transport))
+ address (addresses encoded-address)]
+ (if (contains? address :latency)
+ (send (:state-agent remote-peer)
+ (fn [state]
+ (conj state {:is-connected true
+ :connected-transport transport
+ :connected-address encoded-address})))))))
+
(defn admit-message!
[peer sender-id address message]
(let [string-builder (StringBuilder. "Received message type ")]
diff --git a/src/org/gnu/clojure/gnunet/udp.clj b/src/org/gnu/clojure/gnunet/udp.clj
index 7fcadf9..d16ff1b 100644
--- a/src/org/gnu/clojure/gnunet/udp.clj
+++ b/src/org/gnu/clojure/gnunet/udp.clj
@@ -43,22 +43,13 @@
port))
:expiration (hello-address-expiration)})))))))
-(defn emit-continuation!
- [peer transport remote-peer encoded-address result]
- (if result
- (send (:state-agent remote-peer)
- (fn [state]
- (conj state {:is-connected true
- :connected-transport transport
- :connected-address encoded-address})))))
-
(defn emit-messages-udp!
[peer transport remote-peer encoded-address continuation! messages]
(if-let [address (first (parse-address encoded-address))]
(let [continuation! #(do
(emit-continuation! peer transport remote-peer
encoded-address %)
- (continuation! %))]
+ (when continuation! (continuation! %)))]
(.add (:send-queue transport)
{:bytes (generate-udp-message peer messages)
:address address
@@ -118,7 +109,8 @@
(send (:transports-agent peer)
(fn [transports]
(assoc transports "udp"
- {:emit-messages! (partial emit-messages-udp! peer)
+ {:name "udp"
+ :emit-messages! (partial emit-messages-udp! peer)
:socket socket
:selection-key selection-key
:send-queue (ConcurrentLinkedQueue.)}))))))