Implemented encryption to obfuscate the grid in puzzle file
[wordblah.git] / wordblah.h
index 13874dc..f818a7e 100644 (file)
@@ -50,7 +50,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 +66,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 +103,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 +234,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 +256,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 +280,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 +300,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);
        }
 }
 
@@ -517,11 +617,14 @@ 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_data (encrypted, puzzle->chars[i], 
+                                                               puzzle->hashed_master_password);
+
+               fprintf (outfile, "%s", encrypted);
                fprintf (outfile, "\n");
        }
        
@@ -670,9 +773,12 @@ 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 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 ++)