Skip to content

Commit

Permalink
Add chacha20 crypto
Browse files Browse the repository at this point in the history
  • Loading branch information
Igor-Misic committed Mar 27, 2024
1 parent 8d0a9e5 commit 28c8c93
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 5 deletions.
11 changes: 11 additions & 0 deletions Inc/bit_manipulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,15 @@ bool BitManipulation_clearBit(uint32_t data, uint8_t n, uint32_t* out);
*/
bool BitManipulation_toggleBit(uint32_t data, uint8_t n, uint32_t* out);


/**
* @brief This function rotates the bits of a 32-bit variable to the left.
*
* @param[in] data The input data to rotate.
* @param[in] n_bits The number of bits in the data to be rotated.
*
* @return The rotated data.
*/
uint32_t BitManipulation_rotl32(uint32_t data, uint32_t n_bits);

#endif /* UTILITY_BIT_MANIPULATION_H_ */
50 changes: 50 additions & 0 deletions Inc/crypto/chacha20.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/****************************************************************************
*
* Copyright (c) 2024 IMProject Development Team. All rights reserved.
* Authors: Igor Misic <[email protected]>
*
* 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 IMProject 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 OWNER 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.
*
****************************************************************************/

#ifndef UTILITY_CHACHA20_H_
#define UTILITY_CHACHA20_H_

#include "typedefs.h"

#define CHACHA20_KEY_SIZE 32U
#define CHACHA20_NONCE_SIZE 12U

void chacha20(const byte_t* plaintext,
uint32_t plaintext_len,
const byte_t key[CHACHA20_KEY_SIZE],
const byte_t nonce[CHACHA20_NONCE_SIZE],
uint32_t inc,
byte_t* encrypted_message);

#endif /* UTILITY_CHACHA20_H_ */
2 changes: 1 addition & 1 deletion Inc/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ void Utils_Serialize24LE(byte_t* buf, uint32_t value);
*
* @note The buffer must be at least 4 bytes long to accommodate the serialized value.
*/
void Utils_Serialize32LE(byte_t* buf, uint32_t value);
void Utils_Serialize32LE(byte_t* const buf, uint32_t value);

/**
* @brief Serialize a blob of data in little-endian format.
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ IMUTILITY_FILES=\
Src/crc/crc32_variants/crc32_q.c \
Src/crc/crc32_variants/crc32_xfer.c \
Src/crypto/caesar_cipher.c \
Src/crypto/chacha20.c \
Src/sort/bubble_sort.c \
Src/sort/heap_sort.c \
Src/sort/insertion_sort.c \
Expand All @@ -126,6 +127,7 @@ SRC_FILES+=$(IMUTILITY_FILES) \
Tests/test_bit_manipulation.c \
Tests/test_bubble_sort.c \
Tests/test_caesar_cipher.c \
Tests/test_chacha20.c \
Tests/test_crc8.c \
Tests/test_crc16.c \
Tests/test_crc32.c \
Expand All @@ -138,14 +140,16 @@ SRC_FILES+=$(IMUTILITY_FILES) \
Tests/test_scheduler.c \
Tests/test_selection_sort.c \
Tests/test_utils.c
INC_DIRS_CODE=\

INC_DIRS_CODE= \
-IInc \
-IInc/crypto \
-IInc/crc \
-IInc/crc/crc8_variants \
-IInc/crc/crc16_variants \
-IInc/crc/crc32_variants \
-IInc/crypto \
-IInc/sort

INC_DIRS=$(INC_DIRS_CODE) -I$(UNITY_ROOT)/src -I$(UNITY_ROOT)/extras/fixture/src
SYMBOLS = -DUNITY_FIXTURE_NO_EXTRAS
SYMBOLS += -DUNITY_INCLUDE_DOUBLE
Expand Down
13 changes: 12 additions & 1 deletion Src/bit_manipulation.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2023 IMProject Development Team. All rights reserved.
* Copyright (c) 2023 - 2024 IMProject Development Team. All rights reserved.
* Authors: Juraj Ciberlin <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -103,3 +103,14 @@ BitManipulation_toggleBit(uint32_t data, uint8_t n, uint32_t* out) {
}
return status;
}

uint32_t
BitManipulation_rotl32(uint32_t data, uint32_t n_bits) {

uint32_t n_bits_tmp = n_bits;
if (n_bits > 32U) {
n_bits_tmp = n_bits % 32U;
}
/* -E> compliant MC3R1.R12.2 1 Right and left-hand operands of shift expression are between 0 and 31 due to the previous IF statement. */
return ((data << n_bits_tmp) ^ (data >> (32U - n_bits_tmp)));
}
174 changes: 174 additions & 0 deletions Src/crypto/chacha20.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/****************************************************************************
*
* Copyright (c) 2024 IMProject Development Team. All rights reserved.
* Authors: Igor Misic <[email protected]>
*
* 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 IMProject 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 OWNER 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.
*
****************************************************************************/

