Skip to content

Commit

Permalink
Adds encryption capability to the CC32xx AES library. (bakerstu#302)
Browse files Browse the repository at this point in the history
- Adds encryption capability to the CC32xx AES library.

- Refactors the comparison test runner to a separate file so that
  a dev-build project can include the test runner and run it on real
  hardware.

- Moves the additional test vectors into a header.
  • Loading branch information
balazsracz authored Aug 1, 2019
1 parent db4766e commit 446e962
Show file tree
Hide file tree
Showing 4 changed files with 384 additions and 154 deletions.
106 changes: 92 additions & 14 deletions src/freertos_drivers/ti/CC32xxAes.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#ifndef _CC32xxAESCCM_HXX_
#define _CC32xxAESCCM_HXX_

#include <stdint.h>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_aes.h"
Expand Down Expand Up @@ -80,10 +82,46 @@ public:
*plain += part;
}

static void encrypt(const std::string &aes_key, const std::string &iv,
/// Performs authenticated encryption using CCM in one call. Use this when
/// all the plaintext is available and both cipher and plaintext fits into
/// memory.
///
/// @param aes_key is the secret key. 16, 24 or 32 bytes long.
/// @param nonce is the use-once initialization. Must be 13, 11 or 7 bytes
/// long.
/// @param auth_data is cleartext data (usually packet headers) that need
/// to be checked for authenticity.
/// @param plain is the plain text data.
/// @param tag_len is the desired length of the authentication
/// tag. Recommend 16.
/// @param cipher will hold the encrypted data.
/// @param tag will hold the authentication checksum. Will be resized to
/// tag_len.
static void encrypt(const std::string &aes_key, const std::string &nonce,
const std::string &auth_data, const std::string &plain,
std::string *cipher, std::string *tag)
unsigned tag_len, std::string *cipher, std::string *tag)
{
static_encrypt_init(aes_key, nonce, auth_data, plain.size(), tag_len);
cipher->resize(plain.size() + 15);
int len = plain.size();
unsigned ofs = 0;
while (len >= 16)
{
process_block(
(const uint8_t *)&plain[ofs], (uint8_t *)&(*cipher)[ofs]);
ofs += 16;
len -= 16;
}
if (len > 0)
{
uint8_t buf[16];
memset(buf, 0, sizeof(buf));
memcpy(buf, &plain[ofs], len);
process_block(buf, (uint8_t *)&(*cipher)[ofs]);
}
cipher->resize(plain.size());
tag->resize(tag_len);
read_tag(tag);
}

/// Initializes streaming decryption. Sets up the module for decryption and
Expand Down Expand Up @@ -143,6 +181,41 @@ public:
}
}

static void static_encrypt_init(const std::string &aes_key,
const std::string &nonce, const std::string &auth_data,
unsigned data_len, uint8_t tag_len)
{
reset();
// Sets configuration
unsigned mode = AES_CFG_DIR_ENCRYPT | AES_CFG_MODE_CCM |
AES_CFG_CTR_WIDTH_32 |
get_mode(aes_key.size(), nonce.size(), tag_len);
MAP_AESConfigSet(AES_BASE, mode);

// Computes the initialization vector form the nonce.
string real_iv;
real_iv.push_back(nonce_length_to_l(nonce.size()) - 1);
real_iv += nonce;
while (real_iv.size() < 16)
{
real_iv.push_back(0);
}
MAP_AESIVSet(AES_BASE, (uint8_t *)real_iv.data());

// Sets key and length variables needed before starting the decryption.
MAP_AESKey1Set(AES_BASE, (uint8_t *)aes_key.data(),
interpret_key_size(aes_key.size()));
MAP_AESDataLengthSet(AES_BASE, data_len);
MAP_AESAuthDataLengthSet(AES_BASE, auth_data.size());

// Writes the pre-authenticated data.
for (unsigned ofs = 0; ofs < auth_data.size(); ofs += 16)
{
MAP_AESDataWrite(AES_BASE, (uint8_t *)&auth_data[ofs],
std::min(16u, auth_data.size() - ofs));
}
}

/// Process streaming encryption data.
/// @param payload input data (ciphertext for decryption). Can be arbitrary
/// length (will be buffered internally if needed).
Expand Down Expand Up @@ -235,18 +308,7 @@ public:

int finalize(int status) override
{
unsigned tag_len = tagOut_->size();
tagOut_->resize(16);
//
// Wait for the context data registers to be ready.
//
while ((AES_CTRL_SVCTXTRDY & (HWREG(AES_BASE + AES_O_CTRL))) == 0)
{
}

MAP_AESTagRead(AES_BASE, (uint8_t *)&(tagOut_->at(0)));
tagOut_->resize(tag_len);

read_tag(tagOut_);
if (expectedTag_ && (*expectedTag_ != *tagOut_)) {
status = -2;
}
Expand Down Expand Up @@ -370,6 +432,22 @@ private:
MAP_AESDataRead(AES_BASE, dout, 16);
}

