X-Git-Url: https://harishankar.org/repos/?p=wordblah.git;a=blobdiff_plain;f=wordblah.h;h=864b238744b910a338b8a7e80a1417686af88c1b;hp=13874dcd67e54244ee367f32e9d4fef15ef00128;hb=HEAD;hpb=4dc5adcef4e6652b07b00087a24fc3d1305a6f81 diff --git a/wordblah.h b/wordblah.h index 13874dc..864b238 100644 --- a/wordblah.h +++ b/wordblah.h @@ -30,11 +30,13 @@ enum COLOR { WHITE=7 }; +/* Enum to define terminal attributes */ enum ATTR { NORMAL = 23, BOLD=1 }; +/* Enum to describe current movement orientation in puzzle grid */ enum ORIENTATION { ACROSS=1, DOWN=2 @@ -50,7 +52,7 @@ typedef char String[MAX_CLUE_LENGTH]; /* The main puzzle struct type */ typedef struct { - char chars[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE]; + char chars[MAX_PUZZLE_SIZE+1][MAX_PUZZLE_SIZE+1]; int start_across_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE]; int start_down_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE]; String clue_across[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE]; @@ -66,7 +68,7 @@ typedef struct { Puzzle puzzle; char filename[65535]; bool is_loaded; - char char_ans[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE]; + char char_ans[MAX_PUZZLE_SIZE+1][MAX_PUZZLE_SIZE+1]; int cur_row; int cur_col; bool solution_revealed; @@ -103,13 +105,113 @@ err: exit (2); } -/* encode the binary data to readable text format using OpenSSL */ -void encode_binary (char *encoded, unsigned char *binary_data, unsigned int len) +/* encode the binary data to readable text format using OpenSSL - also call + OPENSSL_free if the binary data was allocated by OpenSSL */ +void encode_binary (char *encoded, unsigned char *binary_data, unsigned int len, + bool free_openssl_data) { EVP_EncodeBlock ((unsigned char*)encoded, (const unsigned char*)binary_data, len); - OPENSSL_free (binary_data); + if (free_openssl_data) + OPENSSL_free (binary_data); +} + +/* decode the binary data from the textual representation using OpenSSL */ +void decode_binary (char *bin_data, char *encoded) +{ + EVP_DecodeBlock ((unsigned char*)bin_data, + (const unsigned char*)encoded, strlen (encoded)); +} + +/* encrypt a block of text using password/passphrase with OpenSSL and + also encode it to textual representation */ +void encrypt_data (char *enc_data, const char *data, const char *password) +{ + EVP_CIPHER_CTX *ctx; + int len, cipher_len; + ctx = EVP_CIPHER_CTX_new (); + if (! ctx) goto err; + + unsigned char encrypted[256] = { '\0' }; + + unsigned char key[EVP_MAX_KEY_LENGTH] = { '\0'}; + unsigned char iv[EVP_MAX_IV_LENGTH] = { '\0' }; + + if (! EVP_BytesToKey (EVP_aes_256_cbc(), EVP_md5(), NULL, + (unsigned char*)password, strlen(password), + 10, key, iv)) + goto err; + + if (1 != EVP_EncryptInit_ex (ctx, EVP_aes_256_cbc(), NULL, key, iv)) + goto err; + + if (1 != EVP_EncryptUpdate (ctx, (unsigned char*) encrypted, &len, + (unsigned char*) data, strlen (data) )) + goto err; + cipher_len = len; + + if (1 != EVP_EncryptFinal_ex (ctx, encrypted + len, &len)) + goto err; + + cipher_len += len; + EVP_CIPHER_CTX_free (ctx); + + EVP_EncodeBlock ((unsigned char*) enc_data, (unsigned char*) encrypted, + cipher_len); + return; + err: + ERR_print_errors_fp (stderr); + EVP_CIPHER_CTX_free (ctx); + exit (2); +} + +/* decrypt a block of text using password/passphrase with OpenSSL */ +void decrypt_data (char *dec_data, const char *data, const char *password) +{ + EVP_CIPHER_CTX *ctx; + int len, text_len; + ctx = EVP_CIPHER_CTX_new (); + if (! ctx) goto err; + + char enc_data[256] = { '\0' }; + + unsigned char key[EVP_MAX_KEY_LENGTH] = { '\0'}; + unsigned char iv[EVP_MAX_IV_LENGTH] = { '\0' }; + + + if (! EVP_BytesToKey (EVP_aes_256_cbc(), EVP_md5(), NULL, + (unsigned char*)password, strlen(password), + 10, key, iv)) + goto err; + + int r = EVP_DecodeBlock ((unsigned char*)enc_data, + (const unsigned char*) data, strlen (data)); + if (-1 == r) + goto err; + + + if (1 != EVP_DecryptInit_ex (ctx, EVP_aes_256_cbc(), NULL, key, iv)) + goto err; + + if (1 != EVP_DecryptUpdate (ctx, (unsigned char*) dec_data, &len, + (unsigned char*) enc_data, r - (r % 16) )) + goto err; + text_len = len; + + if (1 != EVP_DecryptFinal_ex (ctx, (unsigned char *)dec_data + len, &len)) + goto err; + + text_len += len; + EVP_CIPHER_CTX_free (ctx); + + dec_data[text_len] = '\0'; + + return; + err: + ERR_print_errors_fp (stderr); + EVP_CIPHER_CTX_free (ctx); + exit (2); } /* get a number from the user */ @@ -134,7 +236,7 @@ bool verify_solution_password (Puzzle *p, const char* password) digest_message ((const unsigned char *)password, strlen(password), &hashed_sol_password, &len); char hashed_hex_pwd[256] = { '\0' }; - encode_binary (hashed_hex_pwd, hashed_sol_password, len); + encode_binary (hashed_hex_pwd, hashed_sol_password, len, true); if (strcmp (p->hashed_solution_password, hashed_hex_pwd) == 0) return true; @@ -156,7 +258,7 @@ bool verify_master_password (Puzzle *p, const char* password) digest_message ((const unsigned char *)password, strlen(password), &hashed_mas_password, &len); char hashed_hex_pwd[256] = { '\0' }; - encode_binary (hashed_hex_pwd, hashed_mas_password, len); + encode_binary (hashed_hex_pwd, hashed_mas_password, len, true); if (strcmp (p->hashed_master_password, hashed_hex_pwd) == 0) return true; @@ -180,7 +282,7 @@ void set_solution_password (Puzzle *p, const char *password) /* the hashedpwd contains binary data - we will convert it to hexadecimal data and store in file */ - encode_binary (p->hashed_solution_password, hashedpwd, len); + encode_binary (p->hashed_solution_password, hashedpwd, len, true); } } @@ -200,7 +302,7 @@ void set_master_password (Puzzle *p, const char *password) /* the hashedpwd contains binary data - we will convert it to hexadecimal data and store in file */ - encode_binary (p->hashed_master_password, hashedpwd, len); + encode_binary (p->hashed_master_password, hashedpwd, len, true); } } @@ -479,8 +581,17 @@ void freeze_puzzle (Puzzle *p) /* reset the entire grid */ void init_puzzle (Puzzle *p, int grid_size) { - p->grid_size = grid_size; + /* check for bounds */ + if (p->grid_size > MAX_PUZZLE_SIZE) + p->grid_size = MAX_PUZZLE_SIZE; + else + p->grid_size = grid_size; + + /* grid is always unfrozen for a new puzzle */ p->grid_frozen = false; + + /* initialize all the puzzle data - characters, start of words (across/down) + and the clues to null */ for (int i = 0; i < p->grid_size; i ++) { for (int j = 0; j < p->grid_size; j ++) @@ -488,10 +599,11 @@ void init_puzzle (Puzzle *p, int grid_size) p->chars[i][j] = ' '; p->start_across_word[i][j] = -1; p->start_down_word[i][j] = -1; - strcpy (p->clue_across[i][j], ""); - strcpy (p->clue_down[i][j], ""); + strcpy (p->clue_across[i][j], "\0"); + strcpy (p->clue_down[i][j], "\0"); } } + /* reset the master password and solution password */ strcpy (p->hashed_master_password, "\0"); strcpy (p->hashed_solution_password, "\0"); @@ -517,11 +629,16 @@ void save_puzzle (Puzzle *puzzle, const char* file) /* the hashed_solution_password */ fprintf (outfile, "%s\n", puzzle->hashed_solution_password); - /* First output the grid characters columns/rows */ + /* First output the grid characters columns/rows as encrypted */ for (int i = 0; i < puzzle->grid_size; i ++) { - for (int j = 0; j < puzzle->grid_size; j ++) - fprintf (outfile, "%c", puzzle->chars[i][j]); + char encrypted[256] = { '\0' }; + /* encrypt the grid characters at row i with master password to + generate the key and iv */ + encrypt_data (encrypted, puzzle->chars[i], + puzzle->hashed_master_password); + + fprintf (outfile, "%s", encrypted); fprintf (outfile, "\n"); } @@ -670,22 +787,41 @@ Puzzle load_puzzle (const char* file) /* read each character of the grid */ for (int i = 0; i < p.grid_size; i ++ ) { - fgets (line, MAX_CLUE_LENGTH + 10, infile); + char encrypted[256]; + /* get a line from the file - each line is a grid row */ + fgets (encrypted, MAX_CLUE_LENGTH + 10, infile); + /* decrypt each line from the file and put the decrypted chars + into the grid array */ + decrypt_data (line, encrypted, p.hashed_master_password); + /* finally read the decrypted data into the array */ for (int j = 0; j < p.grid_size; j ++) p.chars[i][j] = line[j]; + } /* read the word numbers */ for (int i = 0; i < p.grid_size; i ++) { + /* get a line from the file - each file represents a row */ + /* the word numbers are started as n1n2 where n1 is + the across word number and n2 is the down word number. + Though both across and down word numbers will be the same + in a given cell, we use separate number to determine whether + there is an across or down word or both in a given cell. */ fgets (line, MAX_CLUE_LENGTH + 10, infile); + /* split the line into tokens with space as the separating character */ char *token = strtok (line, " "); for (int j = 0; j < p.grid_size; j ++) { + /* so long as token is valid, read the first token as across + word number */ if (token != NULL) p.start_across_word[i][j] = atoi (token); + /* similarly get the next token as the down word number */ token = strtok (NULL, " "); if (token != NULL) p.start_down_word[i][j] = atoi (token); + /* get the next token, it should be the across word number format + the next cell or NULL if we have read all the tokens */ token = strtok (NULL, " "); } } @@ -700,7 +836,7 @@ Puzzle load_puzzle (const char* file) while (1) { fgets (line, MAX_CLUE_LENGTH + 10, infile); - /* if reached the end of across clues */ + /* the word DOWN indicates that we reached the end of across clues */ if (strcmp (line, "DOWN\n") == 0) break; word_num[c] = atoi (strtok (line, "\t")); @@ -795,7 +931,7 @@ void print_puzzle (Puzzle *p) /* print the clues if set */ if (p->grid_frozen == true) { - printf ("\x1B[1mACROSS - CLUES\x1B[0m\n"); + printf ("\x1B[1m%s\x1B[0m\n", ACROSS_CLUES); for (int i = 0; i < p->grid_size; i ++) { for (int j = 0; j < p->grid_size; j ++) @@ -807,7 +943,7 @@ void print_puzzle (Puzzle *p) } } } - printf ("\n\x1B[1mDOWN - CLUES\x1B[0m\n"); + printf ("\n\x1B[1m%s\x1B[0m\n", DOWN_CLUES); for (int i = 0; i < p->grid_size; i ++) { for (int j = 0; j < p->grid_size; j ++)