Beispiel #1
0
/**
 * Derive session key and iv from label and public key.
 *
 * @param iv initialization vector to initialize
 * @param skey session key to initialize
 * @param label label to use for KDF
 * @param pub public key to use for KDF
 */
static void
derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
		      struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
		      const char *label,
		      const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
{
  static const char ctx_key[] = "gns-aes-ctx-key";
  static const char ctx_iv[] = "gns-aes-ctx-iv";

  GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
		     pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
		     label, strlen (label),
		     ctx_key, strlen (ctx_key),
		     NULL, 0);
  GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
		     pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
		     label, strlen (label),
		     ctx_iv, strlen (ctx_iv),
		     NULL, 0);
}
/**
 * Derive the key for symmetric encryption/decryption from
 * the public key and the label.
 *
 * @param skey where to store symmetric key
 * @param iv where to store the IV
 * @param label label to use for key derivation
 * @param pub public key to use for key derivation
 */
static void
derive_ublock_encryption_key (struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
			      struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
			      const char *label,
			      const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
{
  struct GNUNET_HashCode key;

  /* derive key from 'label' and public key of the namespace */
  GNUNET_assert (GNUNET_YES ==
		 GNUNET_CRYPTO_kdf (&key, sizeof (key),
				    "UBLOCK-ENC", strlen ("UBLOCK-ENC"),
				    label, strlen (label),
				    pub, sizeof (*pub),
				    NULL, 0));
  GNUNET_CRYPTO_hash_to_aes_key (&key, skey, iv);
}
/**
 * Derive a symmetric encryption key from an HMAC-HASH.
 *
 * @param key Key to use for the HMAC.
 * @param[out] out Key to generate.
 * @param source Source key material (data to HMAC).
 * @param len Length of @a source.
 */
static void
t_hmac_derive_key (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
                   struct GNUNET_CRYPTO_SymmetricSessionKey *out,
                   const void *source,
                   unsigned int len)
{
  static const char ctx[] = "axolotl derive key";
  struct GNUNET_HashCode h;

  t_ax_hmac_hash (key,
                  &h,
                  source,
                  len);
  GNUNET_CRYPTO_kdf (out, sizeof (*out),
                     ctx, sizeof (ctx),
                     &h, sizeof (h),
                     NULL);
}
/**
 * Encrypt data with the axolotl tunnel key.
 *
 * @param t Tunnel whose key to use.
 * @param dst Destination with @a size bytes for the encrypted data.
 * @param src Source of the plaintext. Can overlap with @c dst, must contain @a size bytes
 * @param size Size of the buffers at @a src and @a dst
 */
static void
t_ax_encrypt (struct CadetTunnel *t,
              void *dst,
              const void *src,
              size_t size)
{
  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  struct CadetTunnelAxolotl *ax;
  size_t out_size;

  ax = &t->ax;
  ax->ratchet_counter++;
  if ( (GNUNET_YES == ax->ratchet_allowed) &&
       ( (ratchet_messages <= ax->ratchet_counter) ||
         (0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us)) )
  {
    ax->ratchet_flag = GNUNET_YES;
  }
  if (GNUNET_YES == ax->ratchet_flag)
  {
    /* Advance ratchet */
    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
    struct GNUNET_HashCode dh;
    struct GNUNET_HashCode hmac;
    static const char ctx[] = "axolotl ratchet";

    new_ephemeral (t);
    ax->HKs = ax->NHKs;

    /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
    GNUNET_CRYPTO_ecc_ecdh (ax->DHRs,
                            &ax->DHRr,
                            &dh);
    t_ax_hmac_hash (&ax->RK,
                    &hmac,
                    &dh,
                    sizeof (dh));
    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
                       ctx, sizeof (ctx),
                       &hmac, sizeof (hmac),
                       NULL);
    ax->RK = keys[0];
    ax->NHKs = keys[1];
    ax->CKs = keys[2];

    ax->PNs = ax->Ns;
    ax->Ns = 0;
    ax->ratchet_flag = GNUNET_NO;
    ax->ratchet_allowed = GNUNET_NO;
    ax->ratchet_counter = 0;
    ax->ratchet_expiration
      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
                                  ratchet_time);
  }

  t_hmac_derive_key (&ax->CKs,
                     &MK,
                     "0",
                     1);
  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
                                     &MK,
                                     NULL, 0,
                                     NULL);

  out_size = GNUNET_CRYPTO_symmetric_encrypt (src,
                                              size,
                                              &MK,
                                              &iv,
                                              dst);
  GNUNET_assert (size == out_size);
  t_hmac_derive_key (&ax->CKs,
                     &ax->CKs,
                     "1",
                     1);
}
/**
 * Decrypt and verify data with the appropriate tunnel key and verify that the
 * data has not been altered since it was sent by the remote peer.
 *
 * @param t Tunnel whose key to use.
 * @param dst Destination for the plaintext.
 * @param src Source of the message. Can overlap with @c dst.
 * @param size Size of the message.
 * @return Size of the decrypted data, -1 if an error was encountered.
 */
