[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