Selaa lähdekoodia

Be smarter about getting key matter from DH.

Formerly, once we had g^xy, we took the last N bytes from g^xy.

Now, we take SHA(g^xy || [0]) || SHA1(g^xy || [1]) || ... , in order
to use all bits from g^xy equally, and generate as much key material
as we need.


svn:r370
Nick Mathewson 21 vuotta sitten
vanhempi
commit
f12fdd62aa
3 muutettua tiedostoa jossa 46 lisäystä ja 13 poistoa
  1. 28 9
      src/common/crypto.c
  2. 1 1
      src/common/crypto.h
  3. 17 3
      src/or/test.c

+ 28 - 9
src/common/crypto.c

@@ -798,22 +798,41 @@ int crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey, int pubkey_len)
 
   return 0;
 }
+
+#undef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
 int crypto_dh_compute_secret(crypto_dh_env_t *dh, 
 			     char *pubkey, int pubkey_len,
-			     char *secret_out)
+			     char *secret_out, int secret_bytes_out)
 {
-  BIGNUM *pubkey_bn;
+  unsigned char hash[20];
+  unsigned char *secret_tmp = NULL;
+  BIGNUM *pubkey_bn = NULL;
   int secret_len;
+  int i;
   assert(dh);
-  
+  assert(secret_bytes_out/20 <= 255);
+
   if (!(pubkey_bn = BN_bin2bn(pubkey, pubkey_len, NULL)))
-    return -1;
-  
-  secret_len = DH_compute_key(secret_out, pubkey_bn, dh->dh);  
-  BN_free(pubkey_bn);
-  if (secret_len == -1)
-    return -1;
+    goto error;
+  secret_tmp = tor_malloc(crypto_dh_get_bytes(dh)+1);
+  secret_len = DH_compute_key(secret_tmp, pubkey_bn, dh->dh);
+  for (i = 0; i < secret_bytes_out; i += 20) {
+    secret_tmp[secret_len] = (unsigned char) i/20;
+    if (crypto_SHA_digest(secret_tmp, secret_len+1, hash))
+      goto error;
+    memcpy(secret_out+i, hash, MIN(20, secret_bytes_out-i));
+  }
+  secret_len = secret_bytes_out;
 
+  goto done;
+ error:
+  secret_len = -1;
+ done:
+  if (pubkey_bn)
+    BN_free(pubkey_bn);
+  if (secret_tmp)
+    free(secret_tmp);
   return secret_len;
 }
 void crypto_dh_free(crypto_dh_env_t *dh)

+ 1 - 1
src/common/crypto.h

@@ -81,7 +81,7 @@ int crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey_out,
 			 int pubkey_out_len);
 int crypto_dh_compute_secret(crypto_dh_env_t *dh, 
 			     char *pubkey, int pubkey_len,
-			     char *secret_out);
+			     char *secret_out, int secret_out_len);
 void crypto_dh_free(crypto_dh_env_t *dh);
 
 /* symmetric crypto */

+ 17 - 3
src/or/test.c

@@ -8,6 +8,21 @@
 #include "or.h"
 #include "../common/test.h"
 
+void
+dump_hex(char *s, int len)
+{
+  static const char TABLE[] = "0123456789ABCDEF";
+  unsigned char *d = s;
+  int i, j, nyb;
+  for(i=0;i<len;++i) {
+    for (j=1;j>=0;--j) {
+      nyb = (((int) d[i]) >> (j*4)) & 0x0f;
+      assert(0<=nyb && nyb <=15);
+      putchar(TABLE[nyb]);
+    }
+  }
+}
+
 void
 setup_directory() {
   char buf[256];
@@ -178,8 +193,8 @@ test_crypto_dh()
   
   memset(s1, 0, CRYPTO_DH_SIZE);
   memset(s2, 0xFF, CRYPTO_DH_SIZE);
-  s1len = crypto_dh_compute_secret(dh1, p2, CRYPTO_DH_SIZE, s1);
-  s2len = crypto_dh_compute_secret(dh2, p1, CRYPTO_DH_SIZE, s2);
+  s1len = crypto_dh_compute_secret(dh1, p2, CRYPTO_DH_SIZE, s1, 50);
+  s2len = crypto_dh_compute_secret(dh2, p1, CRYPTO_DH_SIZE, s2, 50);
   test_assert(s1len > 0);
   test_eq(s1len, s2len);
   test_memeq(s1, s2, s1len);
@@ -443,7 +458,6 @@ test_onion_handshake() {
   
   crypto_dh_free(c_dh);
 
-  /* FIXME sometimes (infrequently) the following fails! Why? */
   if (memcmp(c_keys, s_keys, 40)) {
     puts("Aiiiie");
     exit(1);