From ffd28ebd4d874fbc71f556ced86efc306e6a2d4b Mon Sep 17 00:00:00 2001 From: Buke Po Date: Fri, 21 Jul 2017 13:15:44 +0800 Subject: [PATCH] [crypto] reduce memcpy() usage (#2018) --- src/core/crypto/pbkdf2_cmac.cpp | 58 +++++++++++++--------- tests/unit/Makefile.am | 4 ++ tests/unit/test_ncp_buffer.cpp | 4 +- tests/unit/test_pskc.cpp | 88 +++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 24 deletions(-) create mode 100644 tests/unit/test_pskc.cpp diff --git a/src/core/crypto/pbkdf2_cmac.cpp b/src/core/crypto/pbkdf2_cmac.cpp index ef676cb5b..df5643c92 100644 --- a/src/core/crypto/pbkdf2_cmac.cpp +++ b/src/core/crypto/pbkdf2_cmac.cpp @@ -35,6 +35,7 @@ #include "pbkdf2_cmac.h" +#include "common/debug.hpp" #include "utils/wrap_string.h" #include @@ -47,44 +48,57 @@ void otPbkdf2Cmac( uint32_t aIterationCounter, uint16_t aKeyLen, uint8_t *aKey) { - uint32_t blockCounter = 0; - uint16_t useLen = 0; - uint16_t prfBlockLen = MBEDTLS_CIPHER_BLKSIZE_MAX; + const size_t kBlockSize = MBEDTLS_CIPHER_BLKSIZE_MAX; uint8_t prfInput[OT_PBKDF2_SALT_MAX_LEN + 4]; // Salt || INT(), for U1 calculation - uint8_t prfOutput[MBEDTLS_CIPHER_BLKSIZE_MAX]; - uint8_t keyBlock[MBEDTLS_CIPHER_BLKSIZE_MAX]; + long prfOne[kBlockSize / sizeof(long)]; + long prfTwo[kBlockSize / sizeof(long)]; + long keyBlock[kBlockSize / sizeof(long)]; + uint32_t blockCounter = 0; uint8_t *key = aKey; uint16_t keyLen = aKeyLen; + uint16_t useLen = 0; + + memcpy(prfInput, aSalt, aSaltLen); + assert(aIterationCounter % 2 == 0); + aIterationCounter /= 2; while (keyLen) { - memcpy(prfInput, aSalt, aSaltLen); - - blockCounter++; - prfInput[aSaltLen + 0] = (uint8_t)(blockCounter >> 24); - prfInput[aSaltLen + 1] = (uint8_t)(blockCounter >> 16); - prfInput[aSaltLen + 2] = (uint8_t)(blockCounter >> 8); - prfInput[aSaltLen + 3] = (uint8_t)(blockCounter); + ++blockCounter; + prfInput[aSaltLen + 0] = static_cast(blockCounter >> 24); + prfInput[aSaltLen + 1] = static_cast(blockCounter >> 16); + prfInput[aSaltLen + 2] = static_cast(blockCounter >> 8); + prfInput[aSaltLen + 3] = static_cast(blockCounter); // Calculate U_1 - mbedtls_aes_cmac_prf_128(aPassword, aPasswordLen, prfInput, aSaltLen + 4, prfOutput); - memcpy(keyBlock, prfOutput, prfBlockLen); + mbedtls_aes_cmac_prf_128(aPassword, aPasswordLen, prfInput, aSaltLen + 4, + reinterpret_cast(keyBlock)); - for (uint32_t i = 1; i < aIterationCounter; i++) + // Calculate U_2 + mbedtls_aes_cmac_prf_128(aPassword, aPasswordLen, reinterpret_cast(keyBlock), + kBlockSize, reinterpret_cast(prfOne)); + + for (uint32_t j = 0; j < kBlockSize / sizeof(long); ++j) { - memcpy(prfInput, prfOutput, prfBlockLen); + keyBlock[j] ^= prfOne[j]; + } - // Calculate U_i - mbedtls_aes_cmac_prf_128(aPassword, aPasswordLen, prfInput, prfBlockLen, prfOutput); + for (uint32_t i = 1; i < aIterationCounter; ++i) + { + // Calculate U_{2 * i - 1} + mbedtls_aes_cmac_prf_128(aPassword, aPasswordLen, reinterpret_cast(prfOne), + kBlockSize, reinterpret_cast(prfTwo)); + // Calculate U_{2 * i} + mbedtls_aes_cmac_prf_128(aPassword, aPasswordLen, reinterpret_cast(prfTwo), + kBlockSize, reinterpret_cast(prfOne)); - // xor - for (uint32_t j = 0; j < prfBlockLen; j++) + for (uint32_t j = 0; j < kBlockSize / sizeof(long); ++j) { - keyBlock[j] ^= prfOutput[j]; + keyBlock[j] ^= prfOne[j] ^ prfTwo[j]; } } - useLen = (keyLen < prfBlockLen) ? keyLen : prfBlockLen; + useLen = (keyLen < kBlockSize) ? keyLen : kBlockSize; memcpy(key, keyBlock, useLen); key += useLen; keyLen -= useLen; diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index e869c9955..44b4177b3 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -96,6 +96,7 @@ check_PROGRAMS = \ test-message \ test-message-queue \ test-priority-queue \ + test-pskc \ test-strlcat \ test-strlcpy \ test-strnlen \ @@ -173,6 +174,9 @@ test_ncp_buffer_SOURCES = test_platform.cpp test_ncp_buffer.cpp test_priority_queue_LDADD = $(COMMON_LDADD) test_priority_queue_SOURCES = test_platform.cpp test_priority_queue.cpp +test_pskc_LDADD = $(COMMON_LDADD) +test_pskc_SOURCES = test_platform.cpp test_pskc.cpp + test_strlcat_LDADD = $(COMMON_LDADD) test_strlcat_SOURCES = test_strlcat.c diff --git a/tests/unit/test_ncp_buffer.cpp b/tests/unit/test_ncp_buffer.cpp index a2596254d..9e3f38880 100644 --- a/tests/unit/test_ncp_buffer.cpp +++ b/tests/unit/test_ncp_buffer.cpp @@ -817,7 +817,7 @@ void TestNcpFrameBuffer(void) SuccessOrQuit(ncpBuffer.InFrameFeedData(sHexText, index), "InFrameFeedData() failed."); SuccessOrQuit(ncpBuffer.InFrameGetPosition(pos1), "InFrameGetPosition() failed"); SuccessOrQuit(ncpBuffer.InFrameFeedData(sMysteryText, sizeof(sHexText) - index), "InFrameFeedData() failed."); - VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index , "InFrameGetDistance() failed"); + VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index, "InFrameGetDistance() failed"); if (addExtra) { @@ -862,7 +862,7 @@ void TestNcpFrameBuffer(void) SuccessOrQuit(ncpBuffer.InFrameFeedData(sHexText, index), "InFrameFeedData() failed."); SuccessOrQuit(ncpBuffer.InFrameGetPosition(pos1), "InFrameGetPosition() failed"); SuccessOrQuit(ncpBuffer.InFrameFeedData(sMysteryText, sizeof(sHexText) - index), "InFrameFeedData() failed."); - VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index , "InFrameGetDistance() failed"); + VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index, "InFrameGetDistance() failed"); if (addExtra) { diff --git a/tests/unit/test_pskc.cpp b/tests/unit/test_pskc.cpp new file mode 100644 index 000000000..bab836fac --- /dev/null +++ b/tests/unit/test_pskc.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include + +#include "meshcop/commissioner.hpp" +#include "utils/wrap_string.h" +#include "common/logging.hpp" + +#include "test_platform.h" +#include "test_util.h" + +static const uint8_t sXPanId[] = +{ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +}; + +void TestMinimumPassphrase(void) +{ + uint8_t pskc[OT_PSKC_MAX_SIZE]; + const uint8_t expectedPskc[] = + { + 0x44, 0x98, 0x8e, 0x22, 0xcf, 0x65, 0x2e, 0xee, + 0xcc, 0xd1, 0xe4, 0xc0, 0x1d, 0x01, 0x54, 0xf8 + }; + const char passphrase[] = "123456"; + otInstance *instance = testInitInstance(); + SuccessOrQuit(ot::MeshCoP::Commissioner::GeneratePSKc(passphrase, "OpenThread", sXPanId, pskc), + "TestMinimumPassphrase failed to generate PSKc"); + VerifyOrQuit(memcmp(pskc, expectedPskc, sizeof(pskc)) == 0, "TestMinimumPassphrase got wrong pskc"); + testFreeInstance(instance); +} + +void TestMaximumPassphrase(void) +{ + uint8_t pskc[OT_PSKC_MAX_SIZE]; + const uint8_t expectedPskc[] = + { + 0x9e, 0x81, 0xbd, 0x35, 0xa2, 0x53, 0x76, 0x2f, + 0x80, 0xee, 0x04, 0xff, 0x2f, 0xa2, 0x85, 0xe9 + }; + const char passphrase[] = + "1234567812345678" "1234567812345678" "1234567812345678" "1234567812345678" + "1234567812345678" "1234567812345678" "1234567812345678" "1234567812345678" + "1234567812345678" "1234567812345678" "1234567812345678" "1234567812345678" + "1234567812345678" "1234567812345678" "1234567812345678" "123456781234567"; + + otInstance *instance = testInitInstance(); + SuccessOrQuit(ot::MeshCoP::Commissioner::GeneratePSKc(passphrase, "OpenThread", sXPanId, pskc), + "TestMaximumPassphrase failed to generate PSKc"); + VerifyOrQuit(memcmp(pskc, expectedPskc, sizeof(pskc)) == 0, "TestMaximumPassphrase got wrong pskc"); + testFreeInstance(instance); +} + +#ifdef ENABLE_TEST_MAIN +int main(void) +{ + TestMinimumPassphrase(); + TestMaximumPassphrase(); + printf("All tests passed\n"); + return 0; +} +#endif