// Chacha20 definition document : https://datatracker.ietf.org/doc/html/rfc8439

#include "chacha20.h"

#include "bit_manipulation.h"
#include "utils.h"

#define KEY_STREAM_SIZE 64U
#define BLOCK_SIZE 64U

// Hex representation of Magic number: "expand 32-byte k"
#define CHACHA_MAGIC_NUMBER_PART_1 (0x61707865U)
#define CHACHA_MAGIC_NUMBER_PART_2 (0x3320646eU)
#define CHACHA_MAGIC_NUMBER_PART_3 (0x79622d32U)
#define CHACHA_MAGIC_NUMBER_PART_4 (0x6b206574U)

#define ARRAY_64_ZERO_VALUES { \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, \
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U \
}

static inline void quarterround(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d);
static void chacha20_block(const byte_t key[CHACHA20_KEY_SIZE], const uint32_t counter,
const byte_t nonce[CHACHA20_NONCE_SIZE],
byte_t out[KEY_STREAM_SIZE]);

static inline void
quarterround(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d) {
*a += *b;
*d = BitManipulation_rotl32(*d ^ *a, 16);
*c += *d;
*b = BitManipulation_rotl32(*b ^ *c, 12);
*a += *b;
*d = BitManipulation_rotl32(*d ^ *a, 8);
*c += *d;
*b = BitManipulation_rotl32(*b ^ *c, 7);
}

static void
chacha20_block(const byte_t key[CHACHA20_KEY_SIZE], const uint32_t counter, const byte_t nonce[CHACHA20_NONCE_SIZE],
byte_t out[KEY_STREAM_SIZE]) {

uint32_t x0 = CHACHA_MAGIC_NUMBER_PART_1;
uint32_t x1 = CHACHA_MAGIC_NUMBER_PART_2;
uint32_t x2 = CHACHA_MAGIC_NUMBER_PART_3;
uint32_t x3 = CHACHA_MAGIC_NUMBER_PART_4;
uint32_t x4 = Utils_Deserialize32LE((uint8_t*)&key[0]);
uint32_t x5 = Utils_Deserialize32LE((uint8_t*)&key[4]);
uint32_t x6 = Utils_Deserialize32LE((uint8_t*)&key[8]);
uint32_t x7 = Utils_Deserialize32LE((uint8_t*)&key[12]);
uint32_t x8 = Utils_Deserialize32LE((uint8_t*)&key[16]);
uint32_t x9 = Utils_Deserialize32LE((uint8_t*)&key[20]);
uint32_t x10 = Utils_Deserialize32LE((uint8_t*)&key[24]);
uint32_t x11 = Utils_Deserialize32LE((uint8_t*)&key[28]);
uint32_t x12 = counter;
uint32_t x13 = Utils_Deserialize32LE((uint8_t*)&nonce[0]);
uint32_t x14 = Utils_Deserialize32LE((uint8_t*)&nonce[4]);
uint32_t x15 = Utils_Deserialize32LE((uint8_t*)&nonce[8]);

for (uint8_t i = 0; i < 10U; ++i) {
quarterround(&x0, &x4, &x8, &x12);
quarterround(&x1, &x5, &x9, &x13);
quarterround(&x2, &x6, &x10, &x14);
quarterround(&x3, &x7, &x11, &x15);
quarterround(&x0, &x5, &x10, &x15);
quarterround(&x1, &x6, &x11, &x12);
quarterround(&x2, &x7, &x8, &x13);
quarterround(&x3, &x4, &x9, &x14);
}

x0 += CHACHA_MAGIC_NUMBER_PART_1;
x1 += CHACHA_MAGIC_NUMBER_PART_2;
x2 += CHACHA_MAGIC_NUMBER_PART_3;
x3 += CHACHA_MAGIC_NUMBER_PART_4;
x4 += Utils_Deserialize32LE((uint8_t*)&key[0]);
x5 += Utils_Deserialize32LE((uint8_t*)&key[4]);
x6 += Utils_Deserialize32LE((uint8_t*)&key[8]);
x7 += Utils_Deserialize32LE((uint8_t*)&key[12]);
x8 += Utils_Deserialize32LE((uint8_t*)&key[16]);
x9 += Utils_Deserialize32LE((uint8_t*)&key[20]);
x10 += Utils_Deserialize32LE((uint8_t*)&key[24]);
x11 += Utils_Deserialize32LE((uint8_t*)&key[28]);
x12 += counter;
x13 += Utils_Deserialize32LE((uint8_t*)&nonce[0]);
x14 += Utils_Deserialize32LE((uint8_t*)&nonce[4]);
x15 += Utils_Deserialize32LE((uint8_t*)&nonce[8]);

Utils_Serialize32LE((uint8_t*)&out[0], x0);
Utils_Serialize32LE((uint8_t*)&out[4], x1);
Utils_Serialize32LE((uint8_t*)&out[8], x2);
Utils_Serialize32LE((uint8_t*)&out[12], x3);
Utils_Serialize32LE((uint8_t*)&out[16], x4);
Utils_Serialize32LE((uint8_t*)&out[20], x5);
Utils_Serialize32LE((uint8_t*)&out[24], x6);
Utils_Serialize32LE((uint8_t*)&out[28], x7);
Utils_Serialize32LE((uint8_t*)&out[32], x8);
Utils_Serialize32LE((uint8_t*)&out[36], x9);
Utils_Serialize32LE((uint8_t*)&out[40], x10);
Utils_Serialize32LE((uint8_t*)&out[44], x11);
Utils_Serialize32LE((uint8_t*)&out[48], x12);
Utils_Serialize32LE((uint8_t*)&out[52], x13);
Utils_Serialize32LE((uint8_t*)&out[56], x14);
Utils_Serialize32LE((uint8_t*)&out[60], x15);
}