/// Finalizes encyrption/decryption and reads out the checksum tag.
/// @param tag_out needs to be resized to the desired number of bytes length
/// before calling. It will be filled with the checksum bytes.
static void read_tag(std::string* tag_out) {
uint8_t tag[16];
//
// Wait for the context data registers to be ready.
//
while ((AES_CTRL_SVCTXTRDY & (HWREG(AES_BASE + AES_O_CTRL))) == 0)
{
}

MAP_AESTagRead(AES_BASE, tag);
tag_out->assign((const char*)tag, tag_out->size());
}

/// Implementation object.
std::unique_ptr<SyncStream> decryptorStream_;
/// Stream that catches the decrypted output in the user-provided
Expand Down
150 changes: 150 additions & 0 deletions src/freertos_drivers/ti/CC32xxAesTest.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/** \copyright
* Copyright (c) 2019, Balazs Racz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - 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.
*
* 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 CC32xxAesTest.hxx
*
* Test runner for the CC32xx AES-CCM tests.
*
* @author Balazs Racz
* @date 29 July 2019
*/

#ifndef _FREERTOS_DRIVERS_TI_CC32XXAESTEST_HXX_
#define _FREERTOS_DRIVERS_TI_CC32XXAESTEST_HXX_

#define LOGLEVEL INFO

#include "freertos_drivers/ti/CC32xxHelper.hxx"
#include "freertos_drivers/ti/CC32xxAes.hxx"
#include "fs.h"

namespace aes_test {

int nibble_to_int(char n)
{
if ('0' <= n && n <= '9')
{
return n - '0';
}
if ('a' <= n && n <= 'f')
{
return n - 'a' + 10;
}
if ('A' <= n && n <= 'F')
{
return n - 'A' + 10;
}
DIE("Unknown nibble arrived.");
}

std::string hex2str(const char *hex)
{
std::string ret;
while (*hex && *(hex + 1))
{
if (*hex == ' ') {
++hex;
continue;
}
ret.push_back((nibble_to_int(*hex) << 4) | (nibble_to_int(*(hex + 1))));
hex += 2;
}
return ret;
}

const char HEXCHR[17] = "0123456789abcdef";

std::string str2hex(const string& s) {
std::string ret;
for (char c : s) {
ret.push_back(HEXCHR[c>>4]);
ret.push_back(HEXCHR[c & 0xf]);
}
return ret;
}

void get_example(int index, string &Key, string &Nonce, string &Adata,
string &Payload, string &CT)
{
#include "utils/AesCcmTestVectors.hxx"
#include "utils/AesCcmTestVectorsEx.hxx"
}

bool have_failure = false;

void printcomp(const string& exp, const string& act, const char* name) {
if (exp == act) {
LOG(INFO, "%s correct.", name);
return;
}
have_failure = true;
LOG(INFO, "%s failed.", name);
LOG(INFO, "Expected=%s", str2hex(exp).c_str());
LOG(INFO, "Actual =%s", str2hex(act).c_str());
}

/// @return true if the tests passed, false if they failed.
bool run_all_tests()
{
string key;
string nonce;
string auth_data;
string plain;
string cipher;
string tag;

for (int i : {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 60, 61, 62, 63, 63, 64, 65, 66, 10, 11, 12, 13, 14, 15, 16, 17, 18})
{
get_example(i, key, nonce, auth_data, plain, cipher);
// Move the last part of the cipher to the tag.
tag = cipher.substr(plain.size());
cipher.resize(plain.size());
LOG(INFO, "\nExample %d keylen=%d nlen=%d alen=%d taglen=%d datalen=%d", i, (int)key.size(), (int)nonce.size(), (int)auth_data.size(), (int)tag.size(), (int)plain.size());
usleep(5000);
string o_plain;
string o_tag;
o_tag.resize(tag.size());
HASSERT(cipher.size() == plain.size());
CCMHelper::decrypt(
key, nonce, auth_data, cipher, &o_plain, &o_tag);
printcomp(tag, o_tag, "tag");
printcomp(plain, o_plain, "plain");

LOG(INFO, "\nEncrypting");

string o_cipher;
o_tag.clear();
CCMHelper::encrypt(
key, nonce, auth_data, plain, tag.size(), &o_cipher, &o_tag);
printcomp(tag, o_tag, "tag");
printcomp(cipher, o_cipher, "cipher");
}
return !have_failure;
}

} // namespace aes_test

#endif // _FREERTOS_DRIVERS_TI_CC32XXAESTEST_HXX_
Loading

0 comments on commit 446e962

Please sign in to comment.