diff --git a/include/nt/rc6.hpp b/include/nt/rc6.hpp new file mode 100644 index 000000000..c1eeeee85 --- /dev/null +++ b/include/nt/rc6.hpp @@ -0,0 +1,117 @@ +/************************************************************************* + * + * Project + * _____ _____ __ __ _____ + * / ____| __ \| \/ | __ \ + * ___ _ __ ___ _ __ | | __| |__) | \ / | |__) | + * / _ \| '_ \ / _ \ '_ \| | |_ | ___/| |\/| | ___/ + *| (_) | |_) | __/ | | | |__| | | | | | | | + * \___/| .__/ \___|_| |_|\_____|_| |_| |_|_| + * | | + * |_| + * + * Copyright (C) Akiel Aries, , et al. + * + * This software is licensed as described in the file LICENSE, which + * you should have received as part of this distribution. The terms + * among other details are referenced in the official documentation + * seen here : https://akielaries.github.io/openGPMP/ along with + * important files seen in this project. + * + * You may opt to use, copy, modify, merge, publish, distribute + * and/or sell copies of the Software, and permit persons to whom + * the Software is furnished to do so, under the terms of the + * LICENSE file. As this is an Open Source effort, all implementations + * must be of the same methodology. + * + * + * + * This software is distributed on an AS IS basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. + * + ************************************************************************/ + +#ifndef RC6_HPP +#define RC6_HPP + +#include +#include + +/** + * @class RC6 + * @brief Class implementing the RC6 cipher algorithm + */ +class RC6 { + public: + /** + * @brief Constructor for RC6 class + * @param key The encryption key + */ + RC6(const std::vector &key); + + /** + * @brief Encrypts plaintext using RC6 algorithm + * @param plaintext The plaintext to encrypt + * @return The encrypted ciphertext + */ + std::vector encrypt(const std::vector &plaintext); + + /** + * @brief Decrypts ciphertext using RC6 algorithm + * @param ciphertext The ciphertext to decrypt + * @return The decrypted plaintext + */ + std::vector decrypt(const std::vector &ciphertext); + + private: + const int w = 32; /**< Word size */ + const int r = 20; /**< Number of rounds */ + const int b = 16; /**< Number of bytes in key */ + + std::vector S; /**< Internal state array */ + + /** + * @brief Generates the key schedule from the given key + * @param key The encryption key + */ + void key_schedule(const std::vector &key); + + /** + * @brief Performs key expansion + * @param key The encryption key + * @return The expanded key schedule + */ + std::vector expand(const std::vector &key); + + /** + * @brief Performs left rotation + * @param val The value to rotate + * @param shift The number of bits to rotate by + * @return The rotated value + */ + uint32_t rotl(uint32_t val, int shift); + + /** + * @brief Performs right rotation + * @param val The value to rotate + * @param shift The number of bits to rotate by + * @return The rotated value + */ + uint32_t rotr(uint32_t val, int shift); + + /** + * @brief Encrypts a single block of plaintext + * @param plaintext The plaintext block to encrypt + * @param ciphertext The resulting ciphertext block + */ + void encrypt_block(const uint32_t plaintext[2], uint32_t ciphertext[2]); + + /** + * @brief Decrypts a single block of ciphertext + * @param ciphertext The ciphertext block to decrypt + * @param plaintext The resulting plaintext block + */ + void decrypt_block(const uint32_t ciphertext[2], uint32_t plaintext[2]); +}; + +#endif diff --git a/include/nt/redpike.hpp b/include/nt/redpike.hpp index 25aded68b..5433414de 100644 --- a/include/nt/redpike.hpp +++ b/include/nt/redpike.hpp @@ -37,32 +37,66 @@ #include namespace gpmp { + +namespace nt { + /** - * Red Pike encryption algorithm. + * @class RedPike + * + * @brief Class for encryption and decryption using the RedPike algorithm */ class RedPike { public: - typedef uint32_t word; - constexpr word CONST = 0x9E3779B9; - constexpr int ROUNDS = 16; + /** + * @brief Encrypts the given data using the RedPike algorithm + * + * @param x Pointer to the data to be encrypted + * @param k Pointer to the key used for encryption + */ + void encrypt(uint32_t *x, const uint32_t *k); + + /** + * @brief Decrypts the given data using the RedPike algorithm + * + * @param x Pointer to the data to be decrypted + * @param k Pointer to the key used for decryption + */ + void decrypt(uint32_t *x, const uint32_t *k); + private: /** - * Left rotate operation. - * @param X Value to rotate. - * @param R Number of bits to rotate by. - * @return Rotated value. + * @brief Constant value used in the RedPike algorithm */ - word ROTL(word X, int R); + uint32_t CONST = 0x9E3779B9; /** - * Right rotate operation. - * @param X Value to rotate. - * @param R Number of bits to rotate by. - * @return Rotated value. + * @brief Number of rounds in the RedPike algorithm */ - word ROTR(word X, int R); + int ROUNDS = 16; + + /** + * @brief Performs left rotation on the given value + * + * @param X Value to be rotated + * @param R Number of bits to rotate left by + * + * @return Rotated value + */ + uint32_t rotl(uint32_t X, int R); + + /** + * @brief Performs right rotation on the given value + * + * @param X Value to be rotated + * @param R Number of bits to rotate right by + * + * @return Rotated value + */ + uint32_t rotr(uint32_t X, int R); }; +} // namespace nt + } // namespace gpmp #endif diff --git a/modules/nt/CMakeLists.txt b/modules/nt/CMakeLists.txt index ddf42caca..6230cbc31 100644 --- a/modules/nt/CMakeLists.txt +++ b/modules/nt/CMakeLists.txt @@ -9,8 +9,10 @@ set(SOURCE_FILES logarithms.cpp prime_gen.cpp prime_test.cpp + redpike.cpp rc4.cpp rc5.cpp + rc6.cpp random.cpp ) diff --git a/modules/nt/rc6.cpp b/modules/nt/rc6.cpp new file mode 100644 index 000000000..bd56d7bd3 --- /dev/null +++ b/modules/nt/rc6.cpp @@ -0,0 +1,152 @@ +/************************************************************************* + * + * Project + * _____ _____ __ __ _____ + * / ____| __ \| \/ | __ \ + * ___ _ __ ___ _ __ | | __| |__) | \ / | |__) | + * / _ \| '_ \ / _ \ '_ \| | |_ | ___/| |\/| | ___/ + *| (_) | |_) | __/ | | | |__| | | | | | | | + * \___/| .__/ \___|_| |_|\_____|_| |_| |_|_| + * | | + * |_| + * + * Copyright (C) Akiel Aries, , et al. + * + * This software is licensed as described in the file LICENSE, which + * you should have received as part of this distribution. The terms + * among other details are referenced in the official documentation + * seen here : https://akielaries.github.io/openGPMP/ along with + * important files seen in this project. + * + * You may opt to use, copy, modify, merge, publish, distribute + * and/or sell copies of the Software, and permit persons to whom + * the Software is furnished to do so, under the terms of the + * LICENSE file. As this is an Open Source effort, all implementations + * must be of the same methodology. + * + * + * + * This software is distributed on an AS IS basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. + * + ************************************************************************/ + +#include "../../include/nt/rc6.hpp" +#include +#include + +#include + +RC6::RC6(const std::vector &key) { + key_schedule(key); +} + +void RC6::key_schedule(const std::vector &key) { + std::vector L = expand(key); + S.resize(2 * (r + 1)); + const uint32_t P = 0xB7E15163; + const uint32_t Q = 0x9E3779B9; + S[0] = P; + for (int i = 1; i < 2 * (r + 1); ++i) { + S[i] = S[i - 1] + Q; + } + uint32_t A = 0, B = 0; + int i = 0, j = 0; + for (int k = 0; k < 3 * std::max(b, 2 * (r + 1)); ++k) { + A = S[i] = rotl((S[i] + A + B), 3); + B = L[j] = rotl((L[j] + A + B), (A + B)); + i = (i + 1) % (2 * (r + 1)); + j = (j + 1) % b; + } +} + +std::vector RC6::expand(const std::vector &key) { + std::vector L(b / 4); + for (size_t i = 0; i < key.size(); i++) { + L[i / 4] |= (static_cast(key[i]) << (8 * (i % 4))); + } + return L; +} + +uint32_t RC6::rotl(uint32_t val, int shift) { + return (val << shift) | (val >> (w - shift)); +} + +uint32_t RC6::rotr(uint32_t val, int shift) { + return (val >> shift) | (val << (w - shift)); +} + +void RC6::encrypt_block(const uint32_t plaintext[2], uint32_t ciphertext[2]) { + uint32_t A = plaintext[0], B = plaintext[1]; + A += S[0]; + B += S[1]; + for (int i = 1; i <= r; ++i) { + A = rotl(A ^ B, B) + S[2 * i]; + B = rotl(B ^ A, A) + S[2 * i + 1]; + } + ciphertext[0] = A; + ciphertext[1] = B; +} + +void RC6::decrypt_block(const uint32_t ciphertext[2], uint32_t plaintext[2]) { + uint32_t A = ciphertext[0], B = ciphertext[1]; + for (int i = r; i >= 1; --i) { + B = rotr(B - S[2 * i + 1], A) ^ A; + A = rotr(A - S[2 * i], B) ^ B; + } + B -= S[1]; + A -= S[0]; + plaintext[0] = A; + plaintext[1] = B; +} + +std::vector RC6::encrypt(const std::vector &plaintext) { + if (plaintext.size() % 8 != 0) { + throw std::invalid_argument( + "Plaintext length must be a multiple of 8 bytes"); + } + std::vector ciphertext; + ciphertext.reserve(plaintext.size()); + for (size_t i = 0; i < plaintext.size(); i += 8) { + uint32_t block[2]; + uint32_t encrypted_block[2]; + for (int j = 0; j < 8; ++j) { + block[j / 4] |= + (static_cast(plaintext[i + j]) << (8 * (j % 4))); + } + encrypt_block(block, encrypted_block); + for (int j = 0; j < 2; ++j) { + ciphertext.push_back((encrypted_block[j] >> 24) & 0xFF); + ciphertext.push_back((encrypted_block[j] >> 16) & 0xFF); + ciphertext.push_back((encrypted_block[j] >> 8) & 0xFF); + ciphertext.push_back(encrypted_block[j] & 0xFF); + } + } + return ciphertext; +} + +std::vector RC6::decrypt(const std::vector &ciphertext) { + if (ciphertext.size() % 8 != 0) { + throw std::invalid_argument( + "Ciphertext length must be a multiple of 8 bytes"); + } + std::vector plaintext; + plaintext.reserve(ciphertext.size()); + for (size_t i = 0; i < ciphertext.size(); i += 8) { + uint32_t block[2]; + uint32_t decrypted_block[2]; + for (int j = 0; j < 2; ++j) { + block[j] = + (static_cast(ciphertext[i + 4 * j]) << 24) | + (static_cast(ciphertext[i + 4 * j + 1]) << 16) | + (static_cast(ciphertext[i + 4 * j + 2]) << 8) | + static_cast(ciphertext[i + 4 * j + 3]); + } + decrypt_block(block, decrypted_block); + for (int j = 0; j < 8; ++j) { + plaintext.push_back((decrypted_block[j / 4] >> (8 * (j % 4))) & + 0xFF); + } + } + return plaintext; +} diff --git a/modules/nt/redpike.cpp b/modules/nt/redpike.cpp index 64ed86587..d87f74098 100644 --- a/modules/nt/redpike.cpp +++ b/modules/nt/redpike.cpp @@ -36,31 +36,29 @@ */ #include "../../include/nt/redpike.hpp" - #include -gpmp::RedPike::word gpmp::RedPike::ROTL(gpmp::RedPike::word X, int R) { - return (X << (R & 31)) | (X >> (32 - (R & 31))); +uint32_t gpmp::nt::RedPike::rotl(uint32_t X, int R) { + return ((X) << ((R)&31)) | ((X) >> (32 - ((R)&31))); } -gpmp::RedPike::word gpmp::RedPike::ROTR(gpmp::RedPike::word X, int R) { - return (X >> (R & 31)) | (X << (32 - (R & 31))); +uint32_t gpmp::nt::RedPike::rotr(uint32_t X, int R) { + return ((X) >> ((R)&31)) | ((X) << (32 - ((R)&31))); } -void gpmp::RedPike::encrypt(gpmp::RedPike::word *x, - const gpmp::RedPike::word *k) { - gpmp::RedPike::word rk0 = k[0]; - gpmp::RedPike::word rk1 = k[1]; +void gpmp::nt::RedPike::encrypt(uint32_t *x, const uint32_t *k) { + uint32_t rk0 = k[0]; + uint32_t rk1 = k[1]; - for (int i = 0; i < gpmp::RedPike::ROUNDS; i++) { - rk0 += gpmp::RedPike::CONST; - rk1 -= gpmp::RedPike::CONST; + for (int i = 0; i < ROUNDS; i++) { + rk0 += CONST; + rk1 -= CONST; x[0] ^= rk0; x[0] += x[1]; - x[0] = gpmp::RedPike::ROTL(x[0], x[1]); + x[0] = rotl(x[0], x[1]); - x[1] = gpmp::RedPike::ROTR(x[1], x[0]); + x[1] = rotr(x[1], x[0]); x[1] -= x[0]; x[1] ^= rk1; } @@ -70,21 +68,8 @@ void gpmp::RedPike::encrypt(gpmp::RedPike::word *x, x[1] = rk0; } -void gpmp::RedPike::decrypt(gpmp::RedPike::word *x, - const gpmp::RedPike::word *k) { - gpmp::RedPike::word dk[2] = { - k[1] - gpmp::RedPike::CONST * (gpmp::RedPike::ROUNDS + 1), - k[0] + gpmp::RedPike::CONST * (gpmp::RedPike::ROUNDS + 1)}; - - gpmp::RedPike::encrypt(x, dk); -} - -int main() { - // Example usage - word plaintext[2] = {0x12345678, 0x9ABCDEF0}; - word key[2] = {0xA0B1C2D3, 0xE4F50607}; - - encrypt(plaintext, key); +void gpmp::nt::RedPike::decrypt(uint32_t *x, const uint32_t *k) { + uint32_t dk[2] = {k[1] - CONST * (ROUNDS + 1), k[0] + CONST * (ROUNDS + 1)}; - return 0; + encrypt(x, dk); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ffcbc6363..a434baa9a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,11 +44,14 @@ set(CPP_SOURCES ../modules/ml/trainers.cpp ../modules/nt/cipher.cpp ../modules/nt/rc4.cpp + ../modules/nt/rc5.cpp + ../modules/nt/rc6.cpp ../modules/nt/prime_test.cpp ../modules/nt/prime_gen.cpp ../modules/nt/factorization.cpp ../modules/nt/logarithms.cpp ../modules/nt/random.cpp + ../modules/nt/redpike.cpp ../modules/optim/function.cpp ../modules/optim/quasi.cpp ../modules/stats/describe.cpp