[or-cvs] Implement core of onion-skin-based handshake

Nick Mathewson nickm at seul.org
Thu May 1 19:42:53 UTC 2003


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv28904/src/or

Modified Files:
	onion.c test.c 
Log Message:
Implement core of onion-skin-based handshake

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -d -r1.39 -r1.40
--- onion.c	1 May 2003 06:42:28 -0000	1.39
+++ onion.c	1 May 2003 19:42:51 -0000	1.40
@@ -833,6 +833,147 @@
     inet_ntoa(*((struct in_addr *)(src+3))), dest->expire);
 }
 
+/*----------------------------------------------------------------------*/
+
+/* Given a router's public key, generates a 208-byte encrypted DH pubkey,
+ * and stores it into onion_skin out.  Stores the DH private key into 
+ * handshake_state_out for later completion of the handshake.
+ *
+ * The encrypted pubkey is formed as follows:
+ *    16 bytes of symmetric key
+ *   192 bytes of g^x for DH.
+ * The first 128 bytes are RSA-encrypted with the server's public key,
+ * and the last 80 are encrypted with the symmetric key.
+ */
+int
+onion_skin_create(crypto_pk_env_t *router_key,
+                  crypto_dh_env_t **handshake_state_out,
+                  char *onion_skin_out) /* Must be 208 bytes long */
+{
+  char iv[16];
+  char *pubkey = NULL;
+  crypto_dh_env_t *dh = NULL;
+  crypto_cipher_env_t *cipher = NULL;
+  int dhbytes, pkbytes;
+
+  *handshake_state_out = NULL;
+  memset(onion_skin_out, 0, 208);
+  memset(iv, 0, 16); /* XXXX This can't be safe, can it? */
+
+  if (!(dh = crypto_dh_new()))
+    goto err;
+  
+  dhbytes = crypto_dh_get_bytes(dh);
+  pkbytes = crypto_pk_keysize(router_key);
+  assert(dhbytes+16 == 208);
+  if (!(pubkey = malloc(dhbytes)))
+    goto err;
+
+  if (crypto_rand(16, pubkey))
+    goto err;
+
+  if (crypto_dh_get_public(dh, pubkey+16, dhbytes))
+    goto err;
+
+  if (crypto_pk_public_encrypt(router_key, pubkey, pkbytes,
+                               onion_skin_out, RSA_NO_PADDING))
+    goto err;
+
+  cipher = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, pubkey, iv, 1);
+  
+  if (crypto_cipher_encrypt(cipher, pubkey+pkbytes, dhbytes-16-pkbytes,
+                            onion_skin_out+pkbytes))
+    goto err;
+
+  free(pubkey);
+  crypto_free_cipher_env(cipher);
+  *handshake_state_out = dh;
+  
+  return 0;
+ err:
+  if (pubkey) free(pubkey);
+  if (dh) crypto_dh_free(dh);
+  if (cipher) crypto_free_cipher_env(cipher);
+  return -1;
+}
+
+/* Given an encrypted DH public key as generated by onion_skin_create,
+ * and the private key for this onion router, generate the 192-byte DH
+ * reply, and key_out_len bytes of key material, stored in key_out.
+ */
+int
+onion_skin_server_handshake(char *onion_skin, /* 208 bytes long */
+                            crypto_pk_env_t *private_key,
+                            char *handshake_reply_out, /* 192 bytes long */
+                            char *key_out,
+                            int key_out_len)
+{
+  char buf[208];
+  char iv[16];
+  crypto_dh_env_t *dh = NULL;
+  crypto_cipher_env_t *cipher = NULL;
+  int pkbytes;
+  
+  memset(iv, 0, 16);
+  pkbytes = crypto_pk_keysize(private_key);
+
+  if (crypto_pk_private_decrypt(private_key,
+                                onion_skin, pkbytes,
+                                buf, RSA_NO_PADDING))
+    goto err;
+
+  cipher = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, buf, iv, 0);
+
+  if (crypto_cipher_decrypt(cipher, onion_skin+pkbytes, 208-pkbytes,
+                            buf+pkbytes))
+    goto err;
+  
+  dh = crypto_dh_new();
+  if (crypto_dh_get_public(dh, handshake_reply_out, 192))
+    goto err;
+
+  if (crypto_dh_compute_secret(dh, buf+16, 192, buf))
+    goto err;
+
+  memcpy(key_out, buf+192-key_out_len, key_out_len);
+
+  crypto_free_cipher_env(cipher);
+  crypto_dh_free(dh);
+  return 0;
+ err:
+  if (cipher) crypto_free_cipher_env(cipher);
+  if (dh) crypto_dh_free(dh);
+
+  return -1;
+}
+
+/* Finish the client side of the DH handshake.
+ * Given the 192 byte DH reply as generated by onion_skin_server_handshake
+ * and the handshake state generated by onion_skin_create, generate
+ * key_out_len bytes of shared key material and store them in key_out.
+ *
+ * After the invocation, call crypto_dh_free on handshake_state.
+ */
+int
+onion_skin_client_handshake(crypto_dh_env_t *handshake_state,
+                            char *handshake_reply,/* Must be 192 bytes long*/
+                            char *key_out,
+                            int key_out_len) 
+{
+  char key_material[192];
+  assert(crypto_dh_get_bytes(handshake_state) == 192);
+  
+  memset(key_material, 0, 192);
+
+  if (crypto_dh_compute_secret(handshake_state, handshake_reply, 192,
+                               key_material))
+    return -1;
+  
+  memcpy(key_out, key_material+192-key_out_len, key_out_len);
+
+  return 0;
+}
+
 /*
   Local Variables:
   mode:c

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- test.c	1 May 2003 00:53:46 -0000	1.8
+++ test.c	1 May 2003 19:42:51 -0000	1.9
@@ -475,7 +475,7 @@
   test_buffers();
   puts("========================== Crypto ==========================");
   test_crypto_dh();
-  test_crypto(); /* this seg faults :( */
+  test_crypto(); /* this seg faults :( */  /* Still? -NM 2003/04/30 */
   puts("\n========================== Util ============================");
   test_util();
   puts("");



More information about the tor-commits mailing list