blob: 120503b7ce7d3ffd87844ff3e9b351dbc331efc4 [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 template object for doing counter (CTR)
* mode block ciphers and specialized objects for CTR mode
* AES-128 and AES-256.
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>
#include <string.h>
#include "WeaveCrypto.h"
#include "CTRMode.h"
namespace nl {
namespace Weave {
namespace Crypto {
template <class BlockCipher>
CTRMode<BlockCipher>::CTRMode()
{
memset(this, 0, sizeof(*this));
}
template <class BlockCipher>
CTRMode<BlockCipher>::~CTRMode()
{
Reset();
}
template <class BlockCipher>
void CTRMode<BlockCipher>::SetKey(const uint8_t *key)
{
mBlockCipher.SetKey(key);
}
template <class BlockCipher>
void CTRMode<BlockCipher>::SetCounter(const uint8_t *counter)
{
memcpy(Counter, counter, kCounterLength);
}
template <class BlockCipher>
void CTRMode<BlockCipher>::SetWeaveMessageCounter(uint64_t sendingNodeId, uint32_t msgId)
{
// Initialize the CTR-mode encryption counter for encrypting/decrypting a Weave message. In this mode
// the counter consists of a 128-bit big-endian number with the following format:
//
// (64-bits) | (32 bits) | (32 bits)
// <sending-node-id> | <message-id> | <block-counter>
//
Counter[0] = (uint8_t) (sendingNodeId >> (7 * 8));
Counter[1] = (uint8_t) (sendingNodeId >> (6 * 8));
Counter[2] = (uint8_t) (sendingNodeId >> (5 * 8));
Counter[3] = (uint8_t) (sendingNodeId >> (4 * 8));
Counter[4] = (uint8_t) (sendingNodeId >> (3 * 8));
Counter[5] = (uint8_t) (sendingNodeId >> (2 * 8));
Counter[6] = (uint8_t) (sendingNodeId >> (1 * 8));
Counter[7] = (uint8_t) (sendingNodeId);
Counter[8] = (uint8_t) (msgId >> (3 * 8));
Counter[9] = (uint8_t) (msgId >> (2 * 8));
Counter[10] = (uint8_t) (msgId >> (1 * 8));
Counter[11] = (uint8_t) (msgId);
Counter[12] = 0;
Counter[13] = 0;
Counter[14] = 0;
Counter[15] = 0;
}
template <class BlockCipher>
void CTRMode<BlockCipher>::EncryptData(const uint8_t *inData, uint16_t dataLen, uint8_t *outData)
{
// Index to next byte of encrypted counter to be used.
uint32_t encryptedCounterIndex = mMsgIndex % kCounterLength;
// For each byte of input data...
for (uint16_t dataIndex = 0; dataIndex < dataLen && mMsgIndex < UINT32_MAX; dataIndex++, mMsgIndex++)
{
// If we need more encrypted counter bytes...
if (encryptedCounterIndex == 0)
{
// Encrypt the next counter value.
mBlockCipher.EncryptBlock(Counter, mEncryptedCounter);
// Bump the counter. Since the message size is at most UINT32_MAX (and the counter counts blocks)
// we will never need to update more than the four least-significant bytes.
Counter[kCounterLength-1]++;
if (Counter[kCounterLength-1] == 0)
{
Counter[kCounterLength-2]++;
if (Counter[kCounterLength-2] == 0)
{
Counter[kCounterLength-3]++;
if (Counter[kCounterLength-3] == 0)
{
Counter[kCounterLength-4]++;
}
}
}
}
// XOR the data with the corresponding byte of the encrypted counter.
outData[dataIndex] = inData[dataIndex] ^ mEncryptedCounter[encryptedCounterIndex];
// Bump the counter index.
encryptedCounterIndex++;
if (encryptedCounterIndex == kCounterLength)
encryptedCounterIndex = 0;
}
}
template <class BlockCipher>
void CTRMode<BlockCipher>::Reset()
{
mBlockCipher.Reset();
mMsgIndex = 0;
memset(Counter, 0, sizeof(Counter));
ClearSecretData(mEncryptedCounter, sizeof(mEncryptedCounter));
}
template class CTRMode<Platform::Security::AES128BlockCipherEnc>;
template class CTRMode<Platform::Security::AES256BlockCipherEnc>;
} /* namespace Crypto */
} /* namespace Weave */
} /* namespace nl */