Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lezahlie committed Dec 16, 2022
0 parents commit f378273
Show file tree
Hide file tree
Showing 6 changed files with 361 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.bin
*.o
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CC=gcc
CFLAGS=-Wall -g

hill_keys: hillcipher_main.c hillcipher_keypair.c hillcipher_keypair.h
$(CC) $(CFLAGS) hillcipher_main.c hillcipher_keypair.c -o hill_keys
clean:
rm -f *.o *.bin hill_keys
43 changes: 43 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
```
Author: Leslie Horace
Purpose: Dynamically finding hill cipher encryption/decryption key pairs
Version: 1.0
```
# Hill Cipher KeyPair Generator

## Included files
- hillcipher_main.c
- Functions for creating encyrption key and computing decyrption key
- hillcipher_main.h
- Header file to use functions from "hillcipher_main.c"
- hillcipher_main.c
- simple main to demonstrate hill cipher key pair generation
- Makefile
- compiling program and cleaning out files

## Compiling the program
> make
> gcc ./hillcipher_main.c ./hillcipher_keypair.c -o < outfile>
## Cleaning compiled files
> make clean
## Running the program
usage: < outfile> <enc_key filename> <dec_key filename>
*output files are written in binary, use (.bin) extension*

## About the program
1. Creates a random square key matrix of order n, where n is in range [2, 9]
+ The matrix is filled with random codes [0,26] for language [A-Z]
+ Keeping the order small for demoing purposes
2. Computes the modular inverse by performing elementary row operations
+ Row Multiplication
+ Row swap
+ Row addition
3. All compuations are reduced (mod 26) for language [A-Z]
+ [MODULUS] macro in "hillcipher_key.c" can be modified as needed
4. Generates new encryption keys untill finding one that is invertable
5. Upon finding valid keypair, each key is written to the filename arguments
6. The keys can be read back in for use and/or display to the console

206 changes: 206 additions & 0 deletions hillcipher_keypair.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
Author: Leslie Horace
File: hillcipher_keypair.h
Purpose: c program to generate random hill cipher encryption/decryption key pair
*/

#include <stdlib.h> // c standard library
#include <stdio.h> // writing and reading files
#include <string.h> // i/o file names
#include "hillcipher_keypair.h"
#define MODULUS 26 // hill cipher is invertable mod 26 for lanaguge [A-Z]

// allocates 1dim space for any m*n matrix
int *malloc1D(int m, int n) {
int *X = (int*)malloc(m*n*sizeof(int));
for(int i = 0; i < m*n; i++)
X[i] = 0; // initialize each index
return X; // return pointer to matrix
}

// reads hill cipher key from a file into a n*n matrix
int readKey(char * oFile, int **M, int *n){
FILE * fp = NULL;
// check if file is open for reading
if ((fp = fopen(oFile, "rb")) != NULL) {
fread(&(*n), sizeof(int), 1, fp); // read matrix order
*M = malloc1D((*n), (*n));
fread(M[0], sizeof(int), (*n)*(*n), fp); // read matrix contents
fclose(fp);
}else{ // here if file read error occured
perror("File read error...");
return 1;
}
return 0;
}

// writes hill cipher key from a n*n matrix to a file
int writeKey(char * oFile, int *M, int n){
FILE * fp = NULL;
// check if file is open for writing
if ((fp = fopen(oFile, "wb")) != NULL){
fwrite(&n, sizeof(int), 1, fp); // write matrix order
fwrite(M, sizeof(int), n*n, fp); // write matrix contents
fclose(fp);
}else{ // here if file write error occured
perror("File write error...");
return 1;
}
return 0;
}

// prints any n*m matrix
void printMatrix(int *X, int m, int n){
printf("\n");
for(int i =0; i < m; i ++){
for(int j = 0; j < n; j ++){
printf("%d\t", X[i*n+j]);
}printf("\n");
}
printf("\n");
}

