blob: 1d967238a1b4e2d12e5e21dfe7d527f8a6ea8f5c [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file implements a process to effect a functional test for
* the Weave Deterministic Random Bit Generator (CTR-DRBG).
*
*/
//#include <Weave/Core/WeaveConfig.h>
#include <stdio.h>
#include <string.h>
#include "ToolCommon.h"
#include "TestDRBG.h"
#include <Weave/Support/crypto/DRBG.h>
using namespace nl::Weave::Crypto;
#define DEBUG_PRINT_ENABLE 0
#define VerifyOrFail(TST, MSG) \
do { \
if (!(TST)) \
{ \
fprintf(stderr, "%s FAILED: ", __FUNCTION__); \
fputs(MSG, stderr); \
exit(-1); \
} \
} while (0)
#define SuccessOrFail(ERR, MSG) \
do { \
if ((ERR) != WEAVE_NO_ERROR) \
{ \
fprintf(stderr, "%s FAILED: ", __FUNCTION__); \
fputs(MSG, stderr); \
fputs(ErrorStr(ERR), stderr); \
fputs("\n", stderr); \
exit(-1); \
} \
} while (0)
static uint8_t *TestEntropy = NULL;
static size_t TestEntropyLen = 0;
// DefaultEntropy() function is compiled out to eliminate compiler warning.
// This function can be used later in case we need to do more testing of DRBG
// engine, where we collect entropy from real source.
#if WEAVE_CONFIG_TEST_DRBG_ENTROPY_COLLECTION
static int DefaultEntropy(uint8_t *entropy, size_t entropyLen)
{
int randomVal;
uint8_t *pRandomVal;
size_t idx;
if (entropyLen > 0 && !entropy)
return 1;
do
{
randomVal = rand();
pRandomVal = (uint8_t *)&randomVal;
for (idx = 0; (idx < sizeof(int)) && (entropyLen > 0); idx++, entropyLen--)
*entropy++ = *pRandomVal++;
}
while (entropyLen > 0);
return 0;
}
#endif // WEAVE_CONFIG_TEST_DRBG_ENTROPY_COLLECTION
static int TestEntropyFunct(uint8_t *entropy, size_t entropyLen)
{
if (entropyLen > 0)
if (!TestEntropy || !entropy || (TestEntropyLen < entropyLen))
return 1;
// Copy Test Entropy Data
memcpy(entropy, TestEntropy, entropyLen);
// Update parameters
TestEntropy += entropyLen;
TestEntropyLen -= entropyLen;
return 0;
}
static uint8_t *TestRandomOutput = NULL;
static size_t TestRandomOutputLen = 0;
static int TestRandomOutputFunction(uint8_t *randomOutput, size_t randomOutputLen)
{
int ret;
if (randomOutputLen > 0)
if (!randomOutput || !TestRandomOutput || (randomOutputLen > TestRandomOutputLen))
return 1;
// Compare Random data with expected output
ret = memcmp(randomOutput, TestRandomOutput, randomOutputLen);
// Update parameters
TestRandomOutput += randomOutputLen;
TestRandomOutputLen -= randomOutputLen;
return ret;
}
static int TestDRBG(uint8_t iterationCount, bool usePR, bool useReseed,
uint8_t *entropyInput, size_t entropyInputLen,
uint8_t *personalizationString, size_t personalizationStringLen,
uint8_t *additionalInput, size_t additionalInputLen,
uint8_t *randomOutput, size_t randomOutputLen)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
int ret;
AES128CTRDRBG ctrDRBG;
uint8_t result[64];
#if DEBUG_PRINT_ENABLE
printf("Starting CTR_DRBG AES-128 Test with the following features:\n");
if (usePR)
printf(" - Use Prediction Resistance\n");
else
printf(" - No Prediction Resistance\n");
#endif
// Initialize Entropy Parameters
TestEntropy = entropyInput;
TestEntropyLen = entropyInputLen * iterationCount;
if (usePR)
TestEntropyLen *= 3;
else if (useReseed)
TestEntropyLen *= 2;
// Initilize Result Check Parameters
TestRandomOutput = randomOutput;
TestRandomOutputLen = randomOutputLen * iterationCount;
for (uint8_t i = 0; i < iterationCount; i++)
{
#if DEBUG_PRINT_ENABLE
printf("\tCOUNT = %u\n", i);
#endif
// DRBG Instantiate Function
err = ctrDRBG.Instantiate(TestEntropyFunct, entropyInputLen,
personalizationString, personalizationStringLen);
SuccessOrExit(err);
personalizationString += personalizationStringLen;
if (useReseed)
{
// DRBG Reseed Function
err = ctrDRBG.Reseed(additionalInput, additionalInputLen);
SuccessOrExit(err);
additionalInput += additionalInputLen;
}
// DRBG Generate Function (first call)
err = ctrDRBG.Generate(result, randomOutputLen, additionalInput, additionalInputLen);
SuccessOrExit(err);
additionalInput += additionalInputLen;
// DRBG Generate Function (second call)
err = ctrDRBG.Generate(result, randomOutputLen, additionalInput, additionalInputLen);
SuccessOrExit(err);
additionalInput += additionalInputLen;
// Check Result
ret = TestRandomOutputFunction(result, randomOutputLen);
VerifyOrExit(ret == 0, err = WEAVE_ERROR_DRBG_ENTROPY_SOURCE_FAILED);
// DRBG Uninstantiate Function
ctrDRBG.Uninstantiate();
}
exit:
return err;
}
// Current DRBG implementation doesn't support noDF option
#define WEAVE_CONFIG_DRBG_WITHOUT_DERIVATION_FUNCTION 0
// ============================================================
// Test Body
// ============================================================
int main(int argc, char *argv[])
{
WEAVE_ERROR err;
// ============================================================
// [AES-128 no df]
// [PredictionResistance = False]
// [EntropyInputLen = 256]
// [NonceLen = 0]
// [PersonalizationStringLen = 0]
// [AdditionalInputLen = 0]
// [ReturnedBitsLen = 512]
// ============================================================
#if WEAVE_CONFIG_DRBG_WITHOUT_DERIVATION_FUNCTION // no DF
err = TestDRBG(NIST_CTR_DRBG_AES128_NoPR_NoDF_Count,
NIST_CTR_DRBG_AES128_NoPR_NoDF_PredictionResistance,
NIST_CTR_DRBG_AES128_NoPR_NoDF_Reseed,
NIST_CTR_DRBG_AES128_NoPR_NoDF_EntropyInput,
NIST_CTR_DRBG_AES128_NoPR_NoDF_EntropyInputLen,
NIST_CTR_DRBG_AES128_NoPR_NoDF_PersonalizationString,
NIST_CTR_DRBG_AES128_NoPR_NoDF_PersonalizationStringLen,
NIST_CTR_DRBG_AES128_NoPR_NoDF_AdditionalInput,
NIST_CTR_DRBG_AES128_NoPR_NoDF_AdditionalInputLen,
NIST_CTR_DRBG_AES128_NoPR_NoDF_ReturnedBytes,
NIST_CTR_DRBG_AES128_NoPR_NoDF_ReturnedBytesLen);
SuccessOrFail(err, "TestDRBG failed in NoPR & NoDF case\n");
#endif
// ============================================================
// [AES-128 use df]
// [PredictionResistance = False]
// [EntropyInputLen = 128]
// [NonceLen = 64]
// [PersonalizationStringLen = 128]
// [AdditionalInputLen = 128]
// [ReturnedBitsLen = 512]
// ============================================================
#if (WEAVE_CONFIG_DRBG_RESEED_INTERVAL > 0) // PredictionResistance = False
err = TestDRBG(NIST_CTR_DRBG_AES128_NoPR_UseDF_Count,
NIST_CTR_DRBG_AES128_NoPR_UseDF_PredictionResistance,
NIST_CTR_DRBG_AES128_NoPR_UseDF_Reseed,
NIST_CTR_DRBG_AES128_NoPR_UseDF_EntropyInput,
NIST_CTR_DRBG_AES128_NoPR_UseDF_EntropyInputLen,
NIST_CTR_DRBG_AES128_NoPR_UseDF_PersonalizationString,
NIST_CTR_DRBG_AES128_NoPR_UseDF_PersonalizationStringLen,
NIST_CTR_DRBG_AES128_NoPR_UseDF_AdditionalInput,
NIST_CTR_DRBG_AES128_NoPR_UseDF_AdditionalInputLen,
NIST_CTR_DRBG_AES128_NoPR_UseDF_ReturnedBytes,
NIST_CTR_DRBG_AES128_NoPR_UseDF_ReturnedBytesLen);
SuccessOrFail(err, "TestDRBG failed in NoPR & UseDF case\n");
#endif
// ============================================================
// [AES-128 no df]
// [PredictionResistance = True]
// [EntropyInputLen = 256]
// [NonceLen = 0]
// [PersonalizationStringLen = 256]
// [AdditionalInputLen = 256]
// [ReturnedBitsLen = 512]
// ============================================================
#if WEAVE_CONFIG_DRBG_WITHOUT_DERIVATION_FUNCTION // no DF
err = TestDRBG(NIST_CTR_DRBG_AES128_UsePR_NoDF_Count,
NIST_CTR_DRBG_AES128_UsePR_NoDF_PredictionResistance,
NIST_CTR_DRBG_AES128_UsePR_NoDF_Reseed,
NIST_CTR_DRBG_AES128_UsePR_NoDF_EntropyInput,
NIST_CTR_DRBG_AES128_UsePR_NoDF_EntropyInputLen,
NIST_CTR_DRBG_AES128_UsePR_NoDF_PersonalizationString,
NIST_CTR_DRBG_AES128_UsePR_NoDF_PersonalizationStringLen,
NIST_CTR_DRBG_AES128_UsePR_NoDF_AdditionalInput,
NIST_CTR_DRBG_AES128_UsePR_NoDF_AdditionalInputLen,
NIST_CTR_DRBG_AES128_UsePR_NoDF_ReturnedBytes,
NIST_CTR_DRBG_AES128_UsePR_NoDF_ReturnedBytesLen);
SuccessOrFail(err, "TestDRBG failed in UsePR & NoDF case\n");
#endif
// ============================================================
// [AES-128 use df]
// [PredictionResistance = True]
// [EntropyInputLen = 128]
// [NonceLen = 64]
// [PersonalizationStringLen = 0]
// [AdditionalInputLen = 128]
// [ReturnedBitsLen = 512]
// ============================================================
#if (WEAVE_CONFIG_DRBG_RESEED_INTERVAL == 0) // PredictionResistance = True
err = TestDRBG(NIST_CTR_DRBG_AES128_UsePR_UseDF_Count,
NIST_CTR_DRBG_AES128_UsePR_UseDF_PredictionResistance,
NIST_CTR_DRBG_AES128_UsePR_UseDF_Reseed,
NIST_CTR_DRBG_AES128_UsePR_UseDF_EntropyInput,
NIST_CTR_DRBG_AES128_UsePR_UseDF_EntropyInputLen,
NIST_CTR_DRBG_AES128_UsePR_UseDF_PersonalizationString,
NIST_CTR_DRBG_AES128_UsePR_UseDF_PersonalizationStringLen,
NIST_CTR_DRBG_AES128_UsePR_UseDF_AdditionalInput,
NIST_CTR_DRBG_AES128_UsePR_UseDF_AdditionalInputLen,
NIST_CTR_DRBG_AES128_UsePR_UseDF_ReturnedBytes,
NIST_CTR_DRBG_AES128_UsePR_UseDF_ReturnedBytesLen);
SuccessOrFail(err, "TestDRBG failed in UsePR & UseDF case\n");
#endif
// ============================================================
// [AES-128 no df]
// [PredictionResistance = False]
// [EntropyInputLen = 256]
// [NonceLen = 0]
// [PersonalizationStringLen = 0]
// [AdditionalInputLen = 256]
// [ReturnedBitsLen = 512]
// ============================================================
#if WEAVE_CONFIG_DRBG_WITHOUT_DERIVATION_FUNCTION // no DF
err = TestDRBG(NIST_CTR_DRBG_AES128_NoReseed_NoDF_Count,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_PredictionResistance,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_Reseed,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_EntropyInput,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_EntropyInputLen,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_PersonalizationString,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_PersonalizationStringLen,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_AdditionalInput,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_AdditionalInputLen,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_ReturnedBytes,
NIST_CTR_DRBG_AES128_NoReseed_NoDF_ReturnedBytesLen);
SuccessOrFail(err, "TestDRBG failed in NoReseed & NoDF case\n");
#endif
printf("All tests succeeded\n");
}