I have been messing around with cryptography (for recreational use), and I created my own one-time-pad encryption script in C. Now, with that being said, I freely admit that I am by no means a cryptography expert. I know that Rule No. 1 of cryptography is not to do it yourself. However, I am genuinely interested in whether my encryption script is (theoretically) secure.
First, here is a basic debrief of what I am attempting to achieve with my encryption method:
The goal is to achieve One Time Pad Encryption, where both (1) a hash table and (2) an encryption key are used. The hash table (in this case) is pre-coded where the values are 01-98.
The encryption key is calculated as follows:
- Get random user input (at least the same length as the message)
- Get corresponding index for char in validChars[] (source code below)
- Get the number in defaultHashTable that corresponds to #2's index
The message is encrypted as follows:
- Take the message and convert it into the corresponding defaultHashTable values
- Take the previously generated key and add it to the converted message
- Now it is encrypted (assuming the same key is never used again)
For example:
- Message: hello
- Convert to corresponding defaultHashTable values: hello -> 0805121215
- Get random chars for key: abkdh
- Convert to corresponding defaultHashTable values: abkdh -> 0102110408
- Add the key: 0805121215 + 0102110408 = 0907231623
- Encrypted message: 0907231623
Here is the source code (NOTE: This is a combination of functions that were in separate C header files, so that is why I am not posting a main () function):
typedef struct {
char key[MAX_SIZE][3];
} Key;
Key globalKey;
typedef struct {
char encryptedMessage[MAX_SIZE][3];
} EncryptedMessage;
typedef struct {
char hashtable[HASHTABLE_CAPACITY][3];
} DefaultHashTable;
DefaultHashTable defaultHashTable;
void initDefaultHashTable(){
for (int i = 0; i < HASHTABLE_CAPACITY; i++){
char s[3];
sprintf(s, "%d", (i+1));
if (i < 10){
char tmp = s[0];
s[0] = '0';
s[1] = tmp;
}
for (int j = 0; j < 2; j++){
defaultHashTable.hashtable[i][j] = s[j];
}
}
}
char validChars[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','!','@','#','$','%','^','&','*','(',')','-','+',' ',',','.',':',';','\'','\"','[',']','{','}','_','=','|','\\','/','<','>','?','`','~','\n','\t','0','1','2','3','4','5','6','7','8','9'};
char FAILED = (char)255;
int findChar(char c){
for (int i = 0; i < strlen(validChars); i++){
if (validChars[i] == c){
return i;
}
}
return FALSE;
}
char returnChar(int index){
return validChars[index];
}
char findHashTableValue(char n[3], char hashtable[][3]){
for (int i = 0; i < HASHTABLE_CAPACITY; i++){
if (hashtable[i][0] == n[0] && hashtable[i][1] == n[1])
return returnChar(i);
}
return FAILED;
}
void goThroughLightEnryptionProcess(char * str, char * write_to_file){
initDefaultHashTable();
generateRandomKey(strlen(str), MAX_SIZE, FALSE);
EncryptedMessage encryptMsg = otpEncrypt(defaultHashTable.hashtable, str, globalKey.key);
if (write_to_file == NULL){
for (int i = 0; i < strlen(str); i++){
for (int j = 0; j < 2; j++){
printf("%c", encryptMsg.encryptedMessage[i][j]);
}
}
printf("\n");
} else {
writeFileWithTwoDimensionalArray(encryptMsg.encryptedMessage, HASHTABLE_CAPACITY, write_to_file);
}
}
void loadIntoKeyForRandoKey(int at, char n[3]){
for (int i = 0; i < 2; i++){
globalKey.key[at][i] = n[i];
}
}
void generateRandomKey(int password_length, int max_size, bool use_global){
char response[max_size];
printf("Enter random characters for the key (a-z,A-Z,!@#$%%^&*()-+=, min length of %d): ", password_length);
fgets(response, max_size, stdin);
char * p;
if ((p = strchr(response, '\n')) != NULL){
*p = '\0';
} else {
scanf("%*[^\n]");
scanf("%*c");
}
if (strlen(response) < password_length){
printf("\n[ ERROR ] : Random characters must be greater than or equal to %d.\n", password_length);
return generateRandomKey(password_length, max_size, use_global);
}
for (int i = 0; i < password_length; i++){
int getCharIndex = findChar(response[i]);
if (getCharIndex == FALSE){
printf("\n[ ERROR ] Character '%c' is invalid. Try again.\n", response[i]);
return generateRandomKey(password_length, max_size, use_global);
}
if (use_global == TRUE){
loadIntoKeyForRandoKey(i, globalHashTable.hashtable[getCharIndex]);
} else {
loadIntoKeyForRandoKey(i, defaultHashTable.hashtable[getCharIndex]);
}
}
createFileWithTwoDimensionalArray(globalKey.key, password_length, "key");
}
void loadIntoEncryptedMessage(int at, char n[3], EncryptedMessage *encryptedMsg){
if (strlen(n) == 1){
char tmp = n[0];
n[0] = '0';
n[1] = tmp;
}
for (int i = 0; i < 2; i++){
encryptedMsg->encryptedMessage[at][i] = n[i];
}
}
EncryptedMessage otpEncrypt(char hashtable[][3], char * msg, char key[MAX_SIZE][3]){
EncryptedMessage encryptedMsg;
for (int i = 0; i < strlen(msg); i++){
int convertedKeyValueIntoInt = safelyConvertToInt(key[i]);
if (convertedKeyValueIntoInt == FALSE){
printf("[ ERROR ] : The key is corrupted at %d (value = %s).\n", i, key[i]);
exit(1);
}
int indexOfMsgChar = findChar(msg[i]);
if (indexOfMsgChar == FALSE){
printf("[ ERROR ] : The password (msg) is corrupted at %d (value = %s). This may have occurred because a char '%c' is not allowed.\n", i, msg, msg[i]);
exit(1);
}
char * correspondingEncryptMsgChars = hashtable[indexOfMsgChar];
int convertedEncryptMsgCharsIntoInt = safelyConvertToInt(correspondingEncryptMsgChars);
if (convertedEncryptMsgCharsIntoInt == FALSE){
printf("[ ERROR ] : Hash table is corrupted at %d (value = %s).\n", indexOfMsgChar, correspondingEncryptMsgChars);
exit(1);
}
int encryptedFrag = otpeAdd(convertedEncryptMsgCharsIntoInt, convertedKeyValueIntoInt);
char encryptedFragStr[3];
sprintf(encryptedFragStr, "%d", encryptedFrag);
loadIntoEncryptedMessage(i, encryptedFragStr, &encryptedMsg);
}
return encryptedMsg;
}
My immediate question would be: if I am using a pre-coded hash table (that anyone could infer), does that make the encryption insecure (even though the key that corresponds to the hash table values are completely random via user input)? Is it only secure if I randomize the hash table numbers (01-98) (and potentially randomize the validChars[])?
I am honestly interested whether my logic holds, so any comments, suggestions, or criticisms would be much appreciated.