Implement core of onion-skin-based handshake

svn:r259
This commit is contained in:
Nick Mathewson 2003-05-01 19:42:51 +00:00
parent 0560008497
commit 1eeb3f65fc
2 changed files with 142 additions and 1 deletions

View File

@ -833,6 +833,147 @@ onion_unpack(onion_layer_t *dest, char *src)
inet_ntoa(*((struct in_addr *)(src+3))), dest->expire); 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: Local Variables:
mode:c mode:c

View File

@ -475,7 +475,7 @@ main(int c, char**v) {
test_buffers(); test_buffers();
puts("========================== Crypto =========================="); puts("========================== Crypto ==========================");
test_crypto_dh(); test_crypto_dh();
test_crypto(); /* this seg faults :( */ test_crypto(); /* this seg faults :( */ /* Still? -NM 2003/04/30 */
puts("\n========================== Util ============================"); puts("\n========================== Util ============================");
test_util(); test_util();
puts(""); puts("");