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 : }