static void cmp_secure_functionalTests(void) { #define ARRAY_SIZE 10 // --- Bytes uint8_t array1[ARRAY_SIZE]={1,2,3,4,5,6,7,8,9,0}; uint8_t array2[ARRAY_SIZE]; CC_MEMCPY(array2,array1,sizeof(array1)); // Equal ok(cc_cmp_safe(sizeof(array1), array1,array2)==0, "array1 to array2"); ok(cc_cmp_safe(sizeof(array1), array2,array1)==0, "array2 to array1"); // length is zero ok(cc_cmp_safe(0, array2,array1)!=0, "Array of size 0"); // Equal but first byte array1[0]++; ok(cc_cmp_safe(sizeof(array1), array1,array2)!=0, "first byte"); array1[0]--; // Equal but last byte array1[sizeof(array1)-1]++; ok(cc_cmp_safe(sizeof(array1), array1,array2)!=0, "last byte"); array1[sizeof(array1)-1]--; // --- cc_units uint64_t u64_array1[ARRAY_SIZE]={}; for (size_t i=0;i<ARRAY_SIZE;i++) u64_array1[i]=i; uint64_t u64_array2[ARRAY_SIZE]; uint64_t tmp; CC_MEMCPY(u64_array2,u64_array1,sizeof(u64_array1)); // Equal ok(cc_cmp_safe(sizeof(u64_array1), u64_array1,u64_array2)==0, "array1 to array2"); ok(cc_cmp_safe(sizeof(u64_array1), u64_array2,u64_array1)==0, "array2 to array1"); // length is zero ok(cc_cmp_safe(0, u64_array2,u64_array1)!=0, "Array of size 0"); // Equal but first byte ((uint8_t *)u64_array1)[0]++; ok(cc_cmp_safe(sizeof(u64_array1),u64_array1,u64_array2)!=0, "first byte"); ((uint8_t *)u64_array1)[0]--; // Equal but last byte CC_LOAD64_BE(tmp,&u64_array1[ARRAY_SIZE-1]); CC_STORE64_BE(tmp^0x80,&u64_array1[ARRAY_SIZE-1]); ok(cc_cmp_safe(sizeof(u64_array1), u64_array1,u64_array2)!=0, "last byte"); CC_STORE64_BE(tmp,&u64_array1[ARRAY_SIZE-1]); }
static int generate_block(struct ccdrbg_nistctr_state * drbg, uint32_t *blk) { int rc; uint8_t temp2[CCADRBG_BLOCKSIZE(drbg)]; // the folowing lines are performed as rquested in Radar 19129408 if (drbg->strictFIPS) { rc = gen_block(drbg, temp2); cc_require(rc==CCDRBG_STATUS_OK, errOut); rc = gen_block(drbg, blk); cc_require(rc==CCDRBG_STATUS_OK, errOut); rc = cc_cmp_safe(CCADRBG_BLOCKSIZE(drbg), blk, temp2); rc = (rc==0) ? CCDRBG_STATUS_ABORT: CCDRBG_STATUS_OK; errOut: cc_clear(CCADRBG_BLOCKSIZE(drbg), temp2); }else{ rc=gen_block(drbg, blk); } if(rc==CCDRBG_STATUS_ABORT){ //The world as we know it has come to an end //the DRBG data structure is zeroized. subsequent calls to //DRBG ends up in NULL dereferencing and/or unpredictable state. //catastrophic error in SP 800-90A done((struct ccdrbg_state *)drbg); cc_abort(NULL); } return rc; }
static int generate(struct ccdrbg_state *drbg, size_t dataOutLength, void *dataOut, size_t additionalLength, const void *additional) { struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg; const struct ccdrbg_nisthmac_custom *custom = state->custom; const struct ccdigest_info *di = custom->di; int rc = validate_gen_params(state->reseed_counter, dataOutLength, additional==NULL?0:additionalLength); if(rc!=CCDRBG_STATUS_OK) return rc; // 2. If additional_input ≠ Null, then (Key, V) = HMAC_DRBG_Update (additional_input, Key, V). if (additional && additionalLength) hmac_dbrg_update(drbg, additionalLength, additional, 0, NULL, 0, NULL); // hmac_dbrg_generate_algorithm char *outPtr = (char *) dataOut; while (dataOutLength > 0) { if (!state->bytesLeft) { // 5. V=HMAC(K,V). cchmac(di, state->keysize, state->key, state->vsize, state->nextvptr, state->vptr); // Won't be returned // FIPS 140-2 4.9.2 Conditional Tests // "Each subsequent generation of an n-bit block shall be compared with the previously generated block. The test shall fail if any two compared n-bit blocks are equal." if (0==cc_cmp_safe(state->vsize, state->vptr, state->nextvptr)) { //The world as we know it has come to an end //the DRBG data structure is zeroized. subsequent calls to //DRBG ends up in NULL dereferencing and/or unpredictable state. //catastrophic error in SP 800-90A done(drbg); rc=CCDRBG_STATUS_ABORT; cc_abort(NULL); goto errOut; } CC_SWAP(state->nextvptr, state->vptr); state->bytesLeft = state->vsize; #if DRBG_NISTHMAC_DEBUG cc_print("generate blk: ", state->vsize, state->vptr); #endif } size_t outLength = dataOutLength > state->bytesLeft ? state->bytesLeft : dataOutLength; CC_MEMCPY(outPtr, state->vptr, outLength); state->bytesLeft -= outLength; outPtr += outLength; dataOutLength -= outLength; } // 6. (Key, V) = HMAC_DRBG_Update (additional_input, Key, V). hmac_dbrg_update(drbg, additionalLength, additional, 0, NULL, 0, NULL); // 7. reseed_counter = reseed_counter + 1. state->reseed_counter++; #if DRBG_NISTHMAC_DEBUG dumpState("generate end: ", state); cc_print("generate end nxt: ", state->vsize, state->nextvptr); #endif rc=CCDRBG_STATUS_OK; errOut: return rc; }
/* * NIST SP 800-90 March 2007 * 10.2.1.2 The Update Function */ static int drbg_update(struct ccdrbg_nistctr_state * drbg, const uint32_t *provided_data) { uint32_t i; uint32_t temp[CCADRBG_TEMPLEN_INTS(drbg)]; uint32_t *output_block; /* Clear temp buffer */ cc_clear(sizeof(temp),temp); /* 2. while (len(temp) < seedlen) do */ for (output_block = temp; output_block < &temp[CCADRBG_SEEDLEN_INTS(drbg)]; output_block += CCADRBG_OUTLEN_INTS(drbg)) { /* 2.1 V = (V + 1) mod 2^outlen */ #if NONFIPSINC128 (drbg->inc128)(drbg, drbg->V); #else increment_bigend_128(drbg, drbg->V); #endif /* 2.2 output_block = Block_Encrypt(K, V) */ drbg->ecb->ecb(drbg->key, 1, drbg->V, output_block); } // check that the two halves are not the same. unsigned char* tempPtr = (unsigned char*)temp; if (!cc_cmp_safe(CCADRBG_KEYLEN(drbg), tempPtr, &tempPtr[CCADRBG_KEYLEN(drbg)])) { cc_clear(sizeof(temp), temp); return CCDRBG_STATUS_ERROR; } /* 3 temp is already of size seedlen (CCADRBG_SEEDLEN_INTS) */ /* 4 (part 1) temp = temp XOR provided_data */ for (i = 0; i < CCADRBG_KEYLEN_INTS(drbg); ++i) temp[i] ^= *provided_data++; /* 5 Key = leftmost keylen bits of temp */ drbg->ecb->init(drbg->ecb, drbg->key, CCADRBG_KEYLEN(drbg), &temp[0]); /* 4 (part 2) combined with 6 V = rightmost outlen bits of temp */ for (i = 0; i < CCADRBG_OUTLEN_INTS(drbg); ++i) drbg->V[i] = temp[CCADRBG_KEYLEN_INTS(drbg) + i] ^ *provided_data++; cc_clear(sizeof(temp), temp); return CCDRBG_STATUS_OK; }
static int cmp_secure_timeconstantTests(size_t length, struct ccrng_state *rng, uint32_t test_id) { // Random for messages uint8_t array1[length]; uint8_t array2[length]; int failure_cnt=0; int early_abort=1; uint32_t j,sample_counter; bool retry=true; j=0; while(retry) { sample_counter=0; // Index of current sample measurement_t timing_sample[2*CC_TIMING_SAMPLES]; for (size_t i=0;i<2*CC_TIMING_SAMPLES+(CC_WARMUP/CC_TIMING_REPEAT);i++) { ccrng_generate(rng,length,array1); volatile int cmp_result; if ((i&1) == 0) { // ------------------------- // Random // ------------------------- switch(test_id) { // All equal, except last byte case TEST_LAST_BYTE: memcpy(array2,array1,length); array2[length-1]^=1; break; // All equal, except first byte case TEST_FIRST_BYTE: memcpy(array2,array1,length); array2[0]^=1; break; // Random case TEST_RANDOM: ccrng_generate(rng,length,array2); break; // All equal case TEST_EQUAL: memcpy(array2,array1,length); break; default: return 0; // failure } } else { // ------------------------- // Equal // ------------------------- memcpy(array2,array1,length); } #if 1 // Actual function to test TIMING_WITH_QUANTILE(timing_sample[sample_counter].timing, CC_TIMING_REPEAT, CC_TIMING_PERCENTILE, cmp_result=cc_cmp_safe(length, array1, array2),errOut); #else // Reference which can be expected to fail TIMING_WITH_QUANTILE(timing_sample[sample_counter].timing, CC_TIMING_REPEAT, CC_TIMING_PERCENTILE, cmp_result=memcmp(array1, array2,length),errOut); #endif timing_sample[sample_counter].group=sample_counter&1; #if CC_WARMUP if (i>=CC_WARMUP/CC_TIMING_REPEAT) #endif { sample_counter++; } } #if CCN_OSX if (verbose>1) { char file_name[64]; snprintf(file_name,sizeof(file_name),"corecrypto_test_cc_cmp_timings_%.2zu.csv",length); export_measurement_to_file(file_name,timing_sample,sample_counter); } #endif // Process results #if T_TEST // T test int status=T_test_isRejected(timing_sample,sample_counter); #else // Wilcoxon Rank-Sum Test int status=WilcoxonRankSumTest(timing_sample,sample_counter); #endif if (status!=0) { j++; // retry counter if (j>=CC_TIMING_RETRIES) { diag("Constant timing FAILED for len %d after %d attempts",length,j); //ok_or_fail((status==0),"Decrypt+padding constant timing"); failure_cnt++; break; } } else { if ((verbose>1) && (j>0)) diag("Constant timing ok for len %d after %d attempts (of %d)",length,j+1,CC_TIMING_RETRIES); break; } } // retry early_abort=0; errOut: if (failure_cnt || early_abort) { return 0; } return 1; }
static int hmac_dbrg_update(struct ccdrbg_state *drbg, size_t daLen, const void *da, size_t dbLen, const void *db, size_t dcLen, const void *dc ) { int rc=CCDRBG_STATUS_ERROR; struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg; const struct ccdigest_info *di = state->custom->di; const unsigned char cZero = 0x00; const unsigned char cOne = 0x01; cchmac_ctx_decl(di->state_size, di->block_size, ctx); cchmac_init(di, ctx, state->keysize, state->key); // 1. K = HMAC (K, V || 0x00 || provided_data). cchmac_update(di, ctx, state->vsize, state->vptr); cchmac_update(di, ctx, 1, &cZero); if (da && daLen) cchmac_update(di, ctx, daLen, da); if (db && dbLen) cchmac_update(di, ctx, dbLen, db); if (dc && dcLen) cchmac_update(di, ctx, dcLen, dc); cchmac_final(di, ctx, state->key); // One parameter must be non-empty, or return if (((da && daLen) || (db && dbLen) || (dc && dcLen))) { // 2. V=HMAC(K,V). cchmac(di, state->keysize, state->key, state->vsize, state->vptr, state->vptr); // 4. K = HMAC (K, V || 0x01 || provided_data). cchmac_init(di, ctx, state->keysize, state->key); cchmac_update(di, ctx, state->vsize, state->vptr); cchmac_update(di, ctx, 1, &cOne); if (da && daLen) cchmac_update(di, ctx, daLen, da); if (db && dbLen) cchmac_update(di, ctx, dbLen, db); if (dc && dcLen) cchmac_update(di, ctx, dcLen, dc); cchmac_final(di, ctx, state->key); } // If additional data 5. V=HMAC(K,V) // If no addtional data, this is step 2. V=HMAC(K,V). state->bytesLeft = 0; // FIPS 140-2 4.9.2 Conditional Tests // "the first n-bit block generated after power-up, initialization, or reset shall not be used, but shall be saved for comparison with the next n-bit block to be generated" // Generate the first block and the second block. Compare for FIPS and discard the first block // We keep the second block as the first set of data to be returned cchmac(di, state->keysize, state->key, state->vsize, state->vptr, state->vptr); // First block cchmac(di, state->keysize, state->key, state->vsize, state->vptr, state->nextvptr); // First to be returned if (0==cc_cmp_safe(state->vsize, state->vptr, state->nextvptr)) { //The world as we know it has come to an end //the DRBG data structure is zeroized. subsequent calls to //DRBG ends up in NULL dereferencing and/or unpredictable state. //catastrophic error in SP 800-90A done(drbg); rc=CCDRBG_STATUS_ABORT; cc_abort(NULL); goto errOut; } rc=CCDRBG_STATUS_OK; errOut: return rc; }