static void perfEncrypt () { unsigned int i; char buf[64 * 1024]; char rbuf[64 * 1024]; struct GNUNET_CRYPTO_SymmetricSessionKey sk; struct GNUNET_CRYPTO_SymmetricInitializationVector iv; GNUNET_CRYPTO_symmetric_create_session_key (&sk); memset (buf, 1, sizeof (buf)); for (i = 0; i < 1024; i++) { memset (&iv, (int8_t) i, sizeof (iv)); GNUNET_CRYPTO_symmetric_encrypt (buf, sizeof (buf), &sk, &iv, rbuf); GNUNET_CRYPTO_symmetric_decrypt (rbuf, sizeof (buf), &sk, &iv, buf); } memset (rbuf, 1, sizeof (rbuf)); GNUNET_assert (0 == memcmp (rbuf, buf, sizeof (buf))); }
/** * Encrypt header with the axolotl header key. * * @param t Tunnel whose key to use. * @param msg Message whose header to encrypt. */ static void t_h_encrypt (struct CadetTunnel *t, struct GNUNET_CADET_Encrypted *msg) { struct GNUNET_CRYPTO_SymmetricInitializationVector iv; struct CadetTunnelAxolotl *ax; size_t out_size; ax = &t->ax; GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKs, NULL, 0, NULL); out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->Ns, AX_HEADER_SIZE, &ax->HKs, &iv, &msg->Ns); GNUNET_assert (AX_HEADER_SIZE == out_size); }
static int testSymcipher () { struct GNUNET_CRYPTO_SymmetricSessionKey key; char result[100]; int size; char res[100]; GNUNET_CRYPTO_symmetric_create_session_key (&key); size = GNUNET_CRYPTO_symmetric_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &key, (const struct GNUNET_CRYPTO_SymmetricInitializationVector *) INITVALUE, result); if (size == -1) { printf ("symciphertest failed: encryptBlock returned %d\n", size); return 1; } size = GNUNET_CRYPTO_symmetric_decrypt (result, size, &key, (const struct GNUNET_CRYPTO_SymmetricInitializationVector *) INITVALUE, res); if (strlen (TESTSTRING) + 1 != size) { printf ("symciphertest failed: decryptBlock returned %d\n", size); return 1; } if (0 != strcmp (res, TESTSTRING)) { printf ("symciphertest failed: %s != %s\n", res, TESTSTRING); return 1; } else return 0; }
/** * Publish a UBlock. * * @param h handle to the file sharing subsystem * @param dsh datastore handle to use for storage operation * @param label identifier to use * @param ulabel update label to use, may be an empty string for none * @param ns namespace to publish in * @param meta metadata to use * @param uri URI to refer to in the UBlock * @param bo per-block options * @param options publication options * @param cont continuation * @param cont_cls closure for @a cont * @return NULL on error (@a cont will still be called) */ struct GNUNET_FS_PublishUblockContext * GNUNET_FS_publish_ublock_ (struct GNUNET_FS_Handle *h, struct GNUNET_DATASTORE_Handle *dsh, const char *label, const char *ulabel, const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_Uri *uri, const struct GNUNET_FS_BlockOptions *bo, enum GNUNET_FS_PublishOptions options, GNUNET_FS_UBlockContinuation cont, void *cont_cls) { struct GNUNET_FS_PublishUblockContext *uc; struct GNUNET_HashCode query; struct GNUNET_CRYPTO_SymmetricInitializationVector iv; struct GNUNET_CRYPTO_SymmetricSessionKey skey; struct GNUNET_CRYPTO_EcdsaPrivateKey *nsd; struct GNUNET_CRYPTO_EcdsaPublicKey pub; char *uris; size_t size; char *kbe; char *sptr; ssize_t mdsize; size_t slen; size_t ulen; struct UBlock *ub_plain; struct UBlock *ub_enc; /* compute ublock to publish */ if (NULL == meta) mdsize = 0; else mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); GNUNET_assert (mdsize >= 0); uris = GNUNET_FS_uri_to_string (uri); slen = strlen (uris) + 1; if (NULL == ulabel) ulen = 1; else ulen = strlen (ulabel) + 1; size = mdsize + sizeof (struct UBlock) + slen + ulen; if (size > MAX_UBLOCK_SIZE) { size = MAX_UBLOCK_SIZE; mdsize = size - sizeof (struct UBlock) - (slen + ulen); } ub_plain = GNUNET_malloc (size); kbe = (char *) &ub_plain[1]; if (NULL != ulabel) memcpy (kbe, ulabel, ulen); kbe += ulen; memcpy (kbe, uris, slen); kbe += slen; GNUNET_free (uris); sptr = kbe; if (NULL != meta) mdsize = GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, mdsize, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (-1 == mdsize) { GNUNET_break (0); GNUNET_free (ub_plain); cont (cont_cls, _("Internal error.")); return NULL; } size = sizeof (struct UBlock) + slen + mdsize + ulen; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under identifier `%s'\n", label); /* get public key of the namespace */ GNUNET_CRYPTO_ecdsa_key_get_public (ns, &pub); derive_ublock_encryption_key (&skey, &iv, label, &pub); /* encrypt ublock */ ub_enc = GNUNET_malloc (size); GNUNET_CRYPTO_symmetric_encrypt (&ub_plain[1], ulen + slen + mdsize, &skey, &iv, &ub_enc[1]); GNUNET_free (ub_plain); ub_enc->purpose.size = htonl (ulen + slen + mdsize + sizeof (struct UBlock) - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); ub_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK); /* derive signing-key from 'label' and public key of the namespace */ nsd = GNUNET_CRYPTO_ecdsa_private_key_derive (ns, label, "fs-ublock"); GNUNET_CRYPTO_ecdsa_key_get_public (nsd, &ub_enc->verification_key); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (nsd, &ub_enc->purpose, &ub_enc->signature)); GNUNET_CRYPTO_hash (&ub_enc->verification_key, sizeof (ub_enc->verification_key), &query); GNUNET_free (nsd); uc = GNUNET_new (struct GNUNET_FS_PublishUblockContext); uc->cont = cont; uc->cont_cls = cont_cls; uc->qre = GNUNET_DATASTORE_put (dsh, 0, &query, ulen + slen + mdsize + sizeof (struct UBlock), ub_enc, GNUNET_BLOCK_TYPE_FS_UBLOCK, bo->content_priority, bo->anonymity_level, bo->replication_level, bo->expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &ublock_put_cont, uc); return uc; }
/** * 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); }
/** * We've received an on-demand encoded block from the datastore. * Attempt to do on-demand encoding and (if successful), call the * continuation with the resulting block. On error, clean up and ask * the datastore for more results. * * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * @param cont function to call with the actual block (at most once, on success) * @param cont_cls closure for cont * @return GNUNET_OK on success */ int GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid, GNUNET_DATASTORE_DatumProcessor cont, void *cont_cls) { const struct OnDemandBlock *odb; struct GNUNET_HashCode nkey; struct GNUNET_CRYPTO_SymmetricSessionKey skey; struct GNUNET_CRYPTO_SymmetricInitializationVector iv; struct GNUNET_HashCode query; ssize_t nsize; char ndata[DBLOCK_SIZE]; char edata[DBLOCK_SIZE]; const char *fn; struct GNUNET_DISK_FileHandle *fh; uint64_t off; struct IndexInfo *ii; if (size != sizeof (struct OnDemandBlock)) { GNUNET_break (0); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } odb = (const struct OnDemandBlock *) data; off = GNUNET_ntohll (odb->offset); ii = GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id); if (NULL == ii) { GNUNET_break (0); return GNUNET_SYSERR; } fn = ii->filename; if ((NULL == fn) || (0 != ACCESS (fn, R_OK))) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# index blocks removed: original file inaccessible"), 1, GNUNET_YES); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } if ((NULL == (fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE))) || (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) || (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof (ndata))))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not access indexed file `%s' (%s) at offset %llu: %s\n"), GNUNET_h2s (&odb->file_id), fn, (unsigned long long) off, (fn == NULL) ? _("not indexed") : STRERROR (errno)); if (fh != NULL) GNUNET_DISK_file_close (fh); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); GNUNET_CRYPTO_hash (ndata, nsize, &nkey); GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv); GNUNET_CRYPTO_symmetric_encrypt (ndata, nsize, &skey, &iv, edata); GNUNET_CRYPTO_hash (edata, nsize, &query); if (0 != memcmp (&query, key, sizeof (struct GNUNET_HashCode))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Indexed file `%s' changed at offset %llu\n"), fn, (unsigned long long) off); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "On-demand encoded block for query `%s'\n", GNUNET_h2s (key)); cont (cont_cls, key, nsize, edata, GNUNET_BLOCK_TYPE_FS_DBLOCK, priority, anonymity, expiration, uid); return GNUNET_OK; }
/** * Sign name and records * * @param key the private key * @param expire block expiration * @param label the name for the records * @param rd record data * @param rd_count number of records * @return NULL on error (block too large) */ struct GNUNET_GNSRECORD_Block * GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *label, const struct GNUNET_GNSRECORD_Data *rd, unsigned int rd_count) { size_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); char payload[sizeof (uint32_t) + payload_len]; struct GNUNET_GNSRECORD_Block *block; struct GNUNET_CRYPTO_EcdsaPublicKey pkey; struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey; struct GNUNET_CRYPTO_SymmetricInitializationVector iv; struct GNUNET_CRYPTO_SymmetricSessionKey skey; struct GNUNET_GNSRECORD_Data rdc[rd_count]; uint32_t rd_count_nbo; unsigned int i; struct GNUNET_TIME_Absolute now; if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE) return NULL; /* convert relative to absolute times */ now = GNUNET_TIME_absolute_get (); for (i=0;i<rd_count;i++) { rdc[i] = rd[i]; if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) { struct GNUNET_TIME_Relative t; /* encrypted blocks must never have relative expiration times, convert! */ rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; t.rel_value_us = rdc[i].expiration_time; rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us; } } /* serialize */ rd_count_nbo = htonl (rd_count); memcpy (payload, &rd_count_nbo, sizeof (uint32_t)); GNUNET_assert (payload_len == GNUNET_GNSRECORD_records_serialize (rd_count, rdc, payload_len, &payload[sizeof (uint32_t)])); block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + sizeof (uint32_t) + payload_len); block->purpose.size = htonl (sizeof (uint32_t) + payload_len + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO)); block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); block->expiration_time = GNUNET_TIME_absolute_hton (expire); /* encrypt and sign */ dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key, label, "gns"); GNUNET_CRYPTO_ecdsa_key_get_public (dkey, &block->derived_key); GNUNET_CRYPTO_ecdsa_key_get_public (key, &pkey); derive_block_aes_key (&iv, &skey, label, &pkey); GNUNET_break (payload_len + sizeof (uint32_t) == GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len + sizeof (uint32_t), &skey, &iv, &block[1])); if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (dkey, &block->purpose, &block->signature)) { GNUNET_break (0); GNUNET_free (dkey); GNUNET_free (block); return NULL; } GNUNET_free (dkey); return block; }
static int verifyCrypto () { struct GNUNET_CRYPTO_SymmetricSessionKey key; char result[GNUNET_CRYPTO_AES_KEY_LENGTH]; char *res; int ret; unsigned char plain[] = { 29, 128, 192, 253, 74, 171, 38, 187, 84, 219, 76, 76, 209, 118, 33, 249, 172, 124, 96, 9, 157, 110, 8, 215, 200, 63, 69, 230, 157, 104, 247, 164 }; unsigned char raw_key_aes[] = { 106, 74, 209, 88, 145, 55, 189, 135, 125, 180, 225, 108, 183, 54, 25, 169, 129, 188, 131, 75, 227, 245, 105, 10, 225, 15, 115, 159, 148, 184, 34, 191 }; unsigned char raw_key_twofish[] = { 145, 55, 189, 135, 125, 180, 225, 108, 183, 54, 25, 169, 129, 188, 131, 75, 227, 245, 105, 10, 225, 15, 115, 159, 148, 184, 34, 191, 106, 74, 209, 88 }; unsigned char encrresult[] = { 155, 88, 106, 174, 124, 172, 47, 149, 85, 15, 208, 176, 65, 124, 155, 74, 215, 25, 177, 231, 162, 109, 165, 4, 133, 165, 93, 44, 213, 77, 206, 204, 1 }; res = NULL; ret = 0; memcpy (key.aes_key, raw_key_aes, GNUNET_CRYPTO_AES_KEY_LENGTH); memcpy (key.twofish_key, raw_key_twofish, GNUNET_CRYPTO_AES_KEY_LENGTH); if (GNUNET_CRYPTO_AES_KEY_LENGTH != GNUNET_CRYPTO_symmetric_encrypt (plain, GNUNET_CRYPTO_AES_KEY_LENGTH, &key, (const struct GNUNET_CRYPTO_SymmetricInitializationVector *) "testtesttesttesttesttesttesttest", result)) { printf ("Wrong return value from encrypt block.\n"); ret = 1; goto error; } if (0 != memcmp (encrresult, result, GNUNET_CRYPTO_AES_KEY_LENGTH)) { int i; printf ("Encrypted result wrong.\n"); for (i=0; i<GNUNET_CRYPTO_AES_KEY_LENGTH; i++) printf ("%u, ", (uint8_t) result[i]); ret = 1; goto error; } res = GNUNET_malloc (GNUNET_CRYPTO_AES_KEY_LENGTH); if (GNUNET_CRYPTO_AES_KEY_LENGTH != GNUNET_CRYPTO_symmetric_decrypt (result, GNUNET_CRYPTO_AES_KEY_LENGTH, &key, (const struct GNUNET_CRYPTO_SymmetricInitializationVector *) "testtesttesttesttesttesttesttest", res)) { printf ("Wrong return value from decrypt block.\n"); ret = 1; goto error; } if (0 != memcmp (res, plain, GNUNET_CRYPTO_AES_KEY_LENGTH)) { printf ("Decrypted result does not match input.\n"); ret = 1; } error: GNUNET_free_non_null (res); return ret; }