Пример #1
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);
}
Пример #2
0
/** Given a router's 128 byte public key,
 * stores the following in onion_skin_out:
 *   - [42 bytes] OAEP padding
 *   - [16 bytes] Symmetric key for encrypting blob past RSA
 *   - [70 bytes] g^x part 1 (inside the RSA)
 *   - [58 bytes] g^x part 2 (symmetrically encrypted)
 *
 * Stores the DH private key into handshake_state_out for later completion
 * of the handshake.
 *
 * The meeting point/cookies and auth are zeroed out for now.
 */
int
onion_skin_TAP_create(crypto_pk_t *dest_router_key,
                  crypto_dh_t **handshake_state_out,
                  char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
{
  char challenge[DH1024_KEY_LEN];
  crypto_dh_t *dh = NULL;
  int dhbytes, pkbytes;

  tor_assert(dest_router_key);
  tor_assert(handshake_state_out);
  tor_assert(onion_skin_out);
  *handshake_state_out = NULL;
  memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);

  if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
    goto err;

  dhbytes = crypto_dh_get_bytes(dh);
  pkbytes = (int) crypto_pk_keysize(dest_router_key);
  tor_assert(dhbytes == 128);
  tor_assert(pkbytes == 128);

  if (crypto_dh_get_public(dh, challenge, dhbytes))
    goto err;

  /* set meeting point, meeting cookie, etc here. Leave zero for now. */
  if (crypto_pk_obsolete_public_hybrid_encrypt(dest_router_key, onion_skin_out,
                                      TAP_ONIONSKIN_CHALLENGE_LEN,
                                      challenge, DH1024_KEY_LEN,
                                      PK_PKCS1_OAEP_PADDING, 1)<0)
    goto err;

  memwipe(challenge, 0, sizeof(challenge));
  *handshake_state_out = dh;

  return 0;
 err:
  /* LCOV_EXCL_START
   * We only get here if RSA encryption fails or DH keygen fails. Those
   * shouldn't be possible. */
  memwipe(challenge, 0, sizeof(challenge));
  if (dh) crypto_dh_free(dh);
  return -1;
  /* LCOV_EXCL_STOP */
}
Пример #3
0
/** Given a router's 128 byte public key,
 * stores the following in onion_skin_out:
 *   - [42 bytes] OAEP padding
 *   - [16 bytes] Symmetric key for encrypting blob past RSA
 *   - [70 bytes] g^x part 1 (inside the RSA)
 *   - [58 bytes] g^x part 2 (symmetrically encrypted)
 *
 * Stores the DH private key into handshake_state_out for later completion
 * of the handshake.
 *
 * The meeting point/cookies and auth are zeroed out for now.
 */
int
onion_skin_TAP_create(crypto_pk_t *dest_router_key,
                  crypto_dh_t **handshake_state_out,
                  char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
{
  char challenge[DH_KEY_LEN];
  crypto_dh_t *dh = NULL;
  int dhbytes, pkbytes;

  tor_assert(dest_router_key);
  tor_assert(handshake_state_out);
  tor_assert(onion_skin_out);
  *handshake_state_out = NULL;
  memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);

  if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
    goto err;

  dhbytes = crypto_dh_get_bytes(dh);
  pkbytes = (int) crypto_pk_keysize(dest_router_key);
  tor_assert(dhbytes == 128);
  tor_assert(pkbytes == 128);

  if (crypto_dh_get_public(dh, challenge, dhbytes))
    goto err;

  note_crypto_pk_op(ENC_ONIONSKIN);

  /* set meeting point, meeting cookie, etc here. Leave zero for now. */
  if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
                                      TAP_ONIONSKIN_CHALLENGE_LEN,
                                      challenge, DH_KEY_LEN,
                                      PK_PKCS1_OAEP_PADDING, 1)<0)
    goto err;

  memwipe(challenge, 0, sizeof(challenge));
  *handshake_state_out = dh;

  return 0;
 err:
  memwipe(challenge, 0, sizeof(challenge));
  if (dh) crypto_dh_free(dh);
  return -1;
}
Пример #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;
}
Пример #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;
}