// performs the extended euclidian algorithm
int extEuclid(int a, int b, int *x, int *y){
int d = 0;
if(a == 0){ // error case: a,b are not relatively prime
*x=a;
*y=a+1;
d = b;
}else{ // recursive case: a,b are relatively prime
int x_tmp = 0, y_tmp = 0;
// backwards substitution to find inverses s.t. ax+by=1
d = extEuclid(b%a, a, &x_tmp, &y_tmp);
*x = y_tmp - (x_tmp * (b/a));
*y = x_tmp;
}
return d; // return the GCD
}

// calculates and returns the positive remainder of mod 26
int positiveMod(int a) {
int r = a % MODULUS;
if (r < 0){
r += MODULUS;
}
return r;
}

// initializes K = key matrix and A = augmented matrix [K | I], where I = identity
void initKeys(int * K, int * A, int n, int m){
for(int i =0; i < n; i ++){
for(int j =0; j < n; j++){
K[i*n+j] = A[i*m+j] = rand() % 26;
// set RIGHT half of A[K | I] as identity matrix
if(i==j){
A[i*m+(j+n)] = 1; // diagonal 1
}else{
A[i*m+(j+n)] = 0; // all else 0
}
}
}
}

// row operation: swaps the pivots row with the target row
void swapRow(int *A, int target, int pivot,int m){
int x=0;
for(int j=0; j < m; j++){
x = A[pivot*m+j]; // temp = A[pivot][j]
A[pivot*m+j] = A[target*m+j]; // A[pivot][j] = A[target][j]
A[target*m+j] = x; // A[target][j] = temp
}
}

// row operation: scale the row by multiplying with the pivots modular inverse
int scaleRow(int *A, int pivot, int n, int m){
int x = 0, y = 0;
// loops starts with the pivot's row
for (int i=pivot; i < n; i++){
// check if current index A[i][pivot] is invertable (mod 26)
if(extEuclid(A[i*m+pivot], MODULUS, &x, &y) == 1){
// if current row is not the pivot row, then swap rows
if(i != pivot){
swapRow(A, i, pivot, m);
}
// multiple the row by the pivot's inverse
for(int j =0; j < m; j++){
A[pivot*m+j] *= x; // A[pivot][j] = A[pivot][pivot]^-1 * A[pivot][j]
A[pivot*m+j] = positiveMod(A[pivot*m+j]); // reduce by (mod 26)
}
return 1; // return 1(true) = is invertable mod 26
}
}
return 0; // return 0 (false) = not invertable mod 26
}

// row operation: subtract each row index by a multiple of pivots row index
void subtractRow(int *A, int pivot, int n, int m){
int x = 0;
for (int i=0; i < n; i++){
// check if the current row is not the pivot row
if(i != pivot){
x = A[i*m+pivot]; // x = A[i][pivot]
for(int j=0; j < m; j++){
A[i*m+j] -= (x * A[pivot*m+j]); // A[i][j] = A[i][j] - (A[i][pivot] * A[pivot][j])
A[i*m+j] = positiveMod(A[i*m+j]); // reduce by (mod 26)
}
}
}
}

// creates a random key and computes it inverse, continues until invertable key pair is found
void findInvertableKey(int * K, int * A, int n, int m){
int valid = 0;
do{
initKeys(K, A, n, m); // intilize a new key matrix and corresponding augmented matrix
for(int i=0; i < n; i++){
// check if scaleRow function returns 1(true) for success
if(scaleRow(A, i, n, m) == 1){
// perform row subtraction to tranform A[K | I] => A[I | K^-1]
subtractRow(A, i, n, m);
valid = 1;
} else{ // here if the key is not invertable, stop inner loop
valid = 0;
break;
}
}
}while(valid == 0); // loops until invertable key is found
}

// set new matrix X = K^-1 (from right half of transformed A[I|K^-1]) for writing
void getInverseKey(int * X, int * A, int n, int m){
for(int i =0; i < n; i++){
for(int j =0; j < n; j++){
X[i*n+j] = A[i*m+(j+n)]; // X[i][j] = I[i][j] in A[K|I]
}
}
}

