diff options
author | Pin <wf6DJd8a3xSSCZbn@protonmail.com> | 2021-09-21 01:15:03 -0400 |
---|---|---|
committer | Pin <wf6DJd8a3xSSCZbn@protonmail.com> | 2021-11-08 23:35:23 -0500 |
commit | c86b56286cc8815cb9ff049629bf58adee9f02f8 (patch) | |
tree | e0da9aeb2df72424caf5fb2dd42d3c2edcfa7bc6 | |
parent | fafe5a45206ef115f25eb3fc6851f79b206128dd (diff) |
Initial PNG CC Implementationv0.0.1
Signed-off-by: Pin <wf6DJd8a3xSSCZbn@protonmail.com>
-rw-r--r-- | .gitignore | 7 | ||||
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | cmd/crc.c | 304 | ||||
-rw-r--r-- | include/CRCLib.h | 55 | ||||
-rw-r--r-- | include/compress_util.h | 8 | ||||
-rw-r--r-- | include/crc.h | 8 | ||||
-rw-r--r-- | include/crc_util.h | 43 | ||||
-rw-r--r-- | src/compress_util.c | 132 | ||||
-rw-r--r-- | src/crc_util.c | 92 |
9 files changed, 668 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7a6301 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.png +*.out +*.woo +*.wow +*.gch +vgcore.* +bin/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9d3cb0d --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +LIBRARIES = `pkg-config --libs zlib libsodium` -Iinclude +SOURCES = ./src/* ./cmd/crc.c +OUTPUT_DIR = ./bin +OUTPUT = -o ${OUTPUT_DIR}/PROG + +build: output_dir + gcc -Wall ${LIBRARIES} ${SOURCES} ${OUTPUT:PROG=crc} + +debug: output_dir + gcc -Wall -g ${LIBRARIES} ${SOURCES} ${OUTPUT:PROG=crc} + +output_dir: + mkdir -p ${OUTPUT_DIR} + +clean: + rm -rf $(OUTPUT_DIR) **.h.gch + +memcheck: debug + valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes -s ${OUTPUT_DIR}/crc diff --git a/cmd/crc.c b/cmd/crc.c new file mode 100644 index 0000000..b872e6c --- /dev/null +++ b/cmd/crc.c @@ -0,0 +1,304 @@ +#pragma GCC optimize("Ofast") + +#include <endian.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sodium.h> +#include <getopt.h> +#include "crc_util.h" +#include "CRCLib.h" +#include "crc.h" +#include "compress_util.h" + +const long idat_signature = 1229209940; +const long iend_signature = 1229278788; + +unsigned long first_idat(unsigned char *addr) { + int idat_found = 0; + unsigned long offset = 8; + int jump_offset = 0; + int header_type = 0; + while(idat_found == 0) { + jump_offset = check_header_length(addr, offset); + header_type = check_header_length(addr, offset+4); + if(header_type == idat_signature) { + idat_found = 1; + } else { + offset = offset + jump_offset + 12; + } + } + return offset; +} + +int total_idat(unsigned char *addr) { + int iend_found = 0; + int found_idat = 0; + unsigned long offset = 8; + int jump_offset = 0; + int header_type = 0; + while(iend_found == 0) { + jump_offset = check_header_length(addr, offset); + header_type = check_header_length(addr, offset+4); + if(header_type == iend_signature) { + iend_found = 1; + } else { + if(header_type == idat_signature) { + found_idat++; + } + offset = offset + jump_offset + 12; + } + } + return found_idat; +} + +int update_file_crc(unsigned char *addr, unsigned long offset , unsigned int crc_num) { + int startCRC = 8 + offset + check_header_length(addr, offset); + unsigned char new_crc; + for(int i = 0; i < 4; i++) { + new_crc = crc_num >> (8*(3-i)) & 0xFF; + addr[startCRC+i] = new_crc; + } + return 0; +} + +void random_data_change(unsigned char *color_data, int width, int length) { + int searching = 1; + size_t rounds = 0; + width = 16; + int color_range = 3; + unsigned char temp_color_data[length]; + + do { + rounds++; + // Creating temporary data set + memcpy(temp_color_data, color_data, length); + // Generating random byte to change + int random_num = randombytes_uniform(length); + // Checking for index break + if(random_num % ((width * color_range) + 1)) { + if(color_data[random_num] == 255) { + temp_color_data[random_num]--; + } else { + temp_color_data[random_num]++; + } + unsigned char *check_data_buff = NULL; + size_t check_data_length = 0; + zlib_compress_data(temp_color_data, length, &check_data_buff, &check_data_length); + + unsigned char full_data[check_data_length+4]; + full_data[0] = 0x49; + full_data[1] = 0x44; + full_data[2] = 0x41; + full_data[3] = 0x54; + for(int i = 0; i < check_data_length; i++) { + full_data[i+4] = check_data_buff[i]; + } + unsigned int temp_crc = crc(full_data, check_data_length); + if ((temp_crc >> (8*3)) == 10 ) { + printf("Found in %zu rounds!\n", rounds); + memcpy(color_data, temp_color_data, length); + searching = 0; + } + free(check_data_buff); + } + + } while(searching == 1); +} + +void build_png_file(struct PNG_FILE_STRUCT *png_file, char *out_file_name) { + FILE *fp; + + fp = fopen(out_file_name, "w"); + + union{ + unsigned char data[sizeof(struct PNG_START_FILE_STRUCT)]; + struct PNG_START_FILE_STRUCT png_data; + }start_data; + + start_data.png_data = png_file->png_start_data; + + // IHDR Data + for(int i = 0; i < sizeof(start_data.data); i++) { + fputc(start_data.data[i], fp); + } + // IDAT Data + for(int i = 0; i < 4; i++) { + fputc(png_file->png_idat_data.idat_length[i], fp); + } + for(int i = 0; i < 4; i++) { + fputc(png_file->png_idat_data.idat_header[i], fp); + } + for(int i = 0; i < be32toh(png_file->png_idat_data.idat_data_length); i++) { + fputc(png_file->png_idat_data.idat_data[i], fp); + } + // Generating CRC + unsigned char full_data[be32toh(png_file->png_idat_data.idat_data_length)+4]; + for(int i = 0; i < 4; i++) { + full_data[i] = png_file->png_idat_data.idat_header[i]; + } + for(int i = 0; i < be32toh(png_file->png_idat_data.idat_data_length); i++) { + full_data[i+4] = png_file->png_idat_data.idat_data[i]; + } + + unsigned int int_crc = crc(full_data, be32toh(png_file->png_idat_data.idat_data_length)); + unsigned char new_crc[4]; + + for(int i = 0; i < 4; i++) { + new_crc[i] = int_crc >> (8*(3-i)) & 0xFF; + fputc(new_crc[i], fp); + } + // IEND Data + unsigned char IEND_DATA[12] = { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; + for(int i = 0; i < 12; i++) { + fputc(IEND_DATA[i], fp); + } + fclose(fp); +} + +int change_idat_content(unsigned char *addr, struct PNG_FILE_STRUCT *png_file, char *message, int accuracy, unsigned long offset, char *out_file_name) { + if(accuracy > 4) { + printf("Warning, accuracy cannot be larger than 4"); + return EXIT_FAILURE; + } + if(accuracy > 2) { + printf("Notice, this could take a long time..."); + } + if(total_idat(addr) < strlen((char*)message)) { + printf("Warning, message exceeds IDAT amount\n"); + exit(EXIT_FAILURE); + } + + int idat_length = check_header_length(addr, offset); + printf("IDAT Length: %d\n", idat_length); + + long size = 1; + size_t idat_byte_length = 0; + unsigned char* idat_data = calloc(size, sizeof(unsigned char)); + for(size_t i = 0; i <= idat_length; i++) { + if(i == size) { + size *= 2; + idat_data = reallocarray(idat_data, size, sizeof(unsigned char)); + } + idat_data[i] = addr[i+offset+8]; + idat_byte_length = i; + } + unsigned char temp_idat_data[idat_byte_length]; + for(int i = 0; i <= idat_length; i++) { + temp_idat_data[i] = idat_data[i]; + } + // Decompressing Data + unsigned char *uncom_data_buff = NULL; + size_t uncom_data_size = 0; + zlib_decompress_data(temp_idat_data, idat_byte_length, &uncom_data_buff, &uncom_data_size); + + random_data_change(uncom_data_buff, 16, uncom_data_size); + + // Compress Data + unsigned char *com_data_buff; + size_t com_data_size = 0; + zlib_compress_data(uncom_data_buff, uncom_data_size, &com_data_buff, &com_data_size); + + png_file->png_idat_data.idat_data = calloc(com_data_size, sizeof(unsigned char)); + + png_file->png_idat_data.idat_data_length = be32toh(com_data_size); + + for(size_t i = 0; i < com_data_size; i++) { + png_file->png_idat_data.idat_data[i] = com_data_buff[i]; + } + + // Build PNG File + build_png_file(png_file, out_file_name); + + free(uncom_data_buff); + free(com_data_buff); + free(idat_data); + free(png_file->png_idat_data.idat_data); + + return 0; +} + +// This is where it all starts +int main(int argc, char **argv) { + FILE *fp; + size_t i = 0; + unsigned long offset = 0; + struct PNG_FILE_STRUCT png_file_data; + char *in_file_name = NULL; + char *out_file_name = NULL; + char *message = NULL; + + static const struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"file", required_argument, NULL, 'f'}, + {"outfile", required_argument, NULL, 'o'}, + {"message", required_argument, NULL, 'm'}, + {0, 0, 0, 0} + }; + + const char* usage = + "Usage: crc [options]\n" + " -h, --help Shows help message\n" + " -f, --file Denotes input file\n" + " -o, --outfile Denotes output file\n" + " -m, --message Encoded message\n" + "\n"; + + int c; + while (1) { + int option_index = 0; + c = getopt_long(argc, argv, "hf:o:m:", long_options ,&option_index); + if(c == -1) { + break; + } + switch(c) { + case 'h': + printf("%s", usage); + exit(EXIT_SUCCESS); + case 'f': + in_file_name = optarg; + break; + case 'o': + out_file_name = optarg; + break; + case 'm': + message = optarg; + break; + } + } + + if(in_file_name == NULL) { + printf("Input file required!\n"); + exit(EXIT_FAILURE); + } else if(out_file_name == NULL) { + printf("Output file required!\n"); + exit(EXIT_FAILURE); + } else if(message == NULL) { + printf("Message required!\n"); + exit(EXIT_FAILURE); + } + + if(sodium_init() == -1) { + return EXIT_FAILURE; + } + + fp = fopen(in_file_name, "rt"); + if (fp == NULL) { + printf("File error\n"); + exit(EXIT_FAILURE); + } + + unsigned char *file_data = file_to_char_array(fp, &i); + fclose(fp); + + populate_start_png(file_data, &png_file_data.png_start_data); + + offset = first_idat(file_data); + + populate_idat_png(file_data, &png_file_data.png_idat_data, offset); + + change_idat_content(file_data, &png_file_data, message, 1, offset, out_file_name); + + free(file_data); +} diff --git a/include/CRCLib.h b/include/CRCLib.h new file mode 100644 index 0000000..f451ffb --- /dev/null +++ b/include/CRCLib.h @@ -0,0 +1,55 @@ +/* + * Code Implemented From: https://www.w3.org/TR/PNG/#D-CRCAppendix +*/ + +/* Table of CRCs of all 8-bit messages. */ +unsigned long crc_table[256]; + +/* Flag: has the table been computed? Initially false. */ +int crc_table_computed = 0; + +/* Make the table for a fast CRC. */ +void make_crc_table(void) +{ + unsigned long c; + int n, k; + + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = 0xedb88320L ^ (c >> 1); + else + c = c >> 1; + } + crc_table[n] = c; + } + crc_table_computed = 1; +} + + +/* Update a running CRC with the bytes buf[0..len-1]--the CRC + should be initialized to all 1's, and the transmitted value + is the 1's complement of the final running CRC (see the + crc() routine below). */ + +unsigned long update_crc(unsigned long crc, unsigned char *buf, + int len) +{ + unsigned long c = crc; + int n; + + if (!crc_table_computed) + make_crc_table(); + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c; +} + +/* Return the CRC of the bytes buf[0..len-1]. */ +unsigned long crc(unsigned char *buf, int len) +{ + return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL; +} + diff --git a/include/compress_util.h b/include/compress_util.h new file mode 100644 index 0000000..f0c623f --- /dev/null +++ b/include/compress_util.h @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <zlib.h> +#include <stddef.h> +#include <assert.h> +#include <errno.h> + +void zlib_decompress_data(unsigned char *data_chunk, size_t file_length, unsigned char **buff, size_t *sz); +void zlib_compress_data(unsigned char *data_chunk, size_t file_length, unsigned char **buff, size_t *sz); diff --git a/include/crc.h b/include/crc.h new file mode 100644 index 0000000..bf3b74a --- /dev/null +++ b/include/crc.h @@ -0,0 +1,8 @@ +#pragma once + +int check_file_header(char *addr); +int check_header_length(unsigned char *addr, long offset); +unsigned long first_idat(unsigned char *addr); +int total_idat(unsigned char *addr); +void build_png_file(struct PNG_FILE_STRUCT *png_file, char *out_file_name); +int change_idat_content(unsigned char *addr, struct PNG_FILE_STRUCT *png_file, char *message, int accuracy, unsigned long offset, char *out_file_name); diff --git a/include/crc_util.h b/include/crc_util.h new file mode 100644 index 0000000..5670cdb --- /dev/null +++ b/include/crc_util.h @@ -0,0 +1,43 @@ +#include <stdio.h> +#include <stdint.h> + +#pragma once + +// PNG File Struct +struct PNG_START_FILE_STRUCT { + unsigned char file_sig[8]; + unsigned char ihdr_length[4]; + unsigned char ihdr_header[4]; + unsigned char file_width[4]; + unsigned char file_height[4]; + unsigned char bit_depth[1]; + unsigned char color_type[1]; + unsigned char compression_method[1]; + unsigned char filter_method[1]; + unsigned char interlace_method[1]; + unsigned char ihdr_crc[4]; +}; + +struct PNG_IDAT_FILE_STRUCT { + union{ + unsigned char idat_length[4]; + uint32_t idat_data_length; + }; + unsigned char idat_header[4]; + unsigned char idat_crc[4]; + unsigned char *idat_data; +}; + +struct PNG_FILE_STRUCT { + struct PNG_START_FILE_STRUCT png_start_data; + struct PNG_IDAT_FILE_STRUCT png_idat_data; +}; + +extern const long png_signature[8]; + +int check_header_length(unsigned char *addr, long offset); +int check_file_header(char *addr); +int create_cc_file(unsigned char *addr, unsigned long file_length); +unsigned char* file_to_char_array(FILE *in_file, size_t* size); +void populate_start_png(unsigned char *addr, struct PNG_START_FILE_STRUCT *png_data); +void populate_idat_png(unsigned char *addr, struct PNG_IDAT_FILE_STRUCT *png_data, unsigned long offset); diff --git a/src/compress_util.c b/src/compress_util.c new file mode 100644 index 0000000..9407c8a --- /dev/null +++ b/src/compress_util.c @@ -0,0 +1,132 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> +#include "compress_util.h" + +#define CHUNK 1024 + +/* + * Built from exmaple provided in: https://zlib.net/zlib_how.html +*/ +void zlib_decompress_data(unsigned char *data_chunk, size_t file_length, unsigned char **buff, size_t *sz) { + int ret; + unsigned int have; + z_stream strm; + // Adding one to zero here + unsigned char out[CHUNK]; + unsigned char in[CHUNK]; + + errno=0; + FILE *data_stream = fmemopen(data_chunk, file_length, "r"); + FILE *of = open_memstream((char**)buff, sz); + if(data_stream == NULL) { + perror("F MEM OPEN"); + } + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if(ret != Z_OK) { + return; + } + + do { + strm.avail_in = fread(in, 1, CHUNK, data_stream); + if(ferror(data_stream)) { + (void)inflateEnd(&strm); + return; + } + if(strm.avail_in == 0) { + break; + } + strm.next_in = in; + + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); + switch(ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + printf("Error: %d\n", ret); + printf("MSG: %s\n", (char*)strm.msg); + return; + } + have = CHUNK - strm.avail_out; + fwrite(out, 1, have, of); + } while(strm.avail_out == 0); + } while(ret != Z_STREAM_END); + + (void)inflateEnd(&strm); + + fclose(data_stream); + fclose(of); +} + +/* + * Built from exmaple provided in: https://zlib.net/zlib_how.html +*/ +void zlib_compress_data(unsigned char *data_chunk, size_t file_length, unsigned char **buff, size_t *sz) { + int ret, flush; + unsigned int have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + int level = 9; + int method = Z_DEFLATED; + int windowBits = 10; + int memLevel = 9; + //int strategy = Z_DEFAULT_STRATEGY; + int strategy = Z_FILTERED; + + FILE *data_stream = fmemopen(data_chunk, file_length, "r"); + FILE *out_data_stream = NULL; + out_data_stream = open_memstream((char**)buff, sz); + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy); + if (ret != Z_OK) { + return; + } + + do { + strm.avail_in = fread(in, 1, CHUNK, data_stream); + if (ferror(data_stream)) { + (void)deflateEnd(&strm); + return; + } + flush = feof(data_stream) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + do { + strm.avail_out = CHUNK; + strm.next_out = out; + + ret = deflate(&strm, flush); + assert(ret != Z_STREAM_ERROR); + have = CHUNK - strm.avail_out; + if(fwrite(out, 1, have, out_data_stream) != have || ferror(out_data_stream)) { + (void)deflateEnd(&strm); + return; + } + } while(strm.avail_out == 0); + assert(strm.avail_in == 0); + + } while(flush != Z_FINISH); + assert(ret == Z_STREAM_END); + + fclose(data_stream); + fclose(out_data_stream); + + (void)deflateEnd(&strm); +} diff --git a/src/crc_util.c b/src/crc_util.c new file mode 100644 index 0000000..2b99d11 --- /dev/null +++ b/src/crc_util.c @@ -0,0 +1,92 @@ +#include <stdio.h> +#include <stdlib.h> +#include "crc_util.h" + +const long png_signature[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; + +int check_header_length(unsigned char *addr, long offset) { + unsigned int res = 0; + for( int i = 0; i < 4; i++ ) { + res |= addr[offset+i]; + if (i < 3) { + res <<= 8; + } + } + return res; +} + +int check_file_header(char *addr) { + int signature_match = 0; + for( int i = 0; i < 8; i++ ) { + if (addr[i] != png_signature[i]) { + signature_match = 1; + } + } + printf("Sig Match: %d\n", signature_match); + return signature_match; + +} + +void populate_idat_png(unsigned char *addr, struct PNG_IDAT_FILE_STRUCT *png_data, unsigned long offset) { + unsigned long cur_idat_length = 0; + for(int i = 0; i < 4; i++){ + png_data->idat_length[i] = addr[i+offset]; + } + + for(int i = 0; i < 4; i++){ + cur_idat_length += (png_data->idat_length[i] << (24-(8*i))); + } + + for(int i = 0; i < 4; i++){ + png_data->idat_header[i] = addr[i+offset+4]; + } +} + +void populate_start_png(unsigned char *addr, struct PNG_START_FILE_STRUCT *png_data) { + union{ + unsigned char *data; + struct PNG_START_FILE_STRUCT *png_data; + }png; + + png.png_data = png_data; + + for(int i = 0; i < sizeof(struct PNG_START_FILE_STRUCT); i++) { + png.data[i] = addr[i]; + } +} + +int create_cc_file(unsigned char *addr, unsigned long file_length) { + FILE *fp; + fp = fopen("png2.png", "w"); + + if(fp == NULL) { + return EXIT_FAILURE; + } + + for(int i = 0; i < file_length; i++){ + fputc(addr[i], fp); + } + fclose(fp); + return 0; +} + +unsigned char* file_to_char_array(FILE *in_file, size_t* size) { + unsigned int c; + unsigned long file_data_cap = 8; + unsigned char* file_data = calloc(file_data_cap, sizeof(unsigned char)); + + for(size_t i = 0;(c = fgetc(in_file)) != EOF; i++) { + if(i == file_data_cap) { + file_data_cap *= 2; + file_data = reallocarray(file_data, file_data_cap, sizeof(unsigned char)); + if(file_data == NULL) { + perror("FAILED ARRAY RESIZE"); + return NULL; + } + } + file_data[i] = c; + *size += 1; + } + return file_data; +} + |