/* * 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. */ /** * @file * This file implements the generating pskc function. */ #include "utils/pskc.hpp" #include "common/code_utils.hpp" #include "common/logging.hpp" namespace otbr { namespace Psk { void Pskc::SetSalt(const uint8_t *aExtPanId, const char *aNetworkName) { const char *saltPrefix = "Thread"; int cur = 0; int ret = kPskcStatus_Ok; int remainingSpace = 0; int networkNameLen = 0; if (strlen(saltPrefix) + OT_EXTENDED_PAN_ID_LENGTH + strlen(aNetworkName) >= sizeof(mSalt)) { otbrLogWarning("Network name too long; will be truncated."); } memset(mSalt, 0, sizeof(mSalt)); memcpy(mSalt, saltPrefix, strlen(saltPrefix)); cur += strlen(saltPrefix); memcpy(mSalt + cur, aExtPanId, OT_EXTENDED_PAN_ID_LENGTH); cur += OT_EXTENDED_PAN_ID_LENGTH; VerifyOrExit(strlen(aNetworkName) > 0, ret = kPskcStatus_InvalidArgument); remainingSpace = sizeof(mSalt) - cur; if (remainingSpace > 0) { networkNameLen = std::min(static_cast(strlen(aNetworkName)), remainingSpace); memcpy(mSalt + cur, aNetworkName, networkNameLen); cur += networkNameLen; } mSaltLen = static_cast(cur); exit: if (ret != kPskcStatus_Ok) { otbrLogErr("ExtPanId or NetworkName is nullptr"); } return; } const uint8_t *Pskc::ComputePskc(const uint8_t *aExtPanId, const char *aNetworkName, const char *aPassphrase) { uint32_t blockCounter = 0; uint16_t useLen = 0; uint16_t prfBlockLen = MBEDTLS_CIPHER_BLKSIZE_MAX; uint8_t prfInput[OT_PBKDF2_SALT_MAX_LENGTH + 4]; uint8_t prfOutput[MBEDTLS_CIPHER_BLKSIZE_MAX]; uint8_t keyBlock[MBEDTLS_CIPHER_BLKSIZE_MAX]; uint16_t keyLen = OT_PSKC_LENGTH; uint8_t *pskc = mPskc; SetSalt(aExtPanId, aNetworkName); while (keyLen) { memcpy(prfInput, mSalt, mSaltLen); blockCounter++; prfInput[mSaltLen + 0] = (uint8_t)(blockCounter >> 24); prfInput[mSaltLen + 1] = (uint8_t)(blockCounter >> 16); prfInput[mSaltLen + 2] = (uint8_t)(blockCounter >> 8); prfInput[mSaltLen + 3] = (uint8_t)(blockCounter); // Calculate U_1 mbedtls_aes_cmac_prf_128(reinterpret_cast(aPassphrase), strlen(aPassphrase), prfInput, mSaltLen + 4, prfOutput); memcpy(keyBlock, prfOutput, prfBlockLen); for (uint32_t i = 1; i < OT_ITERATION_COUNTS; i++) { memcpy(prfInput, prfOutput, prfBlockLen); // Calculate U_i mbedtls_aes_cmac_prf_128(reinterpret_cast(aPassphrase), strlen(aPassphrase), prfInput, prfBlockLen, prfOutput); // xor for (uint32_t j = 0; j < prfBlockLen; j++) { keyBlock[j] ^= prfOutput[j]; } } useLen = (keyLen < prfBlockLen) ? keyLen : prfBlockLen; memcpy(pskc, keyBlock, useLen); pskc += useLen; keyLen -= useLen; } return mPskc; } } // namespace Psk } // namespace otbr