diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/core.clj | 22 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/crypto.clj | 13 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/hello.clj | 38 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/hostlist.clj | 2 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/peer.clj | 5 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/topology.clj | 38 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/transport.clj | 212 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunet/util.clj | 18 | ||||
-rw-r--r-- | src/main/clojure/org/gnu/clojure/gnunetapplet/applet.clj | 2 |
9 files changed, 159 insertions, 191 deletions
diff --git a/src/main/clojure/org/gnu/clojure/gnunet/core.clj b/src/main/clojure/org/gnu/clojure/gnunet/core.clj index b759575..3980dc7 100644 --- a/src/main/clojure/org/gnu/clojure/gnunet/core.clj +++ b/src/main/clojure/org/gnu/clojure/gnunet/core.clj @@ -54,31 +54,29 @@ :signature signature} (:parsed signed)))) +(def iv-context (encode-utf8 "initialization vector")) (defn derive-iv [aes-key seed peer-id] - (derive-aes-iv aes-key - (encode-int32 seed) - (concat - peer-id - (encode-utf8 "initialization vector")))) + (derive-aes-iv aes-key (encode-int32 seed) (concat peer-id iv-context))) +(def pong-iv-context (encode-utf8 "pong initialization vector")) (defn derive-pong-iv [aes-key seed challenge peer-id] - (derive-aes-iv aes-key + (derive-aes-iv + aes-key (encode-int32 seed) - (concat - peer-id - (encode-int32 challenge) - (encode-utf8 "pong initialization vector")))) + (concat peer-id (encode-int32 challenge) pong-iv-context))) +(def auth-key-context (encode-utf8 "authentication key")) (defn derive-auth-key [aes-key seed aes-key-created] - (derive-hmac-key aes-key + (derive-hmac-key + aes-key (encode-int32 seed) (concat (.getEncoded aes-key) (encode-date aes-key-created) - (encode-utf8 "authentication key")))) + auth-key-context))) (defn encode-core-ping [ping aes-key iv-seed remote-peer-id] diff --git a/src/main/clojure/org/gnu/clojure/gnunet/crypto.clj b/src/main/clojure/org/gnu/clojure/gnunet/crypto.clj index 0d824e3..c5a9108 100644 --- a/src/main/clojure/org/gnu/clojure/gnunet/crypto.clj +++ b/src/main/clojure/org/gnu/clojure/gnunet/crypto.clj @@ -138,15 +138,14 @@ (defn encode-aes-key [aes-key] - (concat - (.getEncoded aes-key) - (encode-int32 (crc32 (.getEncoded aes-key))))) + (let [encoded-key (.getEncoded aes-key)] + (concat encoded-key (encode-int32 (crc32 encoded-key))))) (def parse-aes-key - (domonad parser-m [aes-key (items aes-key-size) + (domonad parser-m [encoded-key (items aes-key-size) checksum parse-uint32 - :when (= checksum (crc32 aes-key))] - (make-aes-key aes-key))) + :when (= checksum (crc32 encoded-key))] + (make-aes-key encoded-key))) (defn generate-aes-key! [random] @@ -410,7 +409,7 @@ (with-test (defn generate-kblock-key - "Generates an RSA private key of a given bit-length." + "Generates an RSA private key of a given bit-length given a seed value." [bit-length seed] {:pre [(even? bit-length)]} (loop [seed seed] diff --git a/src/main/clojure/org/gnu/clojure/gnunet/hello.clj b/src/main/clojure/org/gnu/clojure/gnunet/hello.clj deleted file mode 100644 index 6ad2b45..0000000 --- a/src/main/clojure/org/gnu/clojure/gnunet/hello.clj +++ /dev/null @@ -1,38 +0,0 @@ -(ns org.gnu.clojure.gnunet.hello - (:use (org.gnu.clojure.gnunet parser message peer crypto) - clojure.contrib.monads)) - -(def message-type-hello 16) - -(defn encode-transport-address - [address] - (concat - (encode-utf8 (:transport address)) - (encode-int16 (count (:encoded-address address))) - (encode-date (:expiration address)) - (:encoded-address address))) - -(def parse-transport-address - (domonad parser-m [transport parse-utf8 - address-length parse-uint16 - expiration parse-date - encoded-address (items address-length)] - {:transport transport - :expiration expiration - :encoded-address encoded-address})) - -(defn encode-hello - "Encode a hello message." - [hello] - (concat - (encode-int32 0) - (encode-rsa-public-key (:public-key hello)) - (mapcat encode-transport-address (:transport-addresses hello)))) - -(def parse-hello - (domonad parser-m [padding parse-uint32 - :when (== padding 0) - public-key parse-rsa-public-key - addresses (none-or-more parse-transport-address)] - {:public-key public-key - :transport-addresses addresses})) diff --git a/src/main/clojure/org/gnu/clojure/gnunet/hostlist.clj b/src/main/clojure/org/gnu/clojure/gnunet/hostlist.clj index bd154e6..0501b55 100644 --- a/src/main/clojure/org/gnu/clojure/gnunet/hostlist.clj +++ b/src/main/clojure/org/gnu/clojure/gnunet/hostlist.clj @@ -1,5 +1,5 @@ (ns org.gnu.clojure.gnunet.hostlist - (:use (org.gnu.clojure.gnunet parser message hello iostream peer transport)) + (:use (org.gnu.clojure.gnunet parser message iostream peer transport)) (:import java.util.TimerTask)) (def parse-hostlist diff --git a/src/main/clojure/org/gnu/clojure/gnunet/peer.clj b/src/main/clojure/org/gnu/clojure/gnunet/peer.clj index 446aa9a..8f3b645 100644 --- a/src/main/clojure/org/gnu/clojure/gnunet/peer.clj +++ b/src/main/clojure/org/gnu/clojure/gnunet/peer.clj @@ -10,7 +10,7 @@ ;; atom of java.security.PublicKey :public-key-atom - ;; 64 byte (512-bit) vector + ;; vector of 64 bytes (512 bits) :id ;; agent of a map associating transport names (String) to maps associating @@ -99,9 +99,6 @@ ;; java.util.concurrent.ScheduledThreadPoolExecutor :scheduled-executor)))) -(defstruct peer-options - :keypair) - (defn generate-id "Generate the SHA-512 digest of the encoded public key." [public-key] diff --git a/src/main/clojure/org/gnu/clojure/gnunet/topology.clj b/src/main/clojure/org/gnu/clojure/gnunet/topology.clj new file mode 100644 index 0000000..96bbff9 --- /dev/null +++ b/src/main/clojure/org/gnu/clojure/gnunet/topology.clj @@ -0,0 +1,38 @@ +(ns org.gnu.clojure.gnunet.topology + (:use (org.gnu.clojure.gnunet peer transport))) + +(defn verify-transport-address! + [peer remote-peer address] + (second + ((domonad exception-m + [address (fetch-state) + :when-not (or (contains? address :latency) + (contains? address :send-time)) + :when-let [transport ((deref (:transports-agent peer)) + (:transport address))] + :let [challenge (.nextInt (:random peer))] + _ (set-state + (conj address + {:send-time (Date.) ;; TODO: Now is not the actual send time. + :challenge challenge}))] + ((:emit-messages! transport) transport remote-peer + (:encoded-address address) nil + [(hello-for-peer-message peer) + (ping-message remote-peer address challenge)])) address))) + +(defn verify-transport-addresses! + [addresses peer remote-peer] + (merge-transport-addresses {} + (map (partial verify-transport-address! peer remote-peer) + (list-transport-addresses addresses)))) + +(defn verify-remote-peers! + [remote-peers peer] + (doseq [[_ remote-peer] remote-peers] + (send (:transport-addresses-agent remote-peer) + verify-transport-addresses! peer remote-peer)) + remote-peers) + +(defn activate-topology! + [peer] + ) diff --git a/src/main/clojure/org/gnu/clojure/gnunet/transport.clj b/src/main/clojure/org/gnu/clojure/gnunet/transport.clj index 4f8e38a..642b362 100644 --- a/src/main/clojure/org/gnu/clojure/gnunet/transport.clj +++ b/src/main/clojure/org/gnu/clojure/gnunet/transport.clj @@ -1,6 +1,6 @@ (ns org.gnu.clojure.gnunet.transport - (:use (org.gnu.clojure.gnunet core crypto exception hello message metrics - parser peer util) + (:use (org.gnu.clojure.gnunet core crypto exception message metrics parser + peer util) clojure.contrib.monads) (:import (java.util Date Calendar))) @@ -16,20 +16,56 @@ [] (.getTime (doto (Calendar/getInstance) (.add Calendar/MINUTE 5)))) -(def message-type-ping 32) -(def message-type-pong 33) +(def message-type-hello 16) +(def message-type-transport-ping 32) +(def message-type-transport-pong 33) +(def message-type-transport-connect 35) +(def message-type-transport-disconnect 36) +(def message-type-transport-keepalive 39) (def signature-purpose-pong-own 1) -(def signature-purpose-pong-using 2) + +(defn encode-transport-address + [address] + (concat + (encode-utf8 (:transport address)) + (encode-int16 (count (:encoded-address address))) + (encode-date (:expiration address)) + (:encoded-address address))) + +(def parse-transport-address + (domonad parser-m [transport parse-utf8 + address-length parse-uint16 + expiration parse-date + encoded-address (items address-length)] + {:transport transport + :expiration expiration + :encoded-address encoded-address})) + +(defn encode-hello + "Encode a hello message." + [hello] + (concat + (encode-int32 0) + (encode-rsa-public-key (:public-key hello)) + (mapcat encode-transport-address (:transport-addresses hello)))) + +(def parse-hello + (domonad parser-m [padding parse-uint32 + :when (== padding 0) + public-key parse-rsa-public-key + addresses (none-or-more parse-transport-address)] + {:public-key public-key + :transport-addresses addresses})) (defn encode-ping [ping] (concat (encode-int32 (:challenge ping)) (:peer-id ping) - (if-let [transport (:transport ping)] + (when-let [transport (:transport ping)] (concat - (encode-utf8 (:transport ping)) + (encode-utf8 transport) (:encoded-address ping))))) (def parse-ping @@ -81,8 +117,7 @@ :transport (String. (byte-array transport) "UTF-8") :encoded-address encoded-address})) :let [signature-purpose (:purpose signed)] - :when (or (== signature-purpose signature-purpose-pong-own) - (== signature-purpose signature-purpose-pong-using)) + :when (== signature-purpose signature-purpose-pong-own) residue (optional item) :when (nil? residue)] (conj {:challenge challenge @@ -92,7 +127,7 @@ (:parsed signed)))) (defn list-transport-addresses - "Generate a list of transport descriptions." + "Generate a list of transport addresses." [addresses-map] (for [transport addresses-map address (val transport)] @@ -106,23 +141,17 @@ (conj a b {:expiration (my-max (:expiration a) (:expiration b))})) (defn merge-transport-addresses - "Merge a list of transport descriptions into a transports-agent map. The input - list is generated from parse-hello or list-transports. The input map is + "Merge a list of transport addresses into a transports-agent map. The input + list is generated from parse-hello or list-transport-addresses. The map is described in peer.clj." [address-map address-list] - (reduce (fn [address-map new-address] - (if-let [transport (address-map (:transport new-address))] - (if-let [address-info (transport (:encoded-address new-address))] - (assoc address-map (:transport new-address) - (assoc transport (:encoded-address new-address) - (merge-address-info address-info - (dissoc new-address :transport :encoded-address)))) - (assoc address-map (:transport new-address) - (assoc transport (:encoded-address new-address) - (dissoc new-address :transport :encoded-address)))) - (assoc address-map (:transport new-address) - {(:encoded-address new-address) - (dissoc new-address :transport :encoded-address)}))) + (reduce + (fn [address-map new-address] + (assoc-deep + address-map + (dissoc new-address :transport :encoded-address) + (:transport new-address) + (:encoded-address new-address))) address-map address-list)) @@ -141,7 +170,7 @@ (defn ping-message [remote-peer address challenge] - {:message-type message-type-ping + {:message-type message-type-transport-ping :bytes (encode-ping {:challenge challenge :peer-id (:id remote-peer) :transport (:transport address) @@ -155,65 +184,30 @@ (defn update-remote-peers! [remote-peers peer-id hello] - (let [remote-peer (remote-peers peer-id)] - (if remote-peer - (do - (if (:public-key hello) - (swap! (:public-key-atom remote-peer) - #(if (nil? %) (:public-key hello)))) - (send (:transport-addresses-agent remote-peer) - update-transport-addresses - (:transport-addresses hello)) - remote-peers) - (assoc remote-peers peer-id - (struct-map remote-peer-struct - :public-key-atom (atom (:public-key hello)) - :id peer-id - :transport-addresses-agent (agent - (merge-transport-addresses {} - (:transport-addresses hello))) - :state-agent (agent {:is-connected false})))))) - -(defn verify-transport-address! - [peer remote-peer address] - (second - ((domonad exception-m - [address (fetch-state) - :when (not (or (contains? address :latency) - (contains? address :send-time))) - :when-let [transport ((deref (:transports-agent peer)) - (:transport address))] - :let [challenge (.nextInt (:random peer))] - _ (set-state - (conj address - {:send-time (Date.) ;; TODO: Now is not the actual send time. - :challenge challenge}))] - ((:emit-messages! transport) transport remote-peer - (:encoded-address address) nil - [(hello-for-peer-message peer) - (ping-message remote-peer address challenge)])) address))) - -(defn verify-transport-addresses! - [addresses peer remote-peer] - (merge-transport-addresses {} - (map (partial verify-transport-address! peer remote-peer) - (list-transport-addresses addresses)))) - -(defn verify-remote-peers! - [remote-peers peer] - (doseq [[_ remote-peer] remote-peers] - (send (:transport-addresses-agent remote-peer) - verify-transport-addresses! peer remote-peer)) - remote-peers) + (if-let [remote-peer (remote-peers peer-id)] + (do + (if (:public-key hello) + (swap! (:public-key-atom remote-peer) + #(if (nil? %) (:public-key hello)))) + (send (:transport-addresses-agent remote-peer) + update-transport-addresses + (:transport-addresses hello)) + remote-peers) + (assoc remote-peers peer-id + (struct-map remote-peer-struct + :public-key-atom (atom (:public-key hello)) + :id peer-id + :transport-addresses-agent (agent + (merge-transport-addresses {} + (:transport-addresses hello))) + :state-agent (agent {:is-connected false}))))) (defn admit-hello! "Updates peer:remote-peers-agent with new information contained in hello." [peer hello] (let [peer-id (generate-id (:public-key hello))] - (if (not (= peer-id (:id peer))) - (let [remote-peers-agent (:remote-peers-agent peer)] - (send remote-peers-agent update-remote-peers! peer-id hello) - (send remote-peers-agent verify-remote-peers! peer))))) + (when-not (= peer-id (:id peer)) + (send (:remote-peers-agent peer) update-remote-peers! peer-id hello)))) (defn handle-hello! [peer message] @@ -244,56 +238,29 @@ (if (:is-connected state) (let [transport (:connected-transport state) encoded-address (:connected-address state)] - ((:emit-messages! transport) transport remote-peer encoded-address - nil [{:message-type message-type-pong :bytes encoded-pong}])) + ((:emit-messages! transport) + transport remote-peer encoded-address nil + [{:message-type message-type-transport-pong + :bytes encoded-pong}])) (doseq [transports (deref (:transport-addresses-agent remote-peer)) address (val transports)] (when-let [transport ((deref (:transports-agent peer)) (key transports))] - ((:emit-messages! transport) transport remote-peer (key address) - nil - [{:message-type message-type-pong :bytes encoded-pong}])))))))) - -(defn send-pong-using! - [peer remote-peer address ping] - (.execute (:cpu-bound-executor peer) - (fn [] - (let - [state (deref (:state-agent remote-peer)) - pong {:challenge (:challenge ping) - :signature-purpose signature-purpose-pong-using - :expiration (pong-expiration) - :peer-id (:id remote-peer) - :transport (:transport address) - :encoded-address (:encoded-address address)} - signed-material (encode-pong-signed-material pong) - signature (rsa-sign (:private-key peer) signed-material) - pong (assoc pong :signature signature) - encoded-pong (encode-pong pong signed-material) - state (deref (:state-agent remote-peer))] - (if (:is-connected state) - (let [transport (:connected-transport state) - encoded-address (:connected-address state)] - ((:emit-messages! transport) transport remote-peer encoded-address - nil [{:message-type message-type-pong :bytes encoded-pong}])) - (doseq [transports (deref (:transport-addresses-agent remote-peer)) - address (val transports)] - (when-let [transport ((deref (:transports-agent peer)) - (key transports))] - ((:emit-messages! transport) transport remote-peer (key address) - nil - [{:message-type message-type-pong :bytes encoded-pong}])))))))) + ((:emit-messages! transport) + transport remote-peer (key address) nil + [{:message-type message-type-transport-pong + :bytes encoded-pong}])))))))) (defn handle-ping! [peer remote-peer address message] (when-let [ping (first (parse-ping (:bytes message)))] (cond (not (= (:peer-id ping) (:id peer))) nil - (:transport ping) (send-pong-own! peer remote-peer ping) - :else (send-pong-using! peer remote-peer address ping)))) + (:transport ping) (send-pong-own! peer remote-peer ping)))) (defn handle-pong-own! [peer remote-peer pong] + ;; TODO - test that the challenge matches before wasting time with RSA (.execute (:cpu-bound-executor peer) (fn [] (domonad maybe-m @@ -311,11 +278,6 @@ (.getTime (:send-time address)))}))] (metric-add! peer "Peer addresses considered valid" 1)))))) -(defn handle-pong-using! - [peer remote-peer pong] - ;; TODO - fill in this case - (.write *out* "We don't handle PONG_USING yet!\n")) - (defn handle-pong! [peer message] (domonad maybe-m @@ -324,7 +286,6 @@ remote-peer ((deref (:remote-peers-agent peer)) (:peer-id pong))] (condp == (:signature-purpose pong) signature-purpose-pong-own (handle-pong-own! peer remote-peer pong) - signature-purpose-pong-using (handle-pong-using! peer remote-peer pong) nil))) (defn emit-callback! @@ -350,7 +311,8 @@ remote-peer (remote-peers sender-id)] (condp = (:message-type message) message-type-hello (handle-hello! peer message) - message-type-ping (handle-ping! peer remote-peer address message) - message-type-pong (handle-pong! peer message) + message-type-transport-ping (handle-ping! + peer remote-peer address message) + message-type-transport-pong (handle-pong! peer message) (handle-receive! peer remote-peer message)) remote-peers)))) diff --git a/src/main/clojure/org/gnu/clojure/gnunet/util.clj b/src/main/clojure/org/gnu/clojure/gnunet/util.clj index ea813e3..34fe34d 100644 --- a/src/main/clojure/org/gnu/clojure/gnunet/util.clj +++ b/src/main/clojure/org/gnu/clojure/gnunet/util.clj @@ -9,22 +9,34 @@ (list* `assert-args fnname more))))) (defn queue-seq! - "Consume a queue and present it as a sequence." + "Returns a lazy seq that consumes a + java.util.concurrent.ConcurrentLinkedQueue." [queue] (lazy-seq (when-let [c (.poll queue)] (cons c (queue-seq! queue))))) (defn buffer-seq! + "Returns a lazy seq that consumes a subclass of java.nio.Buffer." [buffer] (lazy-seq (when (.hasRemaining buffer) (cons (.get buffer) (buffer-seq! buffer))))) (defn my-max - "Return the maximum in a collection of comparable values." + "Returns the maximum in a collection of comparable values." [& coll] (last (sort coll))) (defn available-processors + "Returns the number of processors available to this Java runtime." [] (.availableProcessors (Runtime/getRuntime))) -(defn skip [& _]) +(defn skip + "Takes any number of arguments and returns nil." + [& _]) + +(defn assoc-deep + "Associates val with the 'path' of keys in a nested map." + [map val key & keys] + (if (nil? keys) + (assoc map key val) + (assoc map key (apply assoc-deep (map key) val keys)))) diff --git a/src/main/clojure/org/gnu/clojure/gnunetapplet/applet.clj b/src/main/clojure/org/gnu/clojure/gnunetapplet/applet.clj index 52c3c0d..12f825b 100644 --- a/src/main/clojure/org/gnu/clojure/gnunetapplet/applet.clj +++ b/src/main/clojure/org/gnu/clojure/gnunetapplet/applet.clj @@ -169,7 +169,7 @@ [(encode-ascii-hash (:id peer)) (merge-transport-addresses {} (for [address (list-transport-addresses new-state)] - (dissoc address :expiration :send-time :challenge)))]})))) + (dissoc address :send-time :challenge)))]})))) (defn remote-peers-watcher [applet f watched-agent old-state new-state] |