| /* |
| * |
| * 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 */ |