/* 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);
}
-/* convert the hashed binary password to hexadecimal representation and
- free the hashed binary password */
-void to_hexadecimal (char *hex, unsigned char *binary_pwd, 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)
{
- char buf[3];
- /* keep reference to beginning of the hashed password */
- unsigned char *binary_pw_begin = binary_pwd;
- for (int i = 0; i < len; i ++)
- {
- sprintf (buf, "%02x", (*binary_pwd)&0xff);
- strcat (hex, buf);
- binary_pwd ++;
- }
- /* free the hashed password */
- OPENSSL_free (binary_pw_begin);
+
+ EVP_EncodeBlock ((unsigned char*)encoded,
+ (const unsigned char*)binary_data, len);
+ 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 };
- to_hexadecimal (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 };
- to_hexadecimal (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 */
- to_hexadecimal (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 */
- to_hexadecimal (p->hashed_master_password, hashedpwd, len);
+ encode_binary (p->hashed_master_password, hashedpwd, len, true);
}
}
/* 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_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 encoded[256];
+ fgets (encoded, MAX_CLUE_LENGTH + 10, infile);
+ decrypt_data (line, encoded, p.hashed_master_password);
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 ++)