/*************************************************************** Title: Crypture 1.0 Author: Jerramy Gipson Features: Stores encrypted text in a bitmap image file. Append to existing text, or overwrite file. Insert text from an existing plain text file. Command line interface, with small executable footprint. No identifying data header used. Randomizes low order bits of image with non-determinable seed, to prevent detection of steganography. Decrypts text to memory only - doesn't write plain text to disk. Interlaces bit writes by password determined seperation distance, to hinder brute force encryption cracking. Uses 1024 bit encryption key. Passwords up to 128 characters long are supported. License: This software is open source and freeware. You may do whatever you want with this software, except for holding me liable for any damage which arises from your usage of it. If it eats your hard-disk, cracks into NASA, and starts a nuclear war, don't come crying to me! Build Tools: This was built on Windows XP, with the Tiny C Compiler, version 0.9.23, using the following command: C:\tcc-0.9.23\tcc> tcc -o crypture.exe -L..\lib -I..\include crypture.c ****************************************************************/ #include #include #include #include #include #include //#include typedef unsigned char UInt8; typedef unsigned short UInt16; typedef unsigned UInt32; #define NUM_SEEDS 32 /* a power of 2 please */ UInt32 rand_seeds[NUM_SEEDS]; int rand_index = 0; UInt16 my_rand() { rand_seeds[rand_index % NUM_SEEDS] = rand_seeds[rand_index % NUM_SEEDS] * 1103515245 + 12345; return (rand_seeds[rand_index++ % NUM_SEEDS] >> 16); } //#define SKIP_DISTANCE 134 UInt8 SKIP_DISTANCE = 0; void create_seed(char* string) { int i; for (i = 0; i < NUM_SEEDS; ++i) { rand_seeds[i] = 0x538F3EA1 * (i+1); char* seed_string = string; while(*seed_string != 0) { rand_seeds[i] = rand_seeds[i] * (UInt8)(*seed_string) + ~(UInt8)(*seed_string); seed_string++; } } rand_index = 0; //to reset rand(). SKIP_DISTANCE = 0; while (SKIP_DISTANCE == 0) SKIP_DISTANCE = my_rand() % 256; } char* text_data = 0; int BMP_FILE = -1; int file_length = 0; UInt8* bmp_ptr = 0; char password[130]; UInt8* index_raw_data(UInt8* raw_data, UInt32 raw_size, UInt32 index) { UInt32 skips_per_cycle = raw_size / SKIP_DISTANCE; if (skips_per_cycle == 0) return 0; UInt32 skip_cycle = index / skips_per_cycle; if (skip_cycle >= SKIP_DISTANCE) return 0; UInt32 skip_offset = index % skips_per_cycle; return raw_data + skip_cycle + (skip_offset*SKIP_DISTANCE); } //This expects text_data to have already been malloced. int extract_text(UInt8* raw_data, UInt32 num_bytes) { int i; int j; create_seed(password); for (i = 0; i < num_bytes; ++i) { text_data[i] = 0; for (j = 0; j < 8; ++j) { UInt8* raw = index_raw_data(raw_data, num_bytes*8, i*8+j); text_data[i] <<= 1; text_data[i] |= (*raw & 0x01); } text_data[i] = (UInt8)(text_data[i] ^ my_rand()); if (text_data[i] == 0) break; //stop at NULL. } for (i = 0; i < num_bytes; ++i) { if (text_data[i] == 0) break; //stop at NULL. if ((UInt8)(text_data[i]) >= 128) { printf("Wrong password or new file.\n"); return 0; } } printf("------------------------------------------\n"); printf("%s\n", text_data); printf("------------------------------------------\n"); return 1; } void insert_text(UInt8* raw_data, UInt32 num_bytes) { int i; int j; create_seed(password); //Hopefully this will prevent corruption (though it will lose data). if (strlen(text_data) < num_bytes - (SKIP_DISTANCE / 8 + 1)) printf("File is %d%% full.\n", 100*strlen(text_data) / num_bytes); else { printf("More than 100%% full. Text has been truncated.\n"); text_data[num_bytes - SKIP_DISTANCE/8 - 2] = 0; } for (i = 0; i < num_bytes; ++i) { UInt8 temp = text_data[i]; text_data[i] = (UInt8)(text_data[i] ^ my_rand()); for (j = 0; j < 8; ++j) { UInt8* raw = index_raw_data(raw_data, num_bytes*8, i*8+j); *raw &= 0xFE; *raw |= (text_data[i] < 0); //checks the high order bit. text_data[i] <<= 1; } if (temp == 0) break; //stop at NULL. } } void randomize_image(UInt8* raw_data, UInt32 num_bits) { char chaos_key[130]; struct _timeb timestruct; strcpy(chaos_key, password); _ftime(×truct); *(UInt16*)chaos_key = timestruct.millitm; if (strlen(password) < 2) chaos_key[2] = 0; create_seed(chaos_key); while (num_bits-- > 0) { *raw_data &= 0xFE; *raw_data |= ((my_rand()>>2) & 0x0001); ++raw_data; } } void EXIT(int val) { if (BMP_FILE != -1) _close(BMP_FILE); else printf("Error opening file.\n"); if (bmp_ptr != 0) free(bmp_ptr); else printf("Error allocating memory.\n"); if (text_data != 0) free(text_data); else printf("Error allocating memory.\n"); exit(val); } void main(int argc, char* argv[]) { int i; if ((argc <= 1) || (argc >= 4)) { printf("Usage: crypture []\n"); exit(-1); } if (argc == 2) { printf("Password: "); gets(password); } else strcpy(password, argv[2]); if ((BMP_FILE = _open(argv[1], (_O_BINARY | _O_RDWR))) == -1) EXIT(-1); if ((file_length = _filelength(BMP_FILE)) < 1) EXIT(-1); if ((bmp_ptr = (UInt8*)malloc(file_length)) == 0) EXIT(-1); _read(BMP_FILE, bmp_ptr, file_length); UInt32 file_size = *(UInt32*)(bmp_ptr + 2); UInt32 data_start = *(UInt32*)(bmp_ptr + 10); UInt16 numbits = *(UInt16*)(bmp_ptr + 28); UInt32 compress = *(UInt32*)(bmp_ptr + 30); if (*(UInt16*)bmp_ptr!= 19778) EXIT(-1); //not a bitmap. if (data_start != 54) EXIT(-1); //uses a color table. if (numbits != 24) EXIT(-1); //Currently use only 24 bit bitmaps. if (compress != 0) EXIT(-1); //Absolutely don't support compression. UInt32 num_bytes = (file_size - data_start) / 8; text_data = malloc(num_bytes); UInt8* raw_data = (UInt8*)(bmp_ptr + data_start); int valid_text = extract_text(raw_data, num_bytes); char* insert_ptr = text_data; printf("Would you like to:\n"); printf(" (1) Exit without modification.\n"); printf(" (2) Erase all and start over.\n"); printf(" (3) Insert from a text file.\n"); if (valid_text) printf(" (4) Add to text?\n"); printf(">"); char answer[100]; gets(answer); switch (answer[0]) { case '4': if (valid_text) insert_ptr += strlen(text_data); //move to end of current text //fall through to next case... case '2': //already set up. printf("\n commits a line of text. \n"); printf("Tilde (~) at start of line quits and writes to file.\n"); printf(" will abort without writing.\n\n"); do { gets(insert_ptr); if (insert_ptr[0] == '~') break; insert_ptr += strlen(insert_ptr); insert_ptr[0] = '\n'; insert_ptr++; insert_ptr[0] = 0; } while(strlen(text_data) < num_bytes/2); insert_ptr[0] = 0; break; case '3': { int TXT_FILE = -1; do { printf("Filename: "); gets(answer); TXT_FILE = _open(answer, (_O_BINARY | _O_RDONLY)); } while (TXT_FILE == -1); UInt32 bytes_to_xfer = _filelength(TXT_FILE); if (bytes_to_xfer >= num_bytes/2) bytes_to_xfer = num_bytes/2 - 1; _read(TXT_FILE, text_data, bytes_to_xfer); text_data[bytes_to_xfer] = 0; _close(TXT_FILE); break; } default: EXIT(0); } randomize_image(raw_data, file_size - data_start); insert_text(raw_data, num_bytes); _lseek(BMP_FILE, 0, SEEK_SET); //back to the beginning. _write(BMP_FILE, bmp_ptr, file_length); printf("Done.\n"); EXIT(0); }