diff options
-rw-r--r-- | src/org/gnu/clojure/gnunet/crypto.clj | 37 | ||||
-rw-r--r-- | src/org/gnu/clojure/gnunet/hello.clj | 55 | ||||
-rw-r--r-- | src/org/gnu/clojure/gnunet/identity.clj | 18 | ||||
-rw-r--r-- | src/org/gnu/clojure/gnunet/message.clj | 44 |
4 files changed, 108 insertions, 46 deletions
diff --git a/src/org/gnu/clojure/gnunet/crypto.clj b/src/org/gnu/clojure/gnunet/crypto.clj index df512d8..ad3e803 100644 --- a/src/org/gnu/clojure/gnunet/crypto.clj +++ b/src/org/gnu/clojure/gnunet/crypto.clj @@ -1,6 +1,7 @@ (ns org.gnu.clojure.gnunet.crypto - (:import (java.security KeyPairGenerator MessageDigest) - java.security.spec.RSAKeyGenParameterSpec)) + (:use (org.gnu.clojure.gnunet message)) + (:import (java.security KeyPairGenerator KeyFactory MessageDigest) + (java.security.spec RSAKeyGenParameterSpec RSAPublicKeySpec))) (defn generate-rsa-keypair "Generate a 2048 bit RSA keypair." @@ -10,8 +11,40 @@ (.initialize rsa spec) (.generateKeyPair rsa))) +(defn generate-rsa-public-key + "Generate an RSA public key from a modulus and exponent." + [modulus exponent] + (let [keyfactory (KeyFactory/getInstance "RSA") + keyspec (RSAPublicKeySpec. modulus exponent)] + (.generatePublic keyfactory keyspec))) + (defn sha-512 "Compute the SHA-512 digest of a sequence of bytes." [x] (let [sha (MessageDigest/getInstance "SHA-512")] (.digest sha (byte-array x)))) + +(defn encode-rsa-public-key + "Convert an RSA public key to a sequence of bytes in gnunet format." + [public-key] + (let [modulus (encode-int (.getModulus public-key)) + modulus-len (count modulus) + exponent (encode-int (.getPublicExponent public-key)) + exponent-len (count exponent)] + (concat + (encode-int16 (+ modulus-len exponent-len 4)) + (encode-int16 modulus-len) + modulus + exponent + (encode-int16 0)))) + +(defn decode-rsa-public-key-and-split + "Split a seq into an RSA public key and the rest." + [a] + (let [[len after-len] (decode-uint16-and-split a) + [sizen after-sizen] (decode-uint16-and-split after-len) + [encoded-n after-n] (split-at sizen after-sizen) + [encoded-e after-e] (split-at (- len sizen 4) after-n) + [padding after-padding] (decode-uint16-and-split after-e)] + [(generate-rsa-public-key (decode-uint encoded-n) (decode-uint encoded-e)) + after-padding]))
\ No newline at end of file diff --git a/src/org/gnu/clojure/gnunet/hello.clj b/src/org/gnu/clojure/gnunet/hello.clj index d63edef..a6f1c33 100644 --- a/src/org/gnu/clojure/gnunet/hello.clj +++ b/src/org/gnu/clojure/gnunet/hello.clj @@ -1,5 +1,5 @@ (ns org.gnu.clojure.gnunet.hello - (:use (org.gnu.clojure.gnunet message identity))) + (:use (org.gnu.clojure.gnunet message identity crypto))) (def message-type-hello 16) @@ -8,38 +8,57 @@ (concat (.getBytes (:name transport) "UTF-8") (list (byte 0)) - (encode-int32 (count (:encoded-address transport))) + (encode-int32 (count (:bytes transport))) (encode-int64 (.getTime (:expiration transport))) - (:encoded-address transport))) + (:bytes transport))) + +(defn decode-transport-and-split + [a] + (let [[encoded-name after-encoded-name] + (split-with (fn [x] (not (== x 0))) a) + [term after-term] (split-at-or-throw 1 after-encoded-name) + [address-length after-address-length] + (decode-uint32-and-split after-term) + [expiration after-expiration] + (decode-uint64-and-split after-address-length) + [encoded-address after-encoded-address] + (split-at address-length after-expiration)] + [{:name (java.lang.String. (byte-array encoded-name) "UTF-8") + :expiration (java.util.Date. expiration) + :bytes encoded-address} + after-encoded-address])) + +(defn many + [f a] + (loop [result (list) + tail a] + (try + (let [[one after-one] (f tail)] + (recur (cons one result) after-one)) + (catch Exception e [result tail])))) (defn decode-transports-and-split [a] - ) + (many decode-transport-and-split a)) (defn encode-hello "Encode a hello message." [hello] - (let [padding (encode-int32 0) - encoded-key (encode-rsa-public-key (:public-key hello)) - encoded-transports (mapcat encode-transport (:transports hello)) - size (+ header-size - (count padding) - (count encoded-key) - (count encoded-transports))] - (concat - (encode-header size message-type-hello) - padding - encoded-key - encoded-transports))) + (concat + (encode-int32 0) + (encode-rsa-public-key (:public-key hello)) + (mapcat encode-transport (:transports hello)))) (defn decode-hello-and-split + "Split a seq into a hello and the rest." [a] - (let [[header after-header] (decode-header-and-split a) - [padding after-padding] (split-at 4 after-header) + (let [[padding after-padding] (decode-uint32-and-split a) [public-key after-public-key] (decode-rsa-public-key-and-split after-padding) [transports after-transports] (decode-transports-and-split after-public-key)] + (if (not (== padding 0)) + (throw (java.lang.Exception. "Must be zero."))) [{:public-key public-key :transports transports} after-transports])) diff --git a/src/org/gnu/clojure/gnunet/identity.clj b/src/org/gnu/clojure/gnunet/identity.clj index ec729ee..85392a4 100644 --- a/src/org/gnu/clojure/gnunet/identity.clj +++ b/src/org/gnu/clojure/gnunet/identity.clj @@ -1,24 +1,6 @@ (ns org.gnu.clojure.gnunet.identity (:use (org.gnu.clojure.gnunet crypto message))) -(defn encode-rsa-public-key - "Convert an RSA public key to a sequence of bytes in gnunet format." - [public-key] - (let [modulus (encode-int (.getModulus public-key)) - modulus-len (count modulus) - exponent (encode-int (.getPublicExponent public-key)) - exponent-len (count exponent)] - (concat - (encode-int16 (+ modulus-len exponent-len 4)) - (encode-int16 modulus-len) - modulus - exponent - (encode-int16 0)))) - -(defn decode-rsa-public-key-and-split - [a] - ) - (defn generate-id "Generate the SHA-512 digest of the encoded public key." [keypair] diff --git a/src/org/gnu/clojure/gnunet/message.clj b/src/org/gnu/clojure/gnunet/message.clj index 3701260..702a3ae 100644 --- a/src/org/gnu/clojure/gnunet/message.clj +++ b/src/org/gnu/clojure/gnunet/message.clj @@ -29,15 +29,37 @@ (encode-int32 (bit-and x 0xFFFFFFFF)))) (defn decode-int - "Convert a sequence of bytes in network order to a 2's complement integer" + "Convert a sequence of bytes in network order to a 2's complement integer." [a] (BigInteger. (byte-array a))) (defn decode-uint - "Convert a sequence of bytes in network order to an unsigned integer" + "Convert a sequence of bytes in network order to an unsigned integer." [a] (BigInteger. 1 (byte-array a))) +(defn split-at-or-throw + [n a] + (let [[head tail] (split-at n a)] + (if (not (== (count head) n)) + (throw (java.lang.Exception. "Not long enough."))) + [head tail])) + +(defn decode-uint16-and-split + [a] + (let [[encoded-int after-encoded-int] (split-at-or-throw 2 a)] + [(int (decode-uint encoded-int)) after-encoded-int])) + +(defn decode-uint32-and-split + [a] + (let [[encoded-int after-encoded-int] (split-at-or-throw 4 a)] + [(int (decode-uint encoded-int)) after-encoded-int])) + +(defn decode-uint64-and-split + [a] + (let [[encoded-int after-encoded-int] (split-at-or-throw 8 a)] + [(long (decode-uint encoded-int)) after-encoded-int])) + (defn encode-header "Encode a gnunet message header." [hdr] @@ -48,10 +70,16 @@ (def header-size (count (encode-header {:size 0 :message-type 0}))) (defn decode-header-and-split - "Split a seq into a gnunet message header and the rest" + "Split a seq into a gnunet message header and the rest." [a] - (let [[encoded-size after-encoded-size] (split-at 2 a) - [encoded-type after-encoded-type] (split-at 2 after-encoded-size)] - [{:size (decode-uint encoded-size) - :message-type (decode-uint encoded-type)} - after-encoded-type])) + (let [[size after-size] (decode-uint16-and-split a) + [message-type after-message-type] (decode-uint16-and-split after-size)] + [{:size size + :message-type message-type} + after-message-type])) + +(defn encode-message + [msg] + (concat + (encode-header (+ (count (:bytes msg)) header-size) (:message-type msg)) + (:bytes msg)))
\ No newline at end of file |