Esempio n. 1
0
File: bench.c Progetto: 1234max/tor
static void
bench_dh(void)
{
  const int iters = 1<<10;
  int i;
  uint64_t start, end;

  reset_perftime();
  start = perftime();
  for (i = 0; i < iters; ++i) {
    char dh_pubkey_a[DH_BYTES], dh_pubkey_b[DH_BYTES];
    char secret_a[DH_BYTES], secret_b[DH_BYTES];
    ssize_t slen_a, slen_b;
    crypto_dh_t *dh_a = crypto_dh_new(DH_TYPE_TLS);
    crypto_dh_t *dh_b = crypto_dh_new(DH_TYPE_TLS);
    crypto_dh_generate_public(dh_a);
    crypto_dh_generate_public(dh_b);
    crypto_dh_get_public(dh_a, dh_pubkey_a, sizeof(dh_pubkey_a));
    crypto_dh_get_public(dh_b, dh_pubkey_b, sizeof(dh_pubkey_b));
    slen_a = crypto_dh_compute_secret(LOG_NOTICE,
                                      dh_a, dh_pubkey_b, sizeof(dh_pubkey_b),
                                      secret_a, sizeof(secret_a));
    slen_b = crypto_dh_compute_secret(LOG_NOTICE,
                                      dh_b, dh_pubkey_a, sizeof(dh_pubkey_a),
                                      secret_b, sizeof(secret_b));
    tor_assert(slen_a == slen_b);
    tor_assert(!memcmp(secret_a, secret_b, slen_a));
    crypto_dh_free(dh_a);
    crypto_dh_free(dh_b);
  }
  end = perftime();
  printf("Complete DH handshakes (1024 bit, public and private ops):\n"
         "      %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
}
Esempio n. 2
0
/** Run unit tests for Diffie-Hellman functionality. */
static void
test_crypto_dh(void)
{
  crypto_dh_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT);
  crypto_dh_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT);
  char p1[DH_BYTES];
  char p2[DH_BYTES];
  char s1[DH_BYTES];
  char s2[DH_BYTES];
  ssize_t s1len, s2len;

  test_eq(crypto_dh_get_bytes(dh1), DH_BYTES);
  test_eq(crypto_dh_get_bytes(dh2), DH_BYTES);

  memset(p1, 0, DH_BYTES);
  memset(p2, 0, DH_BYTES);
  test_memeq(p1, p2, DH_BYTES);
  test_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES));
  test_memneq(p1, p2, DH_BYTES);
  test_assert(! crypto_dh_get_public(dh2, p2, DH_BYTES));
  test_memneq(p1, p2, DH_BYTES);

  memset(s1, 0, DH_BYTES);
  memset(s2, 0xFF, DH_BYTES);
  s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p2, DH_BYTES, s1, 50);
  s2len = crypto_dh_compute_secret(LOG_WARN, dh2, p1, DH_BYTES, s2, 50);
  test_assert(s1len > 0);
  test_eq(s1len, s2len);
  test_memeq(s1, s2, s1len);

  {
    /* XXXX Now fabricate some bad values and make sure they get caught,
     * Check 0, 1, N-1, >= N, etc.
     */
  }

 done:
  crypto_dh_free(dh1);
  crypto_dh_free(dh2);
}
Esempio n. 3
0
/* We are a v2 legacy HS client: Create and return a crypt path for the hidden
 * service on the other side of the rendezvous circuit <b>circ</b>. Initialize
 * the crypt path crypto using the body of the RENDEZVOUS1 cell at
 * <b>rend_cell_body</b> (which must be at least DH_KEY_LEN+DIGEST_LEN bytes).
 */
static crypt_path_t *
create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body)
{
  crypt_path_t *hop = NULL;
  char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];

  /* first DH_KEY_LEN bytes are g^y from the service. Finish the dh
   * handshake...*/
  tor_assert(circ->build_state);
  tor_assert(circ->build_state->pending_final_cpath);
  hop = circ->build_state->pending_final_cpath;

  tor_assert(hop->rend_dh_handshake_state);
  if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, hop->rend_dh_handshake_state,
                               (char*)rend_cell_body, DH_KEY_LEN,
                               keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
    log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
    goto err;
  }
  /* ... and set up cpath. */
  if (circuit_init_cpath_crypto(hop,
                                keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN,
                                0, 0) < 0)
    goto err;

  /* Check whether the digest is right... */
  if (tor_memneq(keys, rend_cell_body+DH_KEY_LEN, DIGEST_LEN)) {
    log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
    goto err;
  }

  /* clean up the crypto stuff we just made */
  crypto_dh_free(hop->rend_dh_handshake_state);
  hop->rend_dh_handshake_state = NULL;

  goto done;

 err:
  hop = NULL;

 done:
  memwipe(keys, 0, sizeof(keys));
  return hop;
}
Esempio n. 4
0
/** Finish the client side of the DH handshake.
 * Given the 128 byte DH reply + 20 byte hash as generated by
 * onion_skin_server_handshake and the handshake state generated by
 * onion_skin_create, verify H(K) with the first 20 bytes of shared
 * key material, then generate key_out_len more bytes of shared key
 * material and store them in key_out.
 *
 * After the invocation, call crypto_dh_free on handshake_state.
 */
