Place Holder Projects Code
Bash MySQL JavaScript MySQL Quick Reference
Notes Documents Return of the Fed Login

Code

*More fully fledged applications can be found on the Projects page. The Bash page is dedicated to fully commented oneliners, and a MySQL quick reference is available here.



/* rsa.cpp
 *	- Will Bergen - 2019
 *	- Toy implementation of RSA pubkey algorithm
 *	- Uses hardcoded, small primes for test purposes
 *	- compile with: g++ rsa.cpp -std=c++11 -g
 * 
 */

#include <stdlib.h>
#include <stdio.h>
#include <cstdint>
#include <string.h>

using namespace std;

/*	RSA Algo:
 *		Key Generation
 *			- Find 2 primes, p and q
 *				- p and q should be similar, 
 *			- Compute n = p*q
 *			- Compute C(n) where C is Carmichael Function
 *				- C(n) = lcm(p-1,q-1) where lcm is Least Common Multiple
 *				- I don't understand the theory here...
 *			- Choose e s.t. 1 < e < C(n) AND gcd(e,C(n)) == 1
 *				- ie. Choose e s.t. e and C(n) are coprime
 *			- Compute d = e^-1 mod C(n)
 *				- ie. Compute d, the multiplicative inverse of e mod C(n)
 *			- e is pub key
 *			- d is priv key
 *
 * 		Encryption
 * 			- Plain text represented as integer p (ignoring padding)
 * 			- Cipher text c = p^e (mod n) where e is the other's public key
 *
 * 		Decryption
 * 			- Cipher text represented as integer c
 * 			- Plain text p = c^d (mod n) where d is your private key
 *
 */

uint64_t C(uint64_t n); 								// Carmichael
uint64_t gcd(uint64_t i, uint64_t j);					// Greatest Common Divisor
uint64_t my_pow(uint64_t x, uint64_t y, uint64_t m);	// Power Mod
uint64_t modInverse(uint64_t x, uint64_t m);			// Multiplicative Inverse
void encrypt(char *input, int msg_length, uint64_t e, uint64_t n, uint64_t *output);
void decrypt(uint64_t *input, int msg_length, uint64_t d, uint64_t n, char *output);




int main(int argc, char **argv)
{
	printf("RSA Running!\n");
	
	// Hardcoded test:
	uint64_t p = 371;
	uint64_t q = 377;
	uint64_t n = p * q;
	printf("Using: [p: %lu, q: %lu, n: %lu]\n", p, q, n);
	printf("Finding C(n)... ");

	uint64_t c = C(p * q); // Carmichael's Function
	printf("%lu!\n",c); 
	
	 
	//	- Choose e s.t. 1 < e < C(n) AND gcd(e,C(n)) == 1
 	//	- ie. Choose e s.t. e and C(n) are coprime

	uint64_t e;
	int i;
	for (int i = 16; i < c; ++i)
	{
		if (gcd(i,c) == 1){
			e = i;
			break;
		}
	}

	printf("Chose %lu for e!\n", e);


	//	- Compute d = e^-1 mod C(n)
 	//	- ie. Compute d, the multiplicative inverse of e mod C(n)
 	
 	uint64_t d = modInverse(e,c);
 	printf("Chose %lu as d!\n", d);

 	// Encrypt a message:
 	char msg[] = "This is my much longer Message!";
 	int msg_length = strlen(msg);
 	printf("Message String: %s, (Length: %i)\n", msg, msg_length);

 	
 	//  - Cipher text c = p^e (mod n) where e is the other's public key
 	
 	// Declares pointers to arrays of size msg_length
 	uint64_t ciph_pad[msg_length];
 	char decrypted_pad[msg_length];

 	// Encrypt:
 	encrypt(msg, msg_length, e, n, ciph_pad);

 	// Print Encrypted Message:
 	printf("Cipher Text: ");
 	for (int i = 0; i < msg_length; ++i)
 	{
 		printf("%c", (int)ciph_pad[i]);
 	}
 	printf("\n");

 	// Decrypt:
 	decrypt(ciph_pad, msg_length, d, n, decrypted_pad);

 	// Print Decrypted Message:
 	printf("Decrypted Text: ");
 	for (int i = 0; i < msg_length; ++i)
 	{
 		printf("%c", decrypted_pad[i]);
 	}
 	printf("\n");

}

/* Encrypt:
 *	- Takes pointer to input char array, ie the message to encrypt
 *	- Takes pointer to output uint64_t array, ie. the cipher buffer
 */
void encrypt(char *input, int msg_length, uint64_t e, uint64_t n, uint64_t *output)
{
 	for (int i = 0; i < msg_length; ++i)
 	{
 		output[i] = (uint64_t)my_pow(input[i], e, n);
 	}
}

/* Decrypt:
 *	- Takes pointer to input uint64_t array, ie the cipher buffer
 *	- Takes pointer to output char array, ie. decrypted message buffer
 */
void decrypt(uint64_t *input, int msg_length, uint64_t d, uint64_t n, char *output)
{
 	for (int i = 0; i < msg_length; ++i)
 	{
 		output[i] = (char)my_pow(input[i], d, n);
 	}
}

// Try them all naive:
uint64_t modInverse(uint64_t x, uint64_t m)
{
	int i;
	for (int i = 1; i < m; ++i)
	{
		if ((x*i) % m == 1)
		// if ((x * i)  == (1 % m))
		{
			return i;
		}
	}
}

// From https://www.geeksforgeeks.org/carmichael-numbers/
// Computes (x ^ y) mod m:
// Vast majority of time spent here
uint64_t my_pow(uint64_t x, uint64_t y, uint64_t m)
{
	if (y == 0)
	{
		return 1;
	}
	uint64_t temp = my_pow(x,y/2,m) % m;
	temp = (temp * temp) % m;
	if (y % 2 == 1)
	{
		temp = (temp * x) % m;
	}
	return temp;

}


/* Greatest Common Divisor
 * 	- Takes two ints i and j
 * 	- If either is 0, return the other
 * 	- r = i mod k
 * 	- Call gcd(j, r)
 */
uint64_t gcd(uint64_t i, uint64_t j)
{
	if (i == 0)
	{
		return j;
	}
	if (j == 0)
	{
		return i;
	}
	
	uint64_t r = i % j;
	uint64_t t = gcd(j,r);
}


/* Carmichael Function
 *  - Takes n
 * 	- Generate sequence Xm (ie. X = [m1, m2, .., mn])
 * 		- For each i < n, add to X if gcd(i,n) == 1
 * 		- X = list of all numbers less than n which are coprime to n
 * 	- k = 1
 * 	- For each m in X, increment k if (m^k) mod n == 1
 * 	- Return k
 */
uint64_t C(uint64_t n)
{
	uint64_t x[100];
	memset(&x, 0, sizeof(uint64_t)*100);
	
	int i;
	int cp_n = 0;
	// starts at 1?
	for (i = 1;i < n; i++)
	{
		if (cp_n >= 99) {break;printf("pad exhausted!\n");exit(0);}
		if (gcd(i,n) == 1)
		{
			x[cp_n] = i;
			cp_n ++;
		}
		
	}
	int k = 1;
	bool flag;
	while (true)
	{ 

		flag = true;
		uint64_t k2 = k;
		for (i = 0;i < cp_n; i++)
		{
			// printf("%lu ^ %i mod %lu ==  %lu\n", x[i], k, n, my_pow(x[i], k, n));
			if (my_pow(x[i], k, n) != 1)
			{
				flag = false;
			}
		}
		if (!flag) {
			k++;
			flag = true;
		} else {
			break;
		}

	}

	return (uint64_t)k;
}