LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType) { uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, 0x00, 0x02, 0x00, 0x20, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46 }; PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); bool result = _decodeType(decoder, dict, type, length); assertTrue(result, "Expected the manifest type to be correctly decoded at the top level"); ccnxManifest_Release(&dict); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&wireFormat); }
LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromLink) { uint8_t mac[] = { 0x01, 0x02, 0x03, 0x04, 0xFF, 0x8F }; PARCBuffer *macbuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(mac, sizeof(mac))); CPIAddress *address = cpiAddress_CreateFromLink(mac, sizeof(mac)); // Do not release test, it is the same reference as address->blob PARCBuffer *test = cpiAddress_GetLinkAddress(address); assertNotNull(test, "Got null link address buffer"); assertTrue(parcBuffer_Equals(test, address->blob), "Returned buffer from cpiAddress_GetLinkAddress not equal to address"); assertTrue(cpiAddress_GetType(address) == cpiAddressType_LINK, "Got wrong address type, expected %d, got %d", cpiAddressType_LINK, cpiAddress_GetType(address)); PARCJSON *json = cpiAddress_ToJson(address); CPIAddress *fromjson = cpiAddress_CreateFromJson(json); assertTrue(cpiAddress_GetType(address) == cpiAddress_GetType(fromjson), "fromjson type does not equal known"); assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address"); assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for LINK type"); CPIAddress *copy = cpiAddress_Copy(address); assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for LINK"); parcJSON_Release(&json); cpiAddress_Destroy(&address); cpiAddress_Destroy(©); cpiAddress_Destroy(&fromjson); parcBuffer_Release(&macbuffer); }
int reader_writer(CCNxPortalFactory *factory, const char *uri) { CCNxPortal *portal = ccnxPortalFactory_GetInstance(factory, ccnxPortalTypeDatagram, ccnxPortalProtocol_TLV, &ccnxPortalAttributes_Blocking); CCNxName *prefix = ccnxName_CreateFromURI(uri); CCNxName *bye = ccnxName_CreateFromURI("lci:/Hello/Goodbye%21"); CCNxName *contentname = ccnxName_CreateFromURI("lci:/Hello/World"); if (ccnxPortal_Listen(portal, prefix, 365 * 86400, CCNxStackTimeout_Never)) { CCNxMetaMessage *msg; while ((msg = ccnxPortal_Receive(portal, CCNxStackTimeout_Never)) != NULL) { if (ccnxMetaMessage_IsInterest(msg)) { CCNxInterest *interest = ccnxMetaMessage_GetInterest(msg); CCNxName *interestName = ccnxInterest_GetName(interest); if (ccnxName_Equals(interestName, contentname)) { const PARCKeyId *publisherKeyId = ccnxPortal_GetKeyId(portal); char buffer[128]; time_t theTime = time(0); sprintf(buffer, "Hello World. The time is %s", ctime(&theTime)); PARCBuffer *payload = parcBuffer_CreateFromArray(buffer, 128); parcBuffer_Flip(payload); PARCBuffer *b = parcBuffer_Acquire(payload); CCNxContentObject *uob = ccnxContentObject_CreateWithDataPayload(contentname, b); // missing NULL check, case 1024 CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(uob); if (ccnxPortal_Send(portal, message, CCNxTransportStackTimeCCNxStackTimeout_Neverout_Never) == false) { fprintf(stderr, "ccnx_write failed\n"); } // ccnxMessage_Release(message); } else if (ccnxName_Equals(interestName, bye)) { break; } } else { ccnxMetaMessage_Display(msg, 0); } ccnxMetaMessage_Release(&msg); } } ccnxName_Release(&prefix); ccnxName_Release(&bye); ccnxName_Release(&contentname); ccnxPortal_Release(&portal); return 0; }
static void * _ccnxChunker_NextFromBuffer(PARCBufferChunker *chunker, _ChunkerState *state) { size_t chunkSize = state->nextChunkSize; parcBuffer_SetPosition(chunker->data, state->position); PARCBuffer *slice = parcBuffer_CreateFromArray(parcBuffer_Overlay(chunker->data, chunkSize), chunkSize); slice = parcBuffer_Flip(slice); _advanceState(chunker, state); return slice; }
/** * Create a PARCBuffer payload containing a JSON string with information about this ContentStore's * size. */ static PARCBuffer * _createStatSizeResponsePayload(const AthenaLRUContentStore *impl, const CCNxName *name, uint64_t chunkNumber) { PARCJSON *json = parcJSON_Create(); parcJSON_AddString(json, "moduleName", AthenaContentStore_LRUImplementation.description); parcJSON_AddInteger(json, "time", parcClock_GetTime(impl->wallClock)); parcJSON_AddInteger(json, "numEntries", impl->numEntries); parcJSON_AddInteger(json, "sizeInBytes", impl->currentSizeInBytes); char *jsonString = parcJSON_ToString(json); parcJSON_Release(&json); PARCBuffer *result = parcBuffer_CreateFromArray(jsonString, strlen(jsonString)); parcMemory_Deallocate(&jsonString); return parcBuffer_Flip(result); }
static CCNxMetaMessage * _create_stats_response(Athena *athena, CCNxName *ccnxName) { PARCJSON *json = parcJSON_Create(); struct timeval tv; gettimeofday(&tv, NULL); uint64_t nowInMillis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); parcJSON_AddString(json, "moduleName", athenaAbout_Name()); parcJSON_AddInteger(json, "time", nowInMillis); parcJSON_AddInteger(json, "numProcessedInterests", athena->stats.numProcessedInterests); parcJSON_AddInteger(json, "numProcessedContentObjects", athena->stats.numProcessedContentObjects); parcJSON_AddInteger(json, "numProcessedControlMessages", athena->stats.numProcessedControlMessages); parcJSON_AddInteger(json, "numProcessedInterestReturns", athena->stats.numProcessedInterestReturns); char *jsonString = parcJSON_ToString(json); parcJSON_Release(&json); PARCBuffer *payload = parcBuffer_CreateFromArray(jsonString, strlen(jsonString)); parcMemory_Deallocate(&jsonString); CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(ccnxName, parcBuffer_Flip(payload)); ccnxContentObject_SetExpiryTime(contentObject, nowInMillis + 100); // this response is good for 100 millis CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(contentObject); ccnxContentObject_Release(&contentObject); parcBuffer_Release(&payload); return result; }
LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup) { uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, 0x00, 0x02, 0x00, 0x20, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46 }; PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); ccnxCodecTlvDecoder_GetType(decoder); // swallow type uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); bool result = _decodeHashGroup(decoder, dict, group, length); assertTrue(result, "Expected hash group to be decoded correctly."); PARCBuffer *expectedPointer = parcBuffer_AllocateCString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0); const PARCBuffer *actualPointer = ccnxManifestHashGroupPointer_GetDigest(pointer); assertTrue(parcBuffer_Equals(expectedPointer, actualPointer), "Expected decoded pointer to equal %s, got %s", parcBuffer_ToHexString(expectedPointer), parcBuffer_ToHexString(actualPointer)); parcBuffer_Release(&expectedPointer); ccnxManifestHashGroup_Release(&group); ccnxManifest_Release(&dict); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&wireFormat); }
LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode) { uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, 0x00, 0x02, 0x00, 0x20, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46 }; PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); bool result = ccnxCodecSchemaV1ManifestDecoder_Decode(decoder, dict); assertTrue(result, "Expected the manifest to be decoded correctly"); ccnxTlvDictionary_Release(&dict); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&wireFormat); }
static CCNxMetaMessage * _create_FIBList_response(Athena *athena, CCNxName *ccnxName, PARCList *fibEntryList) { PARCJSON *jsonPayload = parcJSON_Create(); PARCJSONArray *jsonEntryList = parcJSONArray_Create(); parcJSON_AddArray(jsonPayload, JSON_KEY_RESULT, jsonEntryList); for (size_t i = 0; i < parcList_Size(fibEntryList); ++i) { AthenaFIBListEntry *entry = parcList_GetAtIndex(fibEntryList, i); if (entry != NULL) { CCNxName *prefixName = athenaFIBListEntry_GetName(entry); if (prefixName) { char *prefix = ccnxName_ToString(prefixName); int linkId = athenaFIBListEntry_GetLinkId(entry); const char *linkName = athenaTransportLinkAdapter_LinkIdToName(athena->athenaTransportLinkAdapter, linkId); parcLog_Debug(athena->log, " Route: %s->%s", prefix, linkName); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, JSON_KEY_NAME, prefix); parcJSON_AddString(jsonItem, JSON_KEY_LINK, linkName); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonEntryList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); parcMemory_Deallocate(&prefix); } else { int linkId = athenaFIBListEntry_GetLinkId(entry); const char *linkName = athenaTransportLinkAdapter_LinkIdToName(athena->athenaTransportLinkAdapter, linkId); parcLog_Debug(athena->log, " Route: <empty>->%s", linkName); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, JSON_KEY_NAME, ""); parcJSON_AddString(jsonItem, JSON_KEY_LINK, linkName); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonEntryList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); } } } char *jsonString = parcJSON_ToString(jsonPayload); parcJSONArray_Release(&jsonEntryList); parcJSON_Release(&jsonPayload); PARCBuffer *payload = parcBuffer_CreateFromArray(jsonString, strlen(jsonString)); CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(ccnxName, parcBuffer_Flip(payload)); struct timeval tv; gettimeofday(&tv, NULL); uint64_t nowInMillis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); ccnxContentObject_SetExpiryTime(contentObject, nowInMillis + 100); // this response is good for 100 millis CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(contentObject); ccnxContentObject_Release(&contentObject); parcBuffer_Release(&payload); parcMemory_Deallocate(&jsonString); athena_EncodeMessage(result); return result; }
static CCNxMetaMessage * _create_linkList_response(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, CCNxName *ccnxName) { PARCJSONArray *jsonLinkList = parcJSONArray_Create(); for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->listenerList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->listenerList, index); const char *linkName = athenaTransportLink_GetName(athenaTransportLink); bool notLocal = athenaTransportLink_IsNotLocal(athenaTransportLink); bool localForced = athenaTransportLink_IsForceLocal(athenaTransportLink); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, "linkName", linkName); parcJSON_AddInteger(jsonItem, "index", -1); parcJSON_AddBoolean(jsonItem, "notLocal", notLocal); parcJSON_AddBoolean(jsonItem, "localForced", localForced); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonLinkList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); if (notLocal) { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link listener%s: %s", localForced ? " (forced remote)" : "", linkName); } else { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link listener%s: %s", localForced ? " (forced local)" : "", linkName); } } for (int index = 0; index < parcArrayList_Size(athenaTransportLinkAdapter->instanceList); index++) { AthenaTransportLink *athenaTransportLink = parcArrayList_Get(athenaTransportLinkAdapter->instanceList, index); if (athenaTransportLink) { const char *linkName = athenaTransportLink_GetName(athenaTransportLink); bool notLocal = athenaTransportLink_IsNotLocal(athenaTransportLink); bool localForced = athenaTransportLink_IsForceLocal(athenaTransportLink); PARCJSON *jsonItem = parcJSON_Create(); parcJSON_AddString(jsonItem, "linkName", linkName); parcJSON_AddInteger(jsonItem, "index", index); parcJSON_AddBoolean(jsonItem, "notLocal", notLocal); parcJSON_AddBoolean(jsonItem, "localForced", localForced); PARCJSONValue *jsonItemValue = parcJSONValue_CreateFromJSON(jsonItem); parcJSON_Release(&jsonItem); parcJSONArray_AddValue(jsonLinkList, jsonItemValue); parcJSONValue_Release(&jsonItemValue); if (notLocal) { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link instance [%d] %s: %s", index, localForced ? "(forced remote)" : "(remote)", linkName); } else { parcLog_Debug(athenaTransportLinkAdapter->log, "\n Link instance [%d] %s: %s", index, localForced ? "(forced local)" : "(local)", linkName); } } } char *jsonString = parcJSONArray_ToString(jsonLinkList); parcJSONArray_Release(&jsonLinkList); PARCBuffer *payload = parcBuffer_CreateFromArray(jsonString, strlen(jsonString)); CCNxContentObject *contentObject = ccnxContentObject_CreateWithDataPayload(ccnxName, parcBuffer_Flip(payload)); struct timeval tv; gettimeofday(&tv, NULL); uint64_t nowInMillis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); ccnxContentObject_SetExpiryTime(contentObject, nowInMillis + 100); // this response is good for 100 millis CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(contentObject); ccnxContentObject_Release(&contentObject); parcBuffer_Release(&payload); parcMemory_Deallocate(&jsonString); athena_EncodeMessage(result); return result; }
LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata) { // Re-build the expected metadata from the manifest CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator"); PARCBuffer *digest = parcBuffer_Allocate(16); for (size_t i = 0; i < parcBuffer_Limit(digest); i++) { parcBuffer_PutUint8(digest, 0); } parcBuffer_Flip(digest); size_t entrySize = 1; size_t dataSize = 2; size_t blockSize = 3; size_t treeHeight = 4; // Compute the expected size of this metadata group. size_t metadataSize = 4 * (4 + 8) + 4 + parcBuffer_Limit(digest) + 4 + strlen("ccnx:/locator"); // See test_ccnxCodecSchemaV1_ManifestEncoder.c for the packet construction details. uint8_t rawMetadata[89] = { 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, 0x00, metadataSize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, 0x00, strlen("ccnx:/locator"), 'c', 'c', 'n', 'x', ':', '/', 'l', 'o', 'c', 'a', 't', 'o', 'r', 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, dataSize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, blockSize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, entrySize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, treeHeight, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, 0x00, parcBuffer_Remaining(digest), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawMetadata, sizeof(rawMetadata))); // Create the encoder and swallow the top level container CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); ccnxCodecTlvDecoder_GetType(decoder); // swallow type uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); // Decode the metadata CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); bool result = _decodeHashGroupMetadata(decoder, group, length); assertTrue(result, "Expected hash group metadata to be decoded correctly."); const CCNxName *actualLocator = ccnxManifestHashGroup_GetLocator(group); size_t actualEntrySize = ccnxManifestHashGroup_GetEntrySize(group); size_t actualDataSize = ccnxManifestHashGroup_GetDataSize(group); size_t actualBlockSize = ccnxManifestHashGroup_GetBlockSize(group); size_t actualTreeHeight = ccnxManifestHashGroup_GetTreeHeight(group); const PARCBuffer *actualDigest = ccnxManifestHashGroup_GetOverallDataDigest(group); assertTrue(ccnxName_Equals(groupLocator, actualLocator), "Expected decoded locator to equal %s, got %s", ccnxName_ToString(groupLocator), ccnxName_ToString(actualLocator)); assertTrue(entrySize == actualEntrySize, "Expected %zu entry size, got %zu", entrySize, actualEntrySize); assertTrue(dataSize == actualDataSize, "Expected %zu data size, got %zu", dataSize, actualDataSize); assertTrue(blockSize == actualBlockSize, "Expected %zu block size, got %zu", blockSize, actualBlockSize); assertTrue(treeHeight == actualTreeHeight, "Expected %zu tree height, got %zu", treeHeight, actualTreeHeight); assertTrue(parcBuffer_Equals(digest, actualDigest), "Expected %s digest, got %s", parcBuffer_ToHexString(digest), parcBuffer_ToHexString(actualDigest)); parcBuffer_Release(&digest); ccnxName_Release(&groupLocator); ccnxManifestHashGroup_Release(&group); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&wireFormat); }
/** * Read the secret key out of the encrypted file. * * This function needs its name corrected and rewritten. * * Example: * @code * <#example#> * @endcode */ static PARCBuffer * _AESKeyStoreInit(const char *filename, const char *password) { PARCBuffer *secret_key = NULL; FILE *fp = NULL; _PARCSymmeticSignerFileStoreInfo *ki = NULL; int version; char oidstr[80]; PARCBuffer *aes_key = NULL; PARCBuffer *mac_key = NULL; unsigned char check[SHA256_DIGEST_LENGTH]; unsigned char *keybuf = NULL; int check_start; EVP_CIPHER_CTX ctx; int length = 0; int final_length = 0; fp = fopen(filename, "rb"); if (fp == NULL) { goto Bail; } ki = _d2iAESKeystoreFp(fp, NULL); fclose(fp); if (ki == NULL) { goto Bail; } version = (int) ASN1_INTEGER_get(ki->version); if (version != AES_KEYSTORE_VERSION) { goto Bail; } OBJ_obj2txt(oidstr, sizeof(oidstr), ki->algorithm_oid, 0); if (strcasecmp(oidstr, AES_DEFAULT_DIGEST_ALGORITHM)) { goto Bail; } if (ki->encrypted_key->length < IV_SIZE + (SHA256_DIGEST_LENGTH * 2) + AES_BLOCK_SIZE) { goto Bail; } aes_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\0", 1); mac_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\1", 1); check_start = ki->encrypted_key->length - SHA256_DIGEST_LENGTH; HMAC(EVP_sha256(), parcByteArray_Array(parcBuffer_Array(mac_key)), SHA256_DIGEST_LENGTH, ki->encrypted_key->data, check_start, check, NULL); if (memcmp(&ki->encrypted_key->data[check_start], check, SHA256_DIGEST_LENGTH)) { goto Bail; } keybuf = malloc(SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE); EVP_CIPHER_CTX_init(&ctx); if (!EVP_DecryptInit(&ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), ki->encrypted_key->data)) { goto Bail; } if (!EVP_DecryptUpdate(&ctx, keybuf, &length, &ki->encrypted_key->data[IV_SIZE], ki->encrypted_key->length - IV_SIZE - SHA256_DIGEST_LENGTH)) { goto Bail; } if (!EVP_DecryptFinal(&ctx, keybuf + length, &final_length)) { goto Bail; } secret_key = parcBuffer_CreateFromArray(keybuf, length); parcBuffer_Flip(secret_key); goto out; Bail: free(keybuf); out: if (aes_key) { parcBuffer_Release(&aes_key); } if (mac_key) { parcBuffer_Release(&mac_key); } return secret_key; }