int
onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
            const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
            char *key_out,
            size_t key_out_len,
            const char **msg_out)
{
  ssize_t len;
  char *key_material=NULL;
  size_t key_material_len;
  tor_assert(crypto_dh_get_bytes(handshake_state) == DH1024_KEY_LEN);

  key_material_len = DIGEST_LEN + key_out_len;
  key_material = tor_malloc(key_material_len);
  len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state,
                                 handshake_reply, DH1024_KEY_LEN, key_material,
                                 key_material_len);
  if (len < 0) {
    if (msg_out)
      *msg_out = "DH computation failed.";
    goto err;
  }

  if (tor_memneq(key_material, handshake_reply+DH1024_KEY_LEN, DIGEST_LEN)) {
    /* H(K) does *not* match. Something fishy. */
    if (msg_out)
      *msg_out = "Digest DOES NOT MATCH on onion handshake. Bug or attack.";
    goto err;
  }

  /* use the rest of the key material for our shared keys, digests, etc */
  memcpy(key_out, key_material+DIGEST_LEN, key_out_len);

  memwipe(key_material, 0, key_material_len);
  tor_free(key_material);
  return 0;
 err:
  memwipe(key_material, 0, key_material_len);
  tor_free(key_material);
  return -1;
}
Esempio n. 5
0
/** Finish the client side of the DH handshake.
 * Given the 128 byte DH reply + 20 byte hash as generated by
 * onion_skin_server_handshake and the handshake state generated by
 * onion_skin_create, verify H(K) with the first 20 bytes of shared
 * key material, then generate key_out_len more 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,
            const char *handshake_reply, /* ONIONSKIN_REPLY_LEN bytes */
            char *key_out,
            size_t key_out_len)
{
  ssize_t len;
  char *key_material=NULL;
  size_t key_material_len;
  tor_assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN);

  key_material_len = DIGEST_LEN + key_out_len;
  key_material = tor_malloc(key_material_len);
  len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state,
                                 handshake_reply, DH_KEY_LEN, key_material,
                                 key_material_len);
  if (len < 0)
    goto err;

  if (memcmp(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) {
    /* H(K) does *not* match. Something fishy. */
    log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on onion handshake. "
             "Bug or attack.");
    goto err;
  }

  /* use the rest of the key material for our shared keys, digests, etc */
  memcpy(key_out, key_material+DIGEST_LEN, key_out_len);

  memset(key_material, 0, key_material_len);
  tor_free(key_material);
  return 0;
 err:
  memset(key_material, 0, key_material_len);
  tor_free(key_material);
  return -1;
}
Esempio n. 6
0
/** Given an encrypted DH public key as generated by onion_skin_create,
 * and the private key for this onion router, generate the reply (128-byte
 * DH plus the first 20 bytes of shared key material), and store the
 * next key_out_len bytes of key material in key_out.
 */
