summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Barksdale <amatus.amongus@gmail.com>2010-04-25 21:07:17 -0700
committerDavid Barksdale <amatus.amongus@gmail.com>2010-04-25 21:07:17 -0700
commit65f36dadaf0b218f52f35ec996b9bd5468cf8ba6 (patch)
tree14978d21f197aad765d6c4d2eab54e5509085c5a
parent0cbcdb61463e16fc1a97c1dcf08badea96858c55 (diff)
We can now decode hellos. Clojure really needs some parser-combinator monads.
-rw-r--r--src/org/gnu/clojure/gnunet/crypto.clj37
-rw-r--r--src/org/gnu/clojure/gnunet/hello.clj55
-rw-r--r--src/org/gnu/clojure/gnunet/identity.clj18
-rw-r--r--src/org/gnu/clojure/gnunet/message.clj44
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