int main (int argc, char *argv[]) { struct GNUNET_CRYPTO_EcdhePrivateKey *priv1; struct GNUNET_CRYPTO_EcdhePrivateKey *priv2; struct GNUNET_CRYPTO_EcdhePublicKey pub1; struct GNUNET_CRYPTO_EcdhePublicKey pub2; struct GNUNET_HashCode ecdh1; struct GNUNET_HashCode ecdh2; if (! gcry_check_version ("1.6.0")) { FPRINTF (stderr, _ ("libgcrypt has not the expected version (version %s is required).\n"), "1.6.0"); return 0; } if (getenv ("GNUNET_GCRYPT_DEBUG")) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); GNUNET_log_setup ("test-crypto-ecdhe", "WARNING", NULL); priv1 = GNUNET_CRYPTO_ecdhe_key_create (); priv2 = GNUNET_CRYPTO_ecdhe_key_create (); GNUNET_CRYPTO_ecdhe_key_get_public (priv1, &pub1); GNUNET_CRYPTO_ecdhe_key_get_public (priv2, &pub2); GNUNET_CRYPTO_ecc_ecdh (priv1, &pub2, &ecdh1); GNUNET_CRYPTO_ecc_ecdh (priv2, &pub1, &ecdh2); GNUNET_assert (0 == memcmp (&ecdh1, &ecdh2, sizeof (struct GNUNET_HashCode))); GNUNET_free (priv1); GNUNET_free (priv2); return 0; }
int main (int argc, char *argv[]) { int i; struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe[l]; struct GNUNET_CRYPTO_EcdhePublicKey dhpub[l]; struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa[l]; struct GNUNET_CRYPTO_EddsaPublicKey dspub[l]; struct TestSig sig[l]; start = GNUNET_TIME_absolute_get(); for (i = 0; i < l; i++) { sig[i].purp.purpose = 0; sig[i].purp.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_HashCode)); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &sig[i].h, sizeof (sig[i].h)); } log_duration ("", "Init"); start = GNUNET_TIME_absolute_get(); for (i = 0; i < l; i++) eddsa[i] = GNUNET_CRYPTO_eddsa_key_create(); log_duration ("EdDSA", "create key"); start = GNUNET_TIME_absolute_get(); for (i = 0; i < l; i++) GNUNET_CRYPTO_eddsa_key_get_public (eddsa[i], &dspub[i]); log_duration ("EdDSA", "get pubilc"); start = GNUNET_TIME_absolute_get(); for (i = 0; i < l; i++) GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (eddsa[i], &sig[i].purp, &sig[i].sig)); log_duration ("EdDSA", "sign HashCode"); start = GNUNET_TIME_absolute_get(); for (i = 0; i < l; i++) GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_verify (0, &sig[i].purp, &sig[i].sig, &dspub[i])); log_duration ("EdDSA", "verify HashCode"); start = GNUNET_TIME_absolute_get(); for (i = 0; i < l; i++) ecdhe[i] = GNUNET_CRYPTO_ecdhe_key_create(); log_duration ("ECDH", "create key"); start = GNUNET_TIME_absolute_get(); for (i = 0; i < l; i++) GNUNET_CRYPTO_ecdhe_key_get_public (ecdhe[i], &dhpub[i]); log_duration ("ECDH", "get public"); start = GNUNET_TIME_absolute_get(); for (i = 0; i < l - 1; i+=2) { GNUNET_CRYPTO_ecc_ecdh (ecdhe[i], &dhpub[i+1], &sig[i].h); GNUNET_CRYPTO_ecc_ecdh (ecdhe[i+1], &dhpub[i], &sig[i+1].h); } log_duration ("ECDH", "do DH"); return 0; }
/** * 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; }