int
onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
                            crypto_pk_env_t *private_key,
                            crypto_pk_env_t *prev_private_key,
                            char *handshake_reply_out, /*ONIONSKIN_REPLY_LEN*/
                            char *key_out,
                            size_t key_out_len)
{
  char challenge[ONIONSKIN_CHALLENGE_LEN];
  crypto_dh_env_t *dh = NULL;
  ssize_t len;
  char *key_material=NULL;
  size_t key_material_len=0;
  int i;
  crypto_pk_env_t *k;

  len = -1;
  for (i=0;i<2;++i) {
    k = i==0?private_key:prev_private_key;
    if (!k)
      break;
    note_crypto_pk_op(DEC_ONIONSKIN);
    len = crypto_pk_private_hybrid_decrypt(k, challenge,
                                           onion_skin, ONIONSKIN_CHALLENGE_LEN,
                                           PK_PKCS1_OAEP_PADDING,0);
    if (len>0)
      break;
  }
  if (len<0) {
    log_info(LD_PROTOCOL,
             "Couldn't decrypt onionskin: client may be using old onion key");
    goto err;
  } else if (len != DH_KEY_LEN) {
    log_warn(LD_PROTOCOL, "Unexpected onionskin length after decryption: %ld",
             (long)len);
    goto err;
  }

  dh = crypto_dh_new();
  if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) {
    log_info(LD_GENERAL, "crypto_dh_get_public failed.");
    goto err;
  }

  key_material_len = DIGEST_LEN+key_out_len;
  key_material = tor_malloc(key_material_len);
  len = crypto_dh_compute_secret(dh, challenge, DH_KEY_LEN,
                                 key_material, key_material_len);
  if (len < 0) {
    log_info(LD_GENERAL, "crypto_dh_compute_secret failed.");
    goto err;
  }

  /* send back H(K|0) as proof that we learned K. */
  memcpy(handshake_reply_out+DH_KEY_LEN, key_material, DIGEST_LEN);

  /* use the rest of the key material for our shared keys, digests, etc */
  memcpy(key_out, key_material+DIGEST_LEN, key_out_len);

  memset(challenge, 0, sizeof(challenge));
  memset(key_material, 0, key_material_len);
  tor_free(key_material);
  crypto_dh_free(dh);
  return 0;
 err:
  memset(challenge, 0, sizeof(challenge));
  if (key_material) {
    memset(key_material, 0, key_material_len);
    tor_free(key_material);
  }
  if (dh) crypto_dh_free(dh);

  return -1;
}
Esempio n. 7
0
/** Given an encrypted DH public key as generated by onion_skin_create,
 * and the private key for this onion router, generate the reply (128-byte
 * DH plus the first 20 bytes of shared key material), and store the
 * next key_out_len bytes of key material in key_out.
 */
int
onion_skin_TAP_server_handshake(
                            /*TAP_ONIONSKIN_CHALLENGE_LEN*/
                            const char *onion_skin,
                            crypto_pk_t *private_key,
                            crypto_pk_t *prev_private_key,
                            /*TAP_ONIONSKIN_REPLY_LEN*/
                            char *handshake_reply_out,
                            char *key_out,
                            size_t key_out_len)
{
  char challenge[TAP_ONIONSKIN_CHALLENGE_LEN];
  crypto_dh_t *dh = NULL;
  ssize_t len;
  char *key_material=NULL;
  size_t key_material_len=0;
  int i;
  crypto_pk_t *k;

  len = -1;
  for (i=0;i<2;++i) {
    k = i==0?private_key:prev_private_key;
    if (!k)
      break;
    len = crypto_pk_obsolete_private_hybrid_decrypt(k, challenge,
                                           TAP_ONIONSKIN_CHALLENGE_LEN,
                                           onion_skin,
                                           TAP_ONIONSKIN_CHALLENGE_LEN,
                                           PK_PKCS1_OAEP_PADDING,0);
    if (len>0)
      break;
  }
  if (len<0) {
    log_info(LD_PROTOCOL,
             "Couldn't decrypt onionskin: client may be using old onion key");
    goto err;
  } else if (len != DH1024_KEY_LEN) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Unexpected onionskin length after decryption: %ld",
           (long)len);
    goto err;
  }

  dh = crypto_dh_new(DH_TYPE_CIRCUIT);
  if (!dh) {
    /* LCOV_EXCL_START
     * Failure to allocate a DH key should be impossible.
     */
    log_warn(LD_BUG, "Couldn't allocate DH key");
    goto err;
    /* LCOV_EXCL_STOP */
  }
  if (crypto_dh_get_public(dh, handshake_reply_out, DH1024_KEY_LEN)) {
    /* LCOV_EXCL_START
     * This can only fail if the length of the key we just allocated is too
     * big. That should be impossible. */
    log_info(LD_GENERAL, "crypto_dh_get_public failed.");
    goto err;
    /* LCOV_EXCL_STOP */
  }

  key_material_len = DIGEST_LEN+key_out_len;
  key_material = tor_malloc(key_material_len);
  len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge,
                                 DH1024_KEY_LEN, key_material,
                                 key_material_len);
  if (len < 0) {
    log_info(LD_GENERAL, "crypto_dh_compute_secret failed.");
    goto err;
  }

  /* send back H(K|0) as proof that we learned K. */
  memcpy(handshake_reply_out+DH1024_KEY_LEN, key_material, DIGEST_LEN);

  /* use the rest of the key material for our shared keys, digests, etc */
  memcpy(key_out, key_material+DIGEST_LEN, key_out_len);

  memwipe(challenge, 0, sizeof(challenge));
  memwipe(key_material, 0, key_material_len);
  tor_free(key_material);
  crypto_dh_free(dh);
  return 0;
 err:
  memwipe(challenge, 0, sizeof(challenge));
  if (key_material) {
    memwipe(key_material, 0, key_material_len);
    tor_free(key_material);
  }
  if (dh) crypto_dh_free(dh);

  return -1;
}