/** * Convert the opaque value in the CHALLENGE_REQUEST to the seed value I of a * HIP puzzle. * * The opaque value plays a dual role in a CHALLENGE_REQUEST: * i) it is a challenge that needs to be echoed back by the responder and * ii) it is used to derive the seed value for a cryptographic puzzle. The * puzzle is defined in RFC5201. * * @param opaque the nonce (challenge) in the CHALLENGE_REQUEST * @param opaque_len the length of the nonce * @param puzzle_value the puzzle value generated from the nonce * @return zero on success, -1 in case of an error */ int hip_midauth_puzzle_seed(const uint8_t opaque[], const unsigned int opaque_len, uint8_t puzzle_value[PUZZLE_LENGTH]) { unsigned char sha_digest[SHA_DIGEST_LENGTH]; HIP_ASSERT(puzzle_value != NULL); // the hashed opaque field is used as puzzle seed if (hip_build_digest(HIP_DIGEST_SHA1, opaque, opaque_len, sha_digest)) { HIP_ERROR("Building of SHA1 random seed I failed\n"); return -1; } memcpy(puzzle_value, &sha_digest[SHA_DIGEST_LENGTH - PUZZLE_LENGTH], PUZZLE_LENGTH); return 0; }
/** * generate HIP keying material * @param kij Diffie-Hellman Kij (as in the HIP drafts) * @param kij_len the length of the Kij material * @param keymat pointer to a keymat structure which will be updated according * to the generated keymaterial * @param dstbuf the generated keymaterial will be written here * @param dstbuflen the length of the buffer to which to write to * @param hit1 source HIT * @param hit2 destination HIT * @param calc_index where the one byte index is stored (n of Kn) * @param I the I value * @param J the J value * */ void hip_make_keymat(char *kij, size_t kij_len, struct hip_keymat_keymat *keymat, void *dstbuf, size_t dstbuflen, struct in6_addr *hit1, struct in6_addr *hit2, uint8_t *calc_index, const uint8_t I[PUZZLE_LENGTH], const uint8_t J[PUZZLE_LENGTH]) { int bufsize; uint8_t index_nbr = 1; size_t dstoffset = 0; void *seedkey; struct in6_addr *smaller_hit, *bigger_hit; int hit1_is_bigger; uint8_t *shabuffer = NULL; HIP_DEBUG("\n"); if (dstbuflen < HIP_AH_SHA_LEN) { HIP_ERROR("dstbuf is too short (%d)\n", dstbuflen); return; } HIP_ASSERT(sizeof(index_nbr) == HIP_KEYMAT_INDEX_NBR_SIZE); hit1_is_bigger = hip_hit_is_bigger(hit1, hit2); bigger_hit = hit1_is_bigger ? hit1 : hit2; smaller_hit = hit1_is_bigger ? hit2 : hit1; shabuffer = hip_create_keymat_buffer(kij, kij_len, HIP_AH_SHA_LEN, smaller_hit, bigger_hit, I, J); if (!shabuffer) { HIP_ERROR("No memory for keymat\n"); return; } bufsize = kij_len + 2 * sizeof(struct in6_addr) + 2 * sizeof(uint64_t) + 1; // XX FIXME: is this correct hip_build_digest(HIP_DIGEST_SHA1, shabuffer, bufsize, dstbuf); dstoffset = HIP_AH_SHA_LEN; index_nbr++; /* * K2 = SHA1(Kij | K1 | 2) * K3 = SHA1(Kij | K2 | 3) * ... */ seedkey = dstbuf; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); while (dstoffset < dstbuflen) { hip_build_digest(HIP_DIGEST_SHA1, shabuffer, kij_len + HIP_AH_SHA_LEN + 1, (uint8_t *) dstbuf + dstoffset); seedkey = (uint8_t *) dstbuf + dstoffset; dstoffset += HIP_AH_SHA_LEN; index_nbr++; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); } keymat->offset = 0; keymat->keymatlen = dstoffset; keymat->keymatdst = dstbuf; if (calc_index) { *calc_index = index_nbr; } else { HIP_ERROR("NULL calc_index\n"); } free(shabuffer); }
/** * hip_make_keymat - generate HIP keying material * @param kij Diffie-Hellman Kij (as in the HIP drafts) * @param kij_len the length of the Kij material * @param keymat pointer to a keymat structure which will be updated according * to the generated keymaterial * @param dstbuf the generated keymaterial will be written here * @param hit1 source HIT * @param hit2 destination HIT * @param calc_index where the one byte index is stored (n of Kn) * */ void hip_make_keymat(char *kij, size_t kij_len, struct hip_keymat_keymat *keymat, void *dstbuf, size_t dstbuflen, struct in6_addr *hit1, struct in6_addr *hit2, u8 *calc_index, uint64_t I, uint64_t J) { int bufsize, err = 0; uint8_t index_nbr = 1; int dstoffset = 0; void *seedkey; struct in6_addr *smaller_hit, *bigger_hit; int hit1_is_bigger; u8 *shabuffer = NULL; HIP_DEBUG("\n"); if (dstbuflen < HIP_AH_SHA_LEN) { HIP_ERROR("dstbuf is too short (%d)\n", dstbuflen); return; } _HIP_ASSERT(dstbuflen % 32 == 0); HIP_ASSERT(sizeof(index_nbr) == HIP_KEYMAT_INDEX_NBR_SIZE); hit1_is_bigger = hip_hit_is_bigger(hit1, hit2); bigger_hit = hit1_is_bigger ? hit1 : hit2; smaller_hit = hit1_is_bigger ? hit2 : hit1; _HIP_HEXDUMP("kij", kij, kij_len); _HIP_DEBUG("I=0x%llx J=0x%llx\n", I, J); _HIP_HEXDUMP("bigger hit", bigger_hit, 16); _HIP_HEXDUMP("smaller hit", smaller_hit, 16); _HIP_HEXDUMP("index_nbr", (char *) &index_nbr, HIP_KEYMAT_INDEX_NBR_SIZE); shabuffer = hip_create_keymat_buffer(kij, kij_len, HIP_AH_SHA_LEN, smaller_hit, bigger_hit, I, J); if (!shabuffer) { HIP_ERROR("No memory for keymat\n"); return; } bufsize = kij_len + 2 * sizeof(struct in6_addr) + 2 * sizeof(uint64_t) + 1; //bufsize = kij_len+2*sizeof(struct in6_addr)+ 1; // XX FIXME: is this correct hip_build_digest(HIP_DIGEST_SHA1, shabuffer, bufsize, dstbuf); _HIP_HEXDUMP("keymat digest", dstbuf, HIP_AH_SHA_LEN); dstoffset = HIP_AH_SHA_LEN; index_nbr++; /* * K2 = SHA1(Kij | K1 | 2) * K3 = SHA1(Kij | K2 | 3) * ... */ seedkey = dstbuf; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); while (dstoffset < dstbuflen) { hip_build_digest(HIP_DIGEST_SHA1, shabuffer, kij_len + HIP_AH_SHA_LEN + 1, dstbuf + dstoffset); seedkey = dstbuf + dstoffset; dstoffset += HIP_AH_SHA_LEN; index_nbr++; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); } keymat->offset = 0; keymat->keymatlen = dstoffset; keymat->keymatdst = dstbuf; if (calc_index) *calc_index = index_nbr; else HIP_ERROR("NULL calc_index\n"); _HIP_DEBUG("keymat index_nbr=%u\n", index_nbr); _HIP_HEXDUMP("GENERATED KEYMAT: ", dstbuf, dstbuflen); if (shabuffer) HIP_FREE(shabuffer); return; }
/** * Calculates new keying material. * * This function gets next @c key_len bytes of KEYMAT to @c key starting from * requested offset @c keymat_index. On entry of this function @c calc_index * tells the one byte index value which is related to @c calc_index_keymat (for * example, if @c calc_index_keymat is K3, then @c calc_index is 3). * * On successful return, @c keymat_index and @c calc_index contain the values * used in the last round of calculating Kn of KEYMAT, @c calc_index_keymat * contains the last Kn, and @c Kn_is_at contains the byte offset value of * @c calc_index_keymat. * * @param key buffer where the created KEYMAT is stored. * @param key_len length of @c key in bytes. * @param kij shared key. * @param kij_len length of @c kij in bytes. * @param keymat_index keymat index. * @param calc_index the one byte index value. * @param calc_index_keymat Kn. * @param Kn_is_at the byte offset where @c calc_index_keymat starts. * @return 0 on success, < 0 otherwise. */ int hip_keymat_get_new(void *key, size_t key_len, char *kij, size_t kij_len, uint16_t *keymat_index, uint8_t *calc_index, unsigned char *calc_index_keymat, uint16_t *Kn_is_at) { /* must have the hadb lock when calling this function */ int err = 0; int copied = 0; u8 *tmp_data = NULL; size_t tmp_data_len; _HIP_DEBUG("key_len=%d, requested keymat_index=%u calc_index=%u Kn_is_at=%u\n", key_len, *keymat_index, *calc_index, *Kn_is_at); _HIP_HEXDUMP("calc_index_keymat", calc_index_keymat, HIP_AH_SHA_LEN); if (key_len == 0 || kij_len == 0) { HIP_ERROR("key_len = 0 or kij_len = 0\n"); err = -EINVAL; goto out_err; } _HIP_DEBUG("one byte index at req'd index in the end should be %u\n", (*keymat_index / HIP_AH_SHA_LEN + 1) % 256); if (*keymat_index < *Kn_is_at) { HIP_ERROR("requested keymat index %u is lower than lowest keymat index of Kn (%u)\n", *keymat_index, *Kn_is_at); err = -EINVAL; goto out_err; } /** @todo Check here if we have to test *keymat_index < entry->current_keymat_index ? */ /* before calculating any hashes test if we already have * needed amount of ready keymat * * must first check that the requested keymat_index is within the ready keymat */ if (*keymat_index - *Kn_is_at < HIP_AH_SHA_LEN) { int tmp = HIP_AH_SHA_LEN - (*keymat_index - *Kn_is_at); _HIP_DEBUG("test: can copy %d bytes from the end of sha K\n", tmp); if (tmp > HIP_AH_SHA_LEN) { HIP_ERROR("bug: tmp > 20\n"); err = -EINVAL; goto out_err; } if (tmp > 0) { memcpy(key, calc_index_keymat + HIP_AH_SHA_LEN - tmp, tmp); copied += tmp; } } _HIP_DEBUG("copied=%d\n", copied); _HIP_HEXDUMP("KEY (0)", key, copied); if (copied == key_len) { _HIP_DEBUG("copied all, return\n"); goto out; } _HIP_DEBUG("need %d bytes more data\n", key_len-copied); tmp_data_len = kij_len + HIP_AH_SHA_LEN + 1; tmp_data = (u8 *)HIP_MALLOC(tmp_data_len, GFP_KERNEL); if (!tmp_data) { HIP_ERROR("HIP_MALLOC failed\n"); err = -ENOMEM; goto out_err; } memcpy(tmp_data, kij, kij_len); /* fixed part of every Kn round */ while (copied < key_len) { (*calc_index)++; _HIP_DEBUG("calc_index=%u\n", *calc_index); /* create Kn = SHA-1( Kij | Kn-1 | calc_index) */ /* Kij | Kn-1 */ memcpy(tmp_data+kij_len, calc_index_keymat, HIP_AH_SHA_LEN); /* Kij | Kn-1 | calc_index */ memcpy(tmp_data+kij_len+HIP_AH_SHA_LEN, calc_index, HIP_KEYMAT_INDEX_NBR_SIZE); /* SHA-1( Kij | Kn-1 | calc_index) */ err = hip_build_digest(HIP_DIGEST_SHA1, tmp_data, tmp_data_len, calc_index_keymat); if (err) { HIP_ERROR("build_digest failed (K%u)\n", *calc_index); goto out_err; } *Kn_is_at += HIP_AH_SHA_LEN; if (*Kn_is_at + HIP_AH_SHA_LEN < *keymat_index) { HIP_DEBUG("skip until we are at right offset\n"); continue; } _HIP_DEBUG("copied=%u, key_len=%u calc_index=%u dst to 0x%p\n", copied, key_len, *calc_index, key+copied); if (copied + HIP_AH_SHA_LEN <= key_len) { _HIP_DEBUG("copy whole sha block\n"); memcpy(key+copied, calc_index_keymat, HIP_AH_SHA_LEN); copied += HIP_AH_SHA_LEN; } else { int t = HIP_AH_SHA_LEN - key_len % HIP_AH_SHA_LEN; t = key_len - copied; _HIP_DEBUG("copy partial %d bytes\n", t); memcpy(key+copied, calc_index_keymat, t); copied += t; } } _HIP_DEBUG("end: copied=%u\n", copied); out: _HIP_HEXDUMP("CALCULATED KEY", key, key_len); _HIP_DEBUG("at end: *keymat_index=%u *calc_index=%u\n", *keymat_index, *calc_index); out_err: if(tmp_data) HIP_FREE(tmp_data); return err; }