hill_cipher.cpp File Reference

Implementation of Hill cipher algorithm. More...

`#include <cassert>`
`#include <cmath>`
`#include <cstring>`
`#include <ctime>`
`#include <fstream>`
`#include <iomanip>`
`#include <iostream>`
`#include <string>`
`#include "../numerical_methods/lu_decomposition.h"`
Include dependency graph for hill_cipher.cpp:

## Classes

class | ciphers::HillCipher
| Implementation of Hill Cipher algorithm. More...

## Namespaces

| ciphers
| Algorithms for encryption and decryption.

## Functions

template<typename T >
static std::ostream & | operator<< (std::ostream &out, matrix< T > const &v)
void | test1 (const std::string &text)
| Self test 1 - using 3x3 randomly generated key. More...
void | test2 (const std::string &text)
| Self test 2 - using 8x8 randomly generated key. More...
int | main ()

## Variables

static const char * | ciphers::STRKEY

## Detailed Description

Implementation of Hill cipher algorithm.

Program to generate the encryption-decryption key and perform encryption and decryption of ASCII text using the famous block cipher algorithm. This is a powerful encryption algorithm that is relatively easy to implement with a given key. The strength of the algorithm depends on the size of the block encryption matrix key; the bigger the matrix, the stronger the encryption and more difficult to break it. However, the important requirement for the matrix is that:

1. matrix should be invertible - all inversion conditions should be satisfied and
2. its determinant must not have any common factors with the length of character set Due to this restriction, most implementations only implement with small 3x3 encryption keys and a small subset of ASCII alphabets.

In the current implementation, I present to you an implementation for generating larger encryption keys (I have attempted upto 10x10) and an ASCII character set of 97 printable characters. Hence, a typical ASCII text file could be easily encrypted with the module. The larger character set increases the modulo of cipher and hence the matrix determinants can get very large very quickly rendering them ill-defined.

Note
  This program uses determinant computation using LU decomposition from the file lu_decomposition.h
  The matrix generation algorithm is very rudimentary and does not guarantee an invertible modulus matrix.

Todo:
  Better matrix generation algorithm.

Author
  Krishna Vedala

## Function Documentation

## main()

int main | ( | void |  | ) |

Main function

{
std::srand(std::time(nullptr));
std::cout << "Key dictionary: (" << std::strlen(ciphers::STRKEY) << ")\n\t"
<< ciphers::STRKEY << "\n";
std::string text = "This is a simple text with numb3r5 and exclamat!0n.";
test1(text);
test2(text);
return 0;
}
std::cout
std::string
test2
void test2(const std::string &text)
Self test 2 - using 8x8 randomly generated key.
Definition: hill_cipher.cpp:505
test1
void test1(const std::string &text)
Self test 1 - using 3x3 randomly generated key.
Definition: hill_cipher.cpp:470
ciphers::STRKEY
static const char * STRKEY
Definition: hill_cipher.cpp:73
std::srand
T srand(T... args)
std::strlen
T strlen(T... args)
std::time
T time(T... args)
Here is the call graph for this function:

## operator<<()

template<typename T >

static std::ostream& operator<< | ( | std::ostream & | out,
|  | matrix< T > const & | v
| ) |  |

static

operator to print a matrix

{
const int width = 15;
const char separator = ' ';
for (size_t row = 0; row < v.size(); row++) {
for (size_t col = 0; col < v[row].size(); col++)
out << std::left << std::setw(width) << std::setfill(separator)
<< v[row][col];
out << std::endl;
}
return out;
}
std::endl
T endl(T... args)
std::left
T left(T... args)
std::setfill
T setfill(T... args)
std::setw
T setw(T... args)
std::vector::size
T size(T... args)
Here is the call graph for this function:

## test1()

void test1 | ( | const std::string & | text | ) |

Self test 1 - using 3x3 randomly generated key.

Parameters

  text | string to encrypt and decrypt

{
// std::string text = "Hello world!";
std::cout << "======Test 1 (3x3 key) ======\nOriginal text:\n\t" << text
<< std::endl;
std::pair<matrix<int>, matrix<int>> p =
ciphers::HillCipher::generate_keys(3, 0, 100);
matrix<int> ekey = p.first;
matrix<int> dkey = p.second;
// matrix<int> ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}};
// std::cout << "Encryption key: \n" << ekey;
std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
std::cout << "Encrypted text:\n\t" << gibberish << std::endl;
// matrix<int> dkey = ciphers::HillCipher::generate_decryption_key(ekey);
// std::cout << "Decryption key: \n" << dkey;
std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;
std::ofstream out_file("hill_cipher_test1.txt");
out_file << "Block size: " << ekey.size() << "\n";
out_file << "Encryption Key:\n" << ekey;
out_file << "\nDecryption Key:\n" << dkey;
out_file.close();
assert(txt_back == text);
std::cout << "Passed :)\n";
}
std::ofstream
ciphers::HillCipher::generate_keys
static std::pair< matrix< int >, matrix< int > > generate_keys(size_t size, int limit1=0, int limit2=10)
Generate encryption and decryption key pair.
Definition: hill_cipher.cpp:424
ciphers::HillCipher::decrypt_text
static const std::string decrypt_text(const std::string &text, const matrix< int > &decrypt_key)
Decrypt a given text using a given key.
Definition: hill_cipher.cpp:457
ciphers::HillCipher::encrypt_text
static const std::string encrypt_text(const std::string &text, const matrix< int > &encrypt_key)
Encrypt a given text using a given key.
Definition: hill_cipher.cpp:445
std::pair
std::vector
Here is the call graph for this function:

## test2()

void test2 | ( | const std::string & | text | ) |

Self test 2 - using 8x8 randomly generated key.

Parameters

  text | string to encrypt and decrypt

{
// std::string text = "Hello world!";
std::cout << "======Test 2 (8x8 key) ======\nOriginal text:\n\t" << text
<< std::endl;
std::pair<matrix<int>, matrix<int>> p =
ciphers::HillCipher::generate_keys(8, 0, 3);
matrix<int> ekey = p.first;
matrix<int> dkey = p.second;
std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
std::cout << "Encrypted text:\n\t" << gibberish << std::endl;
std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;
std::ofstream out_file("hill_cipher_test2.txt");
out_file << "Block size: " << ekey.size() << "\n";
out_file << "Encryption Key:\n" << ekey;
out_file << "\nDecryption Key:\n" << dkey;
out_file.close();
assert(txt_back.compare(0, text.size(), text) == 0);
std::cout << "Passed :)\n";
}
std::string::compare
T compare(T... args)
Here is the call graph for this function: