Skip to content

Instantly share code, notes, and snippets.

@eterekhin
Created October 21, 2024 07:34
Show Gist options
  • Save eterekhin/2273f0039a2a6259b939e89aea97579a to your computer and use it in GitHub Desktop.
Save eterekhin/2273f0039a2a6259b939e89aea97579a to your computer and use it in GitHub Desktop.
AES CBC and AES CTR decryption
#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