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
/* 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];
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;
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 */
unsigned int len;
digest_message ((const unsigned char *)password, strlen(password),
&hashed_sol_password, &len);
- char hashed_hex_pwd[256] = { (char) NULL };
- encode_binary (hashed_hex_pwd, hashed_sol_password, len);
+ char hashed_hex_pwd[256] = { '\0' };
+ encode_binary (hashed_hex_pwd, hashed_sol_password, len, true);
if (strcmp (p->hashed_solution_password, hashed_hex_pwd) == 0)
return true;
unsigned int len;
digest_message ((const unsigned char *)password, strlen(password),
&hashed_mas_password, &len);
- char hashed_hex_pwd[256] = { (char) NULL };
- encode_binary (hashed_hex_pwd, hashed_mas_password, len);
+ char hashed_hex_pwd[256] = { '\0' };
+ encode_binary (hashed_hex_pwd, hashed_mas_password, len, true);
if (strcmp (p->hashed_master_password, hashed_hex_pwd) == 0)
return true;
/* 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);
}
}
/* 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);
}
}
/* 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 ++)
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");
/* 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");
}
/* read the puzzle from a file */
Puzzle load_puzzle (const char* file)
{
+ Puzzle p;
/* First open the GZip file */
gzFile insourcefile = gzopen (file, "rb");
if (insourcefile == NULL)
{
fprintf (stderr, "%s %s\n", ERROR_READING_FILE, COMPRESSED);
- exit (1);
+ /* return an invalid puzzle */
+ init_puzzle (&p, 0);
+ return p;
}
/* Open a temporary file to uncompress the contents */
FILE *infile = tmpfile ();
if (infile == NULL)
{
fprintf (stderr, "%s\n", ERROR_READING_FILE);
- exit (1);
+ init_puzzle (&p, 0);
+ return p;
}
/* Put the uncompressed content to the temp file */
char buf[128];
fprintf (stderr, "%s\n", ERROR_READING_FILE);
fclose (infile);
gzclose (insourcefile);
- exit (1);
+ /* return an invalid puzzle */
+ init_puzzle (&p, 0);
+ return p;
}
num = gzread (insourcefile, buf, 128);
}
fseek (infile, 0, 0);
/* Read the temporary file contents to the structure Puzzle */
- Puzzle p;
char line[MAX_CLUE_LENGTH+10];
fgets (line, MAX_CLUE_LENGTH + 10, infile);
p.grid_size = atoi (line);
+ /* if puzzle is invalid or otherwise not proper grid, return an invalid
+ puzzle object */
+ if (p.grid_size == 0)
+ {
+ fprintf (stderr, "%s\n", INVALID_PUZZLE);
+ init_puzzle (&p, 0);
+ return p;
+ }
fgets (line, MAX_CLUE_LENGTH + 10, infile);
p.grid_frozen = atoi (line) == 0 ? false : true ;
fgets (line, MAX_CLUE_LENGTH + 10, infile);
/* 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 n1<space>n2 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, " ");
}
}
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"));
/* 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 ++)
}
}
}
- 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 ++)