diff options
author | David Barksdale <amatus.amongus@gmail.com> | 2010-10-18 18:29:12 -0700 |
---|---|---|
committer | David Barksdale <amatus.amongus@gmail.com> | 2010-10-18 18:29:12 -0700 |
commit | f6445be6adb07426d0fe26f62bc2b88639f064af (patch) | |
tree | 63ff966deb05e2b77924953e3b5850584c86c921 | |
parent | 3842e519d2571c3155df0d558b528fe52514ceb2 (diff) |
Added CORE_PING support. Fixed AES key encoding. Now peers have connected state.
-rw-r--r-- | src/org/gnu/clojure/gnunet/core.clj | 139 | ||||
-rw-r--r-- | src/org/gnu/clojure/gnunet/crypto.clj | 17 | ||||
-rw-r--r-- | src/org/gnu/clojure/gnunet/peer.clj | 3 | ||||
-rw-r--r-- | src/org/gnu/clojure/gnunet/transport.clj | 13 | ||||
-rw-r--r-- | src/org/gnu/clojure/gnunet/udp.clj | 14 |
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.)})))))) |