void
chacha20(const byte_t* plaintext,
uint32_t plaintext_len,
const byte_t key[CHACHA20_KEY_SIZE],
const byte_t nonce[CHACHA20_NONCE_SIZE],
uint32_t inc,
byte_t* encrypted_message) {

uint32_t blocks = plaintext_len / BLOCK_SIZE;
uint32_t remaining_bytes = plaintext_len % BLOCK_SIZE;

for (uint32_t j = 0; j < blocks; ++j) {
byte_t key_stream[KEY_STREAM_SIZE] = ARRAY_64_ZERO_VALUES;
chacha20_block(key, j + inc, nonce, key_stream);

for (uint8_t i = 0; i < BLOCK_SIZE; ++i) {
encrypted_message[(j * BLOCK_SIZE) + i] = plaintext[(j * BLOCK_SIZE) + i] ^ key_stream[i];
}
}

if (0U != remaining_bytes) {
byte_t key_stream[KEY_STREAM_SIZE] = ARRAY_64_ZERO_VALUES;
chacha20_block(key, blocks + inc, nonce, key_stream);

for (uint32_t i = 0; i < remaining_bytes; ++i) {
encrypted_message[(blocks * BLOCK_SIZE) + i] = plaintext[(blocks * BLOCK_SIZE) + i] ^ key_stream[i];
}
}
}
2 changes: 1 addition & 1 deletion Src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ Utils_Serialize24LE(byte_t* buf, uint32_t value) {
}

void
Utils_Serialize32LE(byte_t* buf, uint32_t value) {
Utils_Serialize32LE(byte_t* const buf, uint32_t value) {
buf[3] = (uint8_t)(value >> 24u) & 0xFFu;
buf[2] = (uint8_t)(value >> 16u) & 0xFFu;
buf[1] = (uint8_t)(value >> 8u) & 0xFFu;
Expand Down
24 changes: 24 additions & 0 deletions Tests/test_bit_manipulation.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ TEST_GROUP_RUNNER(BitManipulation) {
RUN_TEST_CASE(BitManipulation, BitManipulation_setBit);
RUN_TEST_CASE(BitManipulation, BitManipulation_clearBit);
RUN_TEST_CASE(BitManipulation, BitManipulation_toggleBit);
RUN_TEST_CASE(BitManipulation, BitManipulation_rotl32);
}

TEST(BitManipulation, BitManipulation_reflect) {
Expand Down Expand Up @@ -83,3 +84,26 @@ TEST(BitManipulation, BitManipulation_toggleBit) {
TEST_ASSERT_TRUE(BitManipulation_toggleBit(data, 4U, &out_data));
TEST_ASSERT_EQUAL_UINT32(0b10100011U, out_data);
}

TEST(BitManipulation, BitManipulation_rotl32) {
const uint32_t data = 0b10110011U;

uint8_t n_bits = 2U;
TEST_ASSERT_BITS(0xFFFFFFFF, 0b00000000000000000000001011001100U, BitManipulation_rotl32(data, n_bits));

n_bits = 3U;
TEST_ASSERT_BITS(0xFFFFFFFF, 0b00000000000000000000010110011000U, BitManipulation_rotl32(data, n_bits));

n_bits = 4U;
TEST_ASSERT_BITS(0xFFFFFFFF, 0b00000000000000000000101100110000U, BitManipulation_rotl32(data, n_bits));

n_bits = 16U;
TEST_ASSERT_BITS(0xFFFFFFFF, 0b00000000101100110000000000000000U, BitManipulation_rotl32(data, n_bits));

n_bits = 32U;
TEST_ASSERT_BITS(0xFFFFFFFF, 0b00000000000000000000000010110011U, BitManipulation_rotl32(data, n_bits));

n_bits = 34U;
TEST_ASSERT_BITS(0xFFFFFFFF, 0b00000000000000000000001011001100U, BitManipulation_rotl32(data, n_bits));
}

Loading

0 comments on commit 28c8c93

Please sign in to comment.