diff --git a/src/common/RC4Crypto.cpp b/src/common/RC4Crypto.cpp new file mode 100644 index 00000000..69d2af9e --- /dev/null +++ b/src/common/RC4Crypto.cpp @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +/* + * Digital Voice Modem - Common Library + * MIT Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2024 Bryan Biedenkapp, N2PLL + * + */ +#include "Defines.h" +#include "RC4Crypto.h" +#include "Log.h" +#include "Utils.h" + +using namespace crypto; + +#include +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/* Initializes a new instance of the AES class. */ + +RC4::RC4() = default; + +/* Encrypt/Decrypt input buffer with given key. */ + +uint8_t* RC4::crypt(const uint8_t in[], uint32_t inLen, const uint8_t key[], uint32_t keyLen) +{ + uint8_t permutation[RC4_PERMUTATION_CNT]; + ::memset(permutation, 0x00U, RC4_PERMUTATION_CNT); + + init(key, keyLen, permutation); + + uint8_t* out = new uint8_t[inLen]; + ::memset(out, 0x00U, inLen); + + transform(in, inLen, permutation, out); + return out; +} + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/* */ + +void RC4::swap(uint8_t* a, uint8_t i1, uint8_t i2) +{ + uint8_t temp = a[i1]; + a[i1] = a[i2]; + a[i2] = temp; +} + +/* */ + +void RC4::init(const uint8_t key[], uint8_t keyLen, uint8_t* permutation) +{ + assert(permutation != nullptr); + + // init state variable + for (uint32_t i = 0U; i < RC4_PERMUTATION_CNT; i++) + permutation[i] = (uint8_t)i; + + m_i1 = 0U; + m_i2 = 0U; + + // randomize, using key + for (int j = 0, i = 0; i < 256; i++) { + j = (j + permutation[i] + key[i % keyLen]) % RC4_PERMUTATION_CNT; + + // swap permutation[i] and permutation[j] + swap(permutation, i, j); + } +} + +/* */ + +void RC4::transform(const uint8_t* input, uint32_t length, uint8_t* permutation, uint8_t* output) +{ + assert(input != nullptr); + assert(output != nullptr); + + uint32_t i = 0U, j = 0U; + for (; i < length; i++, j++) { + // update indices + m_i1 = (uint8_t)((m_i1 + 1) % RC4_PERMUTATION_CNT); + m_i2 = (uint8_t)((m_i2 + permutation[m_i1]) % RC4_PERMUTATION_CNT); + + // swap permutation[m_i1] and permutation[m_i2] + swap(permutation, m_i1, m_i2); + + // transform byte + uint8_t b = (uint8_t)((permutation[m_i1] + permutation[m_i2]) % RC4_PERMUTATION_CNT); + output[j] = (uint8_t)(input[i] ^ permutation[b]); + } +} diff --git a/src/common/RC4Crypto.h b/src/common/RC4Crypto.h new file mode 100644 index 00000000..322cb5e2 --- /dev/null +++ b/src/common/RC4Crypto.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +/* + * Digital Voice Modem - Common Library + * MIT Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2024 Bryan Biedenkapp, N2PLL + * + */ +/** + * @defgroup crypto Cryptography + * @brief Defines and implements cryptography routines. + * @ingroup common + * + * @file RC4Crypto.h + * @ingroup crypto + * @file RC4Crypto.cpp + * @ingroup crypto + */ +#if !defined(__RC4_CRYPTO_H__) +#define __RC4_CRYPTO_H__ + +#include "common/Defines.h" + +namespace crypto +{ + // --------------------------------------------------------------------------- + // Constants + // --------------------------------------------------------------------------- + + const uint32_t RC4_PERMUTATION_CNT = 256; + + // --------------------------------------------------------------------------- + // Class Declaration + // --------------------------------------------------------------------------- + + /** + * @brief Rivest Cipher 4 Algorithm. + * @ingroup crypto + */ + class HOST_SW_API RC4 { + public: + /** + * @brief Initializes a new instance of the RC4 class. + */ + explicit RC4(); + + /** + * @brief Encrypt/Decrypt input buffer with given key. + * @param in Input buffer (if encrypted, will decrypt, if decrypted, will encrypt) + * @param inLen Input buffer length. + * @param key Encryption key. + * @param keyLen Encryption key length. + * @returns uint8_t* Encrypted input buffer. + */ + uint8_t* crypt(const uint8_t in[], uint32_t inLen, const uint8_t key[], uint32_t keyLen); + + private: + uint32_t m_i1; + uint32_t m_i2; + + void swap(uint8_t* a, uint8_t i1, uint8_t i2); + void init(const uint8_t key[], uint8_t keyLen, uint8_t* permutation); + void transform(const uint8_t* input, uint32_t length, uint8_t* permutation, uint8_t* output); + }; +} // namespace crypto + +#endif // __RC4_CRYPTO_H__ diff --git a/tests/crypto/RC4_Crypto_Test.cpp b/tests/crypto/RC4_Crypto_Test.cpp new file mode 100644 index 00000000..cd5e6bd4 --- /dev/null +++ b/tests/crypto/RC4_Crypto_Test.cpp @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only +/** +* Digital Voice Modem - Test Suite +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Test Suite +* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) +* +* Copyright (C) 2024 Bryan Biedenkapp, N2PLL +* +*/ +#include "host/Defines.h" +#include "common/RC4Crypto.h" +#include "common/Log.h" +#include "common/Utils.h" + +using namespace crypto; + +#include +#include +#include + +TEST_CASE("RC4", "[Crypto Test]") { + SECTION("RC4_Crypto_Test") { + bool failed = false; + + INFO("RC4 Crypto Test"); + + srand((unsigned int)time(NULL)); + + // key (K) + uint8_t K[8] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + + // message + uint8_t message[48] = + { + 0x90, 0x56, 0x00, 0x00, 0x2D, 0x75, 0xE6, 0x8D, 0x00, 0x89, 0x69, 0xCF, 0x00, 0xFE, 0x00, 0x04, + 0x4F, 0xC7, 0x60, 0xFF, 0x30, 0x3E, 0x2B, 0xAD, 0x00, 0x89, 0x69, 0xCF, 0x00, 0x00, 0x00, 0x08, + 0x52, 0x50, 0x54, 0x4C, 0x00, 0x89, 0x69, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // perform crypto + RC4* rc4 = new RC4(); + + Utils::dump(2U, "RC4_Crypto_Test, Message", message, 48); + + uint8_t* crypted = rc4->crypt(message, 48 * sizeof(uint8_t), K, 8); + Utils::dump(2U, "RC4_Crypto_Test, Encrypted", crypted, 48); + + uint8_t* decrypted = rc4->crypt(crypted, 48 * sizeof(uint8_t), K, 8); + Utils::dump(2U, "RC4_Crypto_Test, Decrypted", decrypted, 48); + + for (uint32_t i = 0; i < 48U; i++) { + if (decrypted[i] != message[i]) { + ::LogDebug("T", "RC4_Crypto_Test, INVALID AT IDX %d\n", i); + failed = true; + } + } + + delete rc4; + REQUIRE(failed==false); + } +} diff --git a/tests/edac/CRC_9_Test.cpp b/tests/edac/CRC_9_Test.cpp index 179896cf..920f72cf 100644 --- a/tests/edac/CRC_9_Test.cpp +++ b/tests/edac/CRC_9_Test.cpp @@ -39,7 +39,7 @@ TEST_CASE("CRC", "[9-bit Test]") { random[0U] = 0; random[1U] = 0; - uint16_t crc = edac::CRC::crc9(random, 144U); + uint16_t crc = edac::CRC::createCRC9(random, 144U); ::LogDebug("T", "crc = %04X", crc); random[0U] = random[0U] + ((crc >> 8) & 0x01U); @@ -50,8 +50,8 @@ TEST_CASE("CRC", "[9-bit Test]") { random[10U] >>= 8; random[11U] >>= 8; - uint16_t calculated = edac::CRC::crc9(random, 144U); - if (((crc ^ calculated) == 0) || ((crc ^ calculated) == 0x1FFU)) { + uint16_t calculated = edac::CRC::createCRC9(random, 144U); + if (((crc ^ calculated) == 0)/*|| ((crc ^ calculated) == 0x1FFU)*/) { ::LogDebug("T", "9_Sanity_Test, failed CRC9 error check"); failed = true; goto cleanup; diff --git a/tests/nxdn/AMBE_FEC_Test.cpp b/tests/nxdn/AMBE_FEC_Test.cpp index 1ecb1141..7500ec72 100644 --- a/tests/nxdn/AMBE_FEC_Test.cpp +++ b/tests/nxdn/AMBE_FEC_Test.cpp @@ -19,6 +19,7 @@ using namespace edac; using namespace nxdn; +using namespace nxdn::defines; #include diff --git a/tests/p25/HDU_RS_Test.cpp b/tests/p25/HDU_RS_Test.cpp index 8f335f0d..957723f2 100644 --- a/tests/p25/HDU_RS_Test.cpp +++ b/tests/p25/HDU_RS_Test.cpp @@ -18,6 +18,7 @@ using namespace edac; using namespace p25; +using namespace p25::defines; #include #include diff --git a/tests/p25/LDU1_RS_Test.cpp b/tests/p25/LDU1_RS_Test.cpp index 2cd1a9d4..cedad569 100644 --- a/tests/p25/LDU1_RS_Test.cpp +++ b/tests/p25/LDU1_RS_Test.cpp @@ -18,6 +18,7 @@ using namespace edac; using namespace p25; +using namespace p25::defines; #include #include @@ -39,26 +40,26 @@ TEST_CASE("LDU1", "[Reed-Soloman 24,12,13 Test]") { } // LDU1 Encode - uint8_t rs[P25_LDU_LC_LENGTH_BYTES]; - ::memset(rs, 0x00U, P25_LDU_LC_LENGTH_BYTES); + uint8_t rs[P25_LDU_LC_FEC_LENGTH_BYTES]; + ::memset(rs, 0x00U, P25_LDU_LC_FEC_LENGTH_BYTES); for (uint32_t i = 0; i < 9U; i++) rs[i] = random[i]; rs[8U] = 0xF0U; - Utils::dump(2U, "LC::encodeLDU1(), LDU1", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::encodeLDU1(), LDU1", rs, P25_LDU_LC_FEC_LENGTH_BYTES); // encode RS (24,12,13) FEC m_rs.encode241213(rs); - Utils::dump(2U, "LC::encodeLDU1(), LDU1 RS", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::encodeLDU1(), LDU1 RS", rs, P25_LDU_LC_FEC_LENGTH_BYTES); // LDU1 Decode rs[6U] >>= 8; rs[7U] >>= 8; rs[8U] >>= 8; - Utils::dump(2U, "LC::encodeLDU1(), LDU RS (errors injected)", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::encodeLDU1(), LDU RS (errors injected)", rs, P25_LDU_LC_FEC_LENGTH_BYTES); // decode RS (24,12,13) FEC try { @@ -70,12 +71,12 @@ TEST_CASE("LDU1", "[Reed-Soloman 24,12,13 Test]") { } } catch (...) { - Utils::dump(2U, "P25, RS excepted with input data", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "P25, RS excepted with input data", rs, P25_LDU_LC_FEC_LENGTH_BYTES); failed = true; goto cleanup; } - Utils::dump(2U, "LC::decodeLDU1(), LDU1", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::decodeLDU1(), LDU1", rs, P25_LDU_LC_FEC_LENGTH_BYTES); for (uint32_t i = 0; i < 9U; i++) { if (i == 8U) { diff --git a/tests/p25/LDU2_RS_Test.cpp b/tests/p25/LDU2_RS_Test.cpp index cebed74b..8b31a323 100644 --- a/tests/p25/LDU2_RS_Test.cpp +++ b/tests/p25/LDU2_RS_Test.cpp @@ -18,6 +18,7 @@ using namespace edac; using namespace p25; +using namespace p25::defines; #include #include @@ -39,25 +40,25 @@ TEST_CASE("LDU2", "[Reed-Soloman 24,16,9 Test]") { } // LDU2 Encode - uint8_t rs[P25_LDU_LC_LENGTH_BYTES]; - ::memset(rs, 0x00U, P25_LDU_LC_LENGTH_BYTES); + uint8_t rs[P25_LDU_LC_FEC_LENGTH_BYTES]; + ::memset(rs, 0x00U, P25_LDU_LC_FEC_LENGTH_BYTES); for (uint32_t i = 0; i < 12U; i++) rs[i] = random[i]; rs[11U] = 0xF0U; - Utils::dump(2U, "LC::encodeLDU2(), LDU2", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::encodeLDU2(), LDU2", rs, P25_LDU_LC_FEC_LENGTH_BYTES); // encode RS (24,16,9) FEC m_rs.encode24169(rs); - Utils::dump(2U, "LC::encodeLDU2(), LDU2 RS", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::encodeLDU2(), LDU2 RS", rs, P25_LDU_LC_FEC_LENGTH_BYTES); // LDU2 Decode rs[9U] >>= 4; rs[10U] >>= 4; - Utils::dump(2U, "LC::decodeLDU2(), LDU RS (errors injected)", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::decodeLDU2(), LDU RS (errors injected)", rs, P25_LDU_LC_FEC_LENGTH_BYTES); // decode RS (24,16,9) FEC try { @@ -69,12 +70,12 @@ TEST_CASE("LDU2", "[Reed-Soloman 24,16,9 Test]") { } } catch (...) { - Utils::dump(2U, "P25, RS excepted with input data", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "P25, RS excepted with input data", rs, P25_LDU_LC_FEC_LENGTH_BYTES); failed = true; goto cleanup; } - Utils::dump(2U, "LC::decodeLDU2(), LDU2", rs, P25_LDU_LC_LENGTH_BYTES); + Utils::dump(2U, "LC::decodeLDU2(), LDU2", rs, P25_LDU_LC_FEC_LENGTH_BYTES); for (uint32_t i = 0; i < 12U; i++) { if (i == 11U) {