/* * @brief Allow client to write data in cache in the current <peer> tag. * Data can be written directly or ciphered using the ZRTP Key Derivation Function and current s0. * If useKDF flag is set but no s0 is available, nothing is written in cache and an error is returned * * @param[in/out] zrtpContext The ZRTP context we're dealing with * @param[in] peerZID The ZID identifying the peer node we want to write into * @param[in] tagName The name of the tag to be written * @param[in] tagNameLength The length in bytes of the tagName * @param[in] tagContent The content of the tag to be written(a string, if KDF is used the result will be turned into an hexa string) * @param[in] tagContentLength The length in bytes of tagContent * @param[in] derivedDataLength Used only in KDF mode, length in bytes of the derived data to use (max 32) * @param[in] useKDF A flag, if set to 0, write data as it is provided, if set to 1, write KDF(s0, "tagContent", KDF_Context, negotiated hash length) * @param[in] fileFlag Flag, if LOADFILE bit is set, reload the cache buffer from file before updating. * if WRITEFILE bit is set, update the cache file * * @return 0 on success, errorcode otherwise */ int bzrtp_addCustomDataInCache(bzrtpContext_t *zrtpContext, uint8_t peerZID[12], uint8_t *tagName, uint16_t tagNameLength, uint8_t *tagContent, uint16_t tagContentLength, uint8_t derivedDataLength, uint8_t useKDF, uint8_t fileFlag) { /* check we have a valid context, a cache access callback function and a valid channelContext[0] */ if (zrtpContext == NULL || zrtpContext->zrtpCallbacks.bzrtp_loadCache == NULL || zrtpContext->channelContext[0]==NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } if (useKDF == BZRTP_CUSTOMCACHE_PLAINDATA) { /* write content as provided : content is a string and multiple tag is allowed as we are writing the peer URI(To be modified if needed) */ return bzrtp_writePeerNode(zrtpContext, peerZID, tagName, tagNameLength, tagContent, tagContentLength, BZRTP_CACHE_TAGISSTRING|BZRTP_CACHE_ALLOWMULTIPLETAGS, fileFlag); } else { /* we must derive the content using the key derivation function */ uint8_t derivedContent[32]; /* check we have s0 and KDFContext in channel[0] */ bzrtpChannelContext_t *zrtpChannelContext = zrtpContext->channelContext[0]; if (zrtpChannelContext->s0 == NULL || zrtpChannelContext->KDFContext == NULL) { return BZRTP_ERROR_INVALIDCONTEXT; } /* We derive a maximum of 32 bytes for a 256 bit key */ if (derivedDataLength>32) { derivedDataLength = 32; } bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, tagContent, tagContentLength, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, derivedDataLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, derivedContent); /* if derivedDataLength is 4 it means we are writing the session Index, mask the first bit of first byte(MSB) to 0 in order to avoid any counter loop */ if (derivedDataLength == 4) { derivedContent[0] &=0x7F; } /* write it to cache, do not allow multiple tags */ return bzrtp_writePeerNode(zrtpContext, peerZID, tagName, tagNameLength, derivedContent, derivedDataLength, BZRTP_CACHE_TAGISBYTE|BZRTP_CACHE_NOMULTIPLETAGS, fileFlag); } }
void test_zrtpKDF(void) { int i; uint8_t keyKDF[32] = {0x33, 0xe6, 0x6c, 0x01, 0xca, 0x6f, 0xe6, 0x4f, 0xb7, 0x6f, 0xfd, 0xe3, 0x1c, 0xab, 0xc0, 0xfb, 0xad, 0x3d, 0x31, 0x02, 0x67, 0x6b, 0x0c, 0x09, 0x0f, 0xc9, 0x96, 0x38, 0x1e, 0x0a, 0x8c, 0x2f}; uint8_t output[32]; for (i=0; i<KDF_TEST_NUMBER; i++) { bzrtp_keyDerivationFunction(keyKDF, 32, patternKDFLabel[i], strlen((char *)patternKDFLabel[i]), patternKDFContext[i], patternKDFContextLength[i], patternKDFHmacLength[i], (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))bctoolbox_hmacSha256, output); CU_ASSERT_TRUE(memcmp(output, patternKDFOutput[i], patternKDFHmacLength[i]) == 0); } }