Blog | G5 Cyber Security

C++ Block Cipher Guide

TL;DR

This guide shows you how to implement a basic block cipher in C++. We’ll focus on the core concepts and provide code examples for encryption and decryption. It’s not production-ready (security is complex!), but it will help you understand how these ciphers work.

1. Understanding Block Ciphers

Block ciphers encrypt data in fixed-size blocks (e.g., 64 bits, 128 bits). Here’s a simplified overview:

A basic block cipher involves these steps:

  1. Initialisation Vector (IV): Often used with chaining modes to make each encryption unique, even with the same key.
  2. Round Function: The core of the cipher – a series of operations that mix and transform the data.
  3. Key Schedule: Generates subkeys from the main key for use in each round.

2. Simple Example Cipher (Not Secure!)

We’ll create a very basic cipher for demonstration purposes. Do not use this in any real-world application! It’s vulnerable to many attacks.

2.1 Encryption Function

#include <iostream>
#include <string>

std::string encrypt(const std::string& plaintext, const std::string& key) {
  std::string ciphertext = "";
  for (size_t i = 0; i < plaintext.length(); ++i) {
    ciphertext += char((plaintext[i] + key[i % key.length()]) % 256);
  }
  return ciphertext;
}

This code simply adds the ASCII value of each character in the plaintext to the corresponding character in the key (modulo 256). The modulo operation ensures that the result stays within the valid range for a char.

2.2 Decryption Function

std::string decrypt(const std::string& ciphertext, const std::string& key) {
  std::string plaintext = "";
  for (size_t i = 0; i < ciphertext.length(); ++i) {
    plaintext += char((ciphertext[i] - key[i % key.length()] + 256) % 256);
  }
  return plaintext;
}

The decryption function subtracts the key from the ciphertext (again, modulo 256). Adding 256 before the modulo operation handles potential negative values.

2.3 Example Usage

int main() {
  std::string message = "Hello, world!";
  std::string key = "secretkey";

  std::string encryptedMessage = encrypt(message, key);
  std::cout << "Encrypted: " << encryptedMessage << std::endl;

  std::string decryptedMessage = decrypt(encryptedMessage, key);
  std::cout << "Decrypted: " << decryptedMessage << std::endl;

  return 0;
}

3. Improving the Cipher (Still Not Secure!)

The previous example is extremely weak. Here are some ways to improve it, though still not enough for real-world use:

3.1 Example Round Function

// Very simplified round function - DO NOT USE IN PRODUCTION!
unsigned char round(unsigned char input, unsigned char subkey) {
  return (input ^ subkey) * 2 + 1;
}

4. Key Schedule

The key schedule generates a series of subkeys from the main key for each round of encryption.

4.1 Simple Key Schedule Example

std::vector<unsigned char> generateSubkeys(const std::string& key, int numRounds) {
  std::vector<unsigned char> subkeys;
  for (int i = 0; i < numRounds; ++i) {
    subkeys.push_back(key[i % key.length()]);
  }
  return subkeys;
}

5. Chaining Modes

Chaining modes help to encrypt data more securely by making each block dependent on the previous one.

6. Important Considerations for cyber security

Exit mobile version