mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
Implement core of onion-skin-based handshake
svn:r259
This commit is contained in:
parent
0560008497
commit
1eeb3f65fc
141
src/or/onion.c
141
src/or/onion.c
@ -833,6 +833,147 @@ onion_unpack(onion_layer_t *dest, char *src)
|
||||
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
|
||||
|
@ -475,7 +475,7 @@ main(int c, char**v) {
|
||||
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("");
|
||||
|
Loading…
Reference in New Issue
Block a user