static ssize_t
t_ax_decrypt_and_validate (struct CadetTunnel *t,
                           void *dst,
                           const struct GNUNET_CADET_Encrypted *src,
                           size_t size)
{
  struct CadetTunnelAxolotl *ax;
  struct GNUNET_ShortHashCode msg_hmac;
  struct GNUNET_HashCode hmac;
  struct GNUNET_CADET_Encrypted plaintext_header;
  uint32_t Np;
  uint32_t PNp;
  size_t esize; /* Size of encryped payload */

  esize = size - sizeof (struct GNUNET_CADET_Encrypted);
  ax = &t->ax;

  /* Try current HK */
  t_hmac (&src->Ns,
          AX_HEADER_SIZE + esize,
          0, &ax->HKr,
          &msg_hmac);
  if (0 != memcmp (&msg_hmac,
                   &src->hmac,
                   sizeof (msg_hmac)))
  {
    static const char ctx[] = "axolotl ratchet";
    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
    struct GNUNET_CRYPTO_SymmetricSessionKey HK;
    struct GNUNET_HashCode dh;
    struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;

    /* Try Next HK */
    t_hmac (&src->Ns,
            AX_HEADER_SIZE + esize,
            0,
            &ax->NHKr,
            &msg_hmac);
    if (0 != memcmp (&msg_hmac,
                     &src->hmac,
                     sizeof (msg_hmac)))
    {
      /* Try the skipped keys, if that fails, we're out of luck. */
      return try_old_ax_keys (t,
                              dst,
                              src,
                              size);
    }
    HK = ax->HKr;
    ax->HKr = ax->NHKr;
    t_h_decrypt (t,
                 src,
                 &plaintext_header);
    Np = ntohl (plaintext_header.Ns);
    PNp = ntohl (plaintext_header.PNs);
    DHRp = &plaintext_header.DHRs;
    store_ax_keys (t,
                   &HK,
                   PNp);

    /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
    GNUNET_CRYPTO_ecc_ecdh (ax->DHRs,
                            DHRp,
                            &dh);
    t_ax_hmac_hash (&ax->RK,
                    &hmac,
                    &dh, sizeof (dh));
    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
                       ctx, sizeof (ctx),
                       &hmac, sizeof (hmac),
                       NULL);

    /* Commit "purported" keys */
    ax->RK = keys[0];
    ax->NHKr = keys[1];
    ax->CKr = keys[2];
    ax->DHRr = *DHRp;
    ax->Nr = 0;
    ax->ratchet_allowed = GNUNET_YES;
  }
  else
  {
    t_h_decrypt (t,
                 src,
                 &plaintext_header);
    Np = ntohl (plaintext_header.Ns);
    PNp = ntohl (plaintext_header.PNs);
  }
  if ( (Np != ax->Nr) &&
       (GNUNET_OK != store_ax_keys (t,
                                    &ax->HKr,
                                    Np)) )
  {
    /* Try the skipped keys, if that fails, we're out of luck. */
    return try_old_ax_keys (t,
                            dst,
                            src,
                            size);
  }

  t_ax_decrypt (t,
                dst,
                &src[1],
                esize);
  ax->Nr = Np + 1;
  return esize;
}