// primary function for creating a new hill cipher key pair
int createKeyPair(char * ekey_fname, char * dkey_fname){

int *K, *A; // K = key matrix pointer, A = augmented matrix pointer
int n = (rand() % 8) + 2, m = 2*n; // n = random [2-9] matrix order, m = 2*n for augmented matrix traversals

// allocate space for key and augmented matrices
K = malloc1D(n, n);
A = malloc1D(n, m);

// find a invertable key pair
findInvertableKey(K, A, n, m);

// write the encyrption key to specfied filename
printf("\nWriting encryption key to file '%s'...\n", ekey_fname);
int res = writeKey(ekey_fname, K, n);
if(res == 0){ // if encyrption key was successfully written, get the inversekey
getInverseKey(K, A, n, m);
// write the decryption key to specfied filename
printf("\nWriting decryption key to file '%s'...\n", dkey_fname);
res = writeKey(dkey_fname, K, n);
}

// deallocate space for matrices
free(A);
free(K);
return res; // return result for writing keys to files
}
53 changes: 53 additions & 0 deletions hillcipher_keypair.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Author: Leslie Horace
File: hillcipher_keypair.h
Purpose: header file to call functions necessary for creating and utilizing encyrption/decryption key pairs
*/

#ifndef HILLCIPHER_KEYPAIR_
#define HILLCIPHER_KEYPAIR_

/*
allocates space for a 1d array of n*m size
returns a (int *) pointer to the array
*/
int *malloc1D(int m, int n);

/*
reads a binary file key into a matrix
params: input filename.bin, M = pointer to matrix, n = matrix order
returns 1 (error) or 0 (success)
*/
int readKey(char * oFile, int **M, int *n);


/*
prints a m*n matrix to the console
params: matrix pointer X, m = row size, n = col size
*/
void printMatrix(int *X, int m, int n);

/*
calculates GCD(a,b) = d, where ax + by = d
params: a = integer, b = modulus, x = a inverse, and y = b inverse
returns d, inverse x and y are returned as arguments
*/
int extEuclid(int a, int b, int *x, int *y);

/*
computes positive remainder = a (mod 26)
returns the remainder
*/
int postiveMod(int a);

/*
generates a random matrix order n from [2,9]
creates random n*n encyrption and decyrption key matrices
writes out both keys to their specified file names
params: encryption key file name, decyrption key file name
returns 1 (error) or 0 (success)
*/
int createKeyPair(char * ekey_fname, char * dkey_fname);


#endif /* MATRIX_KEY_ */
50 changes: 50 additions & 0 deletions hillcipher_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Author: Leslie Horace
File: hillcipher_main.c
Purpose: c program to demonstrate functions provided by hillcipher_keypair.h
*/

#include <stdlib.h> // c standard library
#include <stdio.h> // writing and reading files
#include <string.h> // i/o file names
#include <time.h> // for seeding randomness
#include "hillcipher_keypair.h"


/* main entry point for generating hill cipher encryption/decryption keys */
int main(int argc, char **argv){

if(argc != 3){
printf("usage: %s <enc key filename> <dec key filename>\n", (char*)argv[0]);
exit(EXIT_FAILURE);
}
char * ekey_fn = argv[1];
char * dkey_fn = argv[2];

srand(time(NULL)); // time seed for randomness

printf("\nGenerating encryption/decryption key pairs...\n");
if(createKeyPair(ekey_fn, dkey_fn) == 1){
exit(EXIT_FAILURE);
}

int * ekey, * dkey, n; // key matrices and matrix order

printf("\nReading key files '%s' and '%s'...\n", ekey_fn, dkey_fn);

if(readKey(ekey_fn, &ekey, &n) != 0){
exit(EXIT_FAILURE);
}
printf("\nEncryption Key ['%s']:\n", ekey_fn);
printMatrix(ekey, n, n);
free(ekey);

if(readKey(dkey_fn, &dkey, &n) != 0){
exit(EXIT_FAILURE);
}
printf("\nDecryption Key ['%s']:\n", dkey_fn);
printMatrix(dkey, n, n);
free(dkey);

exit(EXIT_SUCCESS);
}

0 comments on commit f378273

Please sign in to comment.