Created
October 21, 2024 07:34
-
-
Save eterekhin/2273f0039a2a6259b939e89aea97579a to your computer and use it in GitHub Desktop.
AES CBC and AES CTR decryption
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "include/cryptopp/aes.h" | |
#include "include/cryptopp/ccm.h" | |
#include "include/cryptopp/filters.h" | |
constexpr uint32_t size_of_aes_block = 16; | |
uint32_t get_rounds_number(const std::vector<CryptoPP::byte>& encoded_data) | |
{ | |
return static_cast<int>(std::ceil(static_cast<double>(encoded_data.size()) / size_of_aes_block)); | |
} | |
std::vector<CryptoPP::byte> xor (const CryptoPP::byte* encoded, const CryptoPP::byte* b, const int size) | |
{ | |
std::vector<CryptoPP::byte> result; | |
result.assign(size, 0); | |
for (int i = 0; i < size; i++) | |
{ | |
result[i] = encoded[i] ^ b[i]; | |
} | |
return result; | |
} | |
static std::string decrypt_cbc(const std::vector<CryptoPP::byte>& key, const std::vector<CryptoPP::byte>& encoded, | |
const std::vector<CryptoPP::byte>& iv) | |
{ | |
const uint32_t rounds_number = get_rounds_number(encoded); | |
const CryptoPP::AES::Decryption dec(key.data(), 16); | |
std::vector<CryptoPP::byte> decoded; | |
decoded.assign(encoded.size(), 0); | |
for (int round_index = 0; round_index < rounds_number; round_index++) | |
{ | |
const uint32_t previous_block_offset = (round_index - 1) * size_of_aes_block; | |
const uint32_t current_block_offset = previous_block_offset + size_of_aes_block; | |
CryptoPP::byte* current_out_block = decoded.data() + current_block_offset; | |
dec.ProcessBlock(encoded.data() + current_block_offset, current_out_block); | |
const CryptoPP::byte* xor_with = round_index == 0 | |
? const_cast<CryptoPP::byte*>(iv.data()) | |
: (encoded.data() + previous_block_offset); | |
std::vector<CryptoPP::byte> xored_block = xor (current_out_block, xor_with, size_of_aes_block); | |
std::memcpy(current_out_block, xored_block.data(), size_of_aes_block); | |
} | |
const uint8_t padding = decoded[decoded.size() - 1]; | |
const size_t length_of_string = decoded.size() - padding; | |
const char* c = reinterpret_cast<char*>(decoded.data()); | |
const std::string result = std::string(c, length_of_string); | |
return result; | |
} | |
constexpr int output_size = 16 * 3; | |
void increment(std::vector<CryptoPP::byte>& value) | |
{ | |
for (size_t i = value.size() - 1;; i--) | |
{ | |
if (const CryptoPP::byte current = value[i]; current < 0xFF) | |
{ | |
value[i]++; | |
return; | |
} | |
if (i == 0) | |
break; | |
} | |
// overflow | |
value.assign(value.size(), 0); | |
} | |
std::string decrypt_ctr(const CryptoPP::byte* key, const std::vector<CryptoPP::byte>& encoded, std::vector<CryptoPP::byte> iv) | |
{ | |
const CryptoPP::AESEncryption enc(key, 16); | |
const uint32_t rounds_number = get_rounds_number(encoded); | |
std::vector<CryptoPP::byte> decoded; | |
decoded.assign(rounds_number * size_of_aes_block, 0); | |
const CryptoPP::byte* start = decoded.data(); | |
for (int round = 0; round < rounds_number; round++) | |
{ | |
const int offset = 16 * round; | |
enc.ProcessBlock(iv.data(), decoded.data() + offset); | |
std::vector<CryptoPP::byte> xor_result = xor (encoded.data() + offset, decoded.data() + offset, size_of_aes_block); | |
std::memcpy(decoded.data() + offset, xor_result.data(), size_of_aes_block); | |
increment(iv); | |
} | |
const char* c = reinterpret_cast<char*>(decoded.data()); | |
std::string s = std::string(c, encoded.size()); | |
return s; | |
} | |
std::vector<CryptoPP::byte> parse_from_string(const std::string& str) | |
{ | |
std::vector<CryptoPP::byte> result; | |
result.reserve(str.size() / 2); | |
for (size_t i = 0; i < str.size(); i += 2) { | |
std::stringstream ss; | |
ss << "0x" << str[i] << str[i + 1]; | |
std::string s = ss.str(); | |
const unsigned long value = std::strtoul(s.data(), nullptr, 16); | |
result.push_back(static_cast<CryptoPP::byte>(value)); | |
} | |
return result; | |
} | |
struct parsed | |
{ | |
std::vector<CryptoPP::byte> key; | |
std::vector<CryptoPP::byte> iv; | |
std::vector<CryptoPP::byte> encrypted; | |
}; | |
parsed parse(const std::string& key, const std::string& encrypted_data) | |
{ | |
const std::string iv_string = encrypted_data.substr(0, 32); | |
const std::string encrypted_message = encrypted_data.substr(32); | |
const std::vector<CryptoPP::byte> key_bytes = parse_from_string(key); | |
const std::vector<CryptoPP::byte> iv_bytes = parse_from_string(iv_string); | |
const std::vector<CryptoPP::byte> data_bytes = parse_from_string(encrypted_message); | |
return { key_bytes, iv_bytes, data_bytes}; | |
} | |
int main() { | |
std::string key = "SOME_KEY"; | |
// should look like "iv encrypted" | |
const std::string iv_with_encrypted_message = "ENCRYPTED"; | |
const auto parsed = parse(key, iv_with_encrypted_message); | |
const auto decrypted1 = decrypt_cbc(parsed.key, parsed.encrypted, parsed.iv); | |
std::cout << decrypted1 << '\n'; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment