LCOV - code coverage report
Current view: top level - modules/nt - rc6.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 84 0.0 %
Date: 2024-05-13 05:06:06 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*************************************************************************
       2             :  *
       3             :  *  Project
       4             :  *                         _____ _____  __  __ _____
       5             :  *                        / ____|  __ \|  \/  |  __ \
       6             :  *  ___  _ __   ___ _ __ | |  __| |__) | \  / | |__) |
       7             :  * / _ \| '_ \ / _ \ '_ \| | |_ |  ___/| |\/| |  ___/
       8             :  *| (_) | |_) |  __/ | | | |__| | |    | |  | | |
       9             :  * \___/| .__/ \___|_| |_|\_____|_|    |_|  |_|_|
      10             :  *      | |
      11             :  *      |_|
      12             :  *
      13             :  * Copyright (C) Akiel Aries, <akiel@akiel.org>, et al.
      14             :  *
      15             :  * This software is licensed as described in the file LICENSE, which
      16             :  * you should have received as part of this distribution. The terms
      17             :  * among other details are referenced in the official documentation
      18             :  * seen here : https://akielaries.github.io/openGPMP/ along with
      19             :  * important files seen in this project.
      20             :  *
      21             :  * You may opt to use, copy, modify, merge, publish, distribute
      22             :  * and/or sell copies of the Software, and permit persons to whom
      23             :  * the Software is furnished to do so, under the terms of the
      24             :  * LICENSE file.
      25             :  *
      26             :  *
      27             :  *
      28             :  * This software is distributed on an AS IS basis, WITHOUT
      29             :  * WARRANTY OF ANY KIND, either express or implied.
      30             :  *
      31             :  ************************************************************************/
      32             : #include <cmath>
      33             : #include <cstdint>
      34             : #include <openGPMP/nt/rc6.hpp>
      35             : #include <stdexcept>
      36             : 
      37           0 : RC6::RC6(const std::vector<uint8_t> &key) {
      38           0 :     key_schedule(key);
      39           0 : }
      40             : 
      41           0 : void RC6::key_schedule(const std::vector<uint8_t> &key) {
      42           0 :     std::vector<uint32_t> L = expand(key);
      43           0 :     S.resize(2 * (r + 1));
      44           0 :     const uint32_t P = 0xB7E15163;
      45           0 :     const uint32_t Q = 0x9E3779B9;
      46           0 :     S[0] = P;
      47           0 :     for (int i = 1; i < 2 * (r + 1); ++i) {
      48           0 :         S[i] = S[i - 1] + Q;
      49             :     }
      50           0 :     uint32_t A = 0, B = 0;
      51           0 :     int i = 0, j = 0;
      52           0 :     for (int k = 0; k < 3 * std::max(b, 2 * (r + 1)); ++k) {
      53           0 :         A = S[i] = rotl((S[i] + A + B), 3);
      54           0 :         B = L[j] = rotl((L[j] + A + B), (A + B));
      55           0 :         i = (i + 1) % (2 * (r + 1));
      56           0 :         j = (j + 1) % b;
      57             :     }
      58           0 : }
      59             : 
      60           0 : std::vector<uint32_t> RC6::expand(const std::vector<uint8_t> &key) {
      61           0 :     std::vector<uint32_t> L(b / 4);
      62           0 :     for (size_t i = 0; i < key.size(); i++) {
      63           0 :         L[i / 4] |= (static_cast<uint32_t>(key[i]) << (8 * (i % 4)));
      64             :     }
      65           0 :     return L;
      66             : }
      67             : 
      68           0 : uint32_t RC6::rotl(uint32_t val, int shift) {
      69           0 :     return (val << shift) | (val >> (w - shift));
      70             : }
      71             : 
      72           0 : uint32_t RC6::rotr(uint32_t val, int shift) {
      73           0 :     return (val >> shift) | (val << (w - shift));
      74             : }
      75             : 
      76           0 : void RC6::encrypt_block(const uint32_t plaintext[2], uint32_t ciphertext[2]) {
      77           0 :     uint32_t A = plaintext[0], B = plaintext[1];
      78           0 :     A += S[0];
      79           0 :     B += S[1];
      80           0 :     for (int i = 1; i <= r; ++i) {
      81           0 :         A = rotl(A ^ B, B) + S[2 * i];
      82           0 :         B = rotl(B ^ A, A) + S[2 * i + 1];
      83             :     }
      84           0 :     ciphertext[0] = A;
      85           0 :     ciphertext[1] = B;
      86           0 : }
      87             : 
      88           0 : void RC6::decrypt_block(const uint32_t ciphertext[2], uint32_t plaintext[2]) {
      89           0 :     uint32_t A = ciphertext[0], B = ciphertext[1];
      90           0 :     for (int i = r; i >= 1; --i) {
      91           0 :         B = rotr(B - S[2 * i + 1], A) ^ A;
      92           0 :         A = rotr(A - S[2 * i], B) ^ B;
      93             :     }
      94           0 :     B -= S[1];
      95           0 :     A -= S[0];
      96           0 :     plaintext[0] = A;
      97           0 :     plaintext[1] = B;
      98           0 : }
      99             : 
     100           0 : std::vector<uint8_t> RC6::encrypt(const std::vector<uint8_t> &plaintext) {
     101           0 :     if (plaintext.size() % 8 != 0) {
     102           0 :         throw std::invalid_argument(
     103           0 :             "Plaintext length must be a multiple of 8 bytes");
     104             :     }
     105           0 :     std::vector<uint8_t> ciphertext;
     106           0 :     ciphertext.reserve(plaintext.size());
     107           0 :     for (size_t i = 0; i < plaintext.size(); i += 8) {
     108             :         uint32_t block[2];
     109             :         uint32_t encrypted_block[2];
     110           0 :         for (int j = 0; j < 8; ++j) {
     111           0 :             block[j / 4] |=
     112           0 :                 (static_cast<uint32_t>(plaintext[i + j]) << (8 * (j % 4)));
     113             :         }
     114           0 :         encrypt_block(block, encrypted_block);
     115           0 :         for (int j = 0; j < 2; ++j) {
     116           0 :             ciphertext.push_back((encrypted_block[j] >> 24) & 0xFF);
     117           0 :             ciphertext.push_back((encrypted_block[j] >> 16) & 0xFF);
     118           0 :             ciphertext.push_back((encrypted_block[j] >> 8) & 0xFF);
     119           0 :             ciphertext.push_back(encrypted_block[j] & 0xFF);
     120             :         }
     121             :     }
     122           0 :     return ciphertext;
     123           0 : }
     124             : 
     125           0 : std::vector<uint8_t> RC6::decrypt(const std::vector<uint8_t> &ciphertext) {
     126           0 :     if (ciphertext.size() % 8 != 0) {
     127           0 :         throw std::invalid_argument(
     128           0 :             "Ciphertext length must be a multiple of 8 bytes");
     129             :     }
     130           0 :     std::vector<uint8_t> plaintext;
     131           0 :     plaintext.reserve(ciphertext.size());
     132           0 :     for (size_t i = 0; i < ciphertext.size(); i += 8) {
     133             :         uint32_t block[2];
     134             :         uint32_t decrypted_block[2];
     135           0 :         for (int j = 0; j < 2; ++j) {
     136           0 :             block[j] =
     137           0 :                 (static_cast<uint32_t>(ciphertext[i + 4 * j]) << 24) |
     138           0 :                 (static_cast<uint32_t>(ciphertext[i + 4 * j + 1]) << 16) |
     139           0 :                 (static_cast<uint32_t>(ciphertext[i + 4 * j + 2]) << 8) |
     140           0 :                 static_cast<uint32_t>(ciphertext[i + 4 * j + 3]);
     141             :         }
     142           0 :         decrypt_block(block, decrypted_block);
     143           0 :         for (int j = 0; j < 8; ++j) {
     144           0 :             plaintext.push_back((decrypted_block[j / 4] >> (8 * (j % 4))) &
     145             :                                 0xFF);
     146             :         }
     147             :     }
     148           0 :     return plaintext;
     149           0 : }

Generated by: LCOV version 1.14