diff --git a/Implementierung/Makefile b/Implementierung/Makefile index 1c7ed9f..843d95b 100644 --- a/Implementierung/Makefile +++ b/Implementierung/Makefile @@ -1,6 +1,6 @@ -SRC = src/main.c src/helper.c src/io.c src/md2.c src/md2_impls/md2_common.c src/md2_impls/md2_0.c +SRC = src/main.c src/helper.c src/io.c src/md2.c src/md2_impls/md2_common.c src/md2_impls/md2_0.c src/md2_impls/md2_2.c OBJ = ${subst src,build,${SRC:.c=.o}} CC = gcc CFLAGS = -Ilib -ggdb -std=c11 -g -Wall -Wextra -no-pie -O3 diff --git a/Implementierung/lib/io.h b/Implementierung/lib/io.h index f780a77..6887f25 100644 --- a/Implementierung/lib/io.h +++ b/Implementierung/lib/io.h @@ -10,6 +10,17 @@ #include #include +/** + * @brief Open a file and load its stats + * + * @param path the filepath + * @param file where the pointer of the file handle should be stored + * @param file_stat pointer to a stat struct + * @return true it worked + * @return false there was an error + */ +bool open_file(const char* path, FILE** file, struct stat* file_stat); + /** * @brief reads a file at a path * diff --git a/Implementierung/lib/md2_impls/md2_2.h b/Implementierung/lib/md2_impls/md2_2.h new file mode 100644 index 0000000..4e64689 --- /dev/null +++ b/Implementierung/lib/md2_impls/md2_2.h @@ -0,0 +1,23 @@ +#ifndef MD2_2_H +#define MD2_2_H + +#include +#include +#include +#include +#include +#include + +#include "../io.h" + +/** + * @brief This implementation loads the file in bits and not at once + * + * @param _ unused + * @param filename name of the file to load + * @param out + */ +void md2_hash_2(size_t len, const uint8_t buf[len], uint8_t out[16]); +void md2_checksum_2(size_t len, uint8_t* buf); + +#endif // MD2_2_H \ No newline at end of file diff --git a/Implementierung/src/io.c b/Implementierung/src/io.c index dedb5ce..339bd75 100644 --- a/Implementierung/src/io.c +++ b/Implementierung/src/io.c @@ -1,26 +1,35 @@ #include "../lib/io.h" +bool open_file(const char* path, FILE** file, struct stat* file_stat) { + (*file) = fopen(path, "r"); + if ((*file) == NULL) { + if (errno == 0) errno = EIO; + return false; + } + + int status = fstat(fileno((*file)), file_stat); + if (status == -1) { + if (errno == 0) errno = EIO; + fclose((*file)); + return false; + }; + + if ((file_stat->st_mode & S_IFMT) != S_IFREG) { + printf("File is not a regular file!\n"); + errno = ENOENT; + fclose((*file)); + return false; + } + + return true; +} + uint8_t* read_file(const char* path, size_t* size) { // Read the contents of the file specified by path into a heap-allocated // buffer and return a pointer to that buffer. - FILE* f = fopen(path, "r"); - if (f == NULL) { - printf("Fopen error: %d\n", errno); - fclose(f); - return NULL; - } - + FILE* f; struct stat statOfFile; - int status = fstat(fileno(f), &statOfFile); - if (status == -1) { - printf("Fstat error: %d\n", errno); - fclose(f); - return NULL; - }; - - if ((statOfFile.st_mode & S_IFMT) != S_IFREG) { - printf("File is not a regular file!\n"); - fclose(f); + if (!open_file(path, &f, &statOfFile)) { return NULL; } @@ -30,8 +39,8 @@ uint8_t* read_file(const char* path, size_t* size) { fread(data, statOfFile.st_blksize, statOfFile.st_blocks, f); // size_t bytesRead = fread(data, sizeof(uint8_t), statOfFile.st_size, f); if (bytesRead != 0 && !feof(f)) { - printf("Error reading file!\n"); fclose(f); + if (errno == 0) errno = EIO; return NULL; } diff --git a/Implementierung/src/main.c b/Implementierung/src/main.c index 9bdb675..42b8e6f 100644 --- a/Implementierung/src/main.c +++ b/Implementierung/src/main.c @@ -62,6 +62,43 @@ unsigned runTests(struct configuration* c) { return failed; } +bool calculate_hash(struct configuration c, char* hash) { + size_t len; + uint8_t* data; + + if (c.implementationToUse != 2) { + data = read_file(c.filename, &len); + } else { + data = (uint8_t*)c.filename; + len = 0; + } + + if (data == NULL) { + printf("Error reading file %s!\n", c.filename); + return false; + } + + errno = 0; + uint8_t out[16]; + if (c.doBenchmark) { + double duration = + run_benchmark(c.benchmarkingCycles, md2_hash, len, data, out); + printf("Running %d cycles took %f seconds\n", c.benchmarkingCycles, + duration); + } else { + md2_hash(len, data, out); + } + + if (errno != 0) { + return false; + } + + md2_encode_hash(out, hash); + + if (c.implementationToUse != 2) free(data); + return true; +} + int main(int argc, char** argv) { struct configuration c; enum argumentParseResult result = parseArguments(argc, argv, &c); @@ -87,33 +124,27 @@ int main(int argc, char** argv) { "benchmark cycles: %d\n", c.implementationToUse, c.doBenchmark, c.benchmarkingCycles); + if (c.runTests && c.implementationToUse == 2) { + fprintf(stderr, "Cannot run tests on implementation 2!\n"); + return EXIT_FAILURE; + } + if (c.runTests) { printf("Running tests...\n\n"); return runTests(&c); } printf("Hashing file %s...\n\n", c.filename); - size_t len; - uint8_t* data = read_file(c.filename, &len); - if (data == NULL) { - printf("Error reading file %s!", c.filename); + + char hash[32]; + if (!calculate_hash(c, hash)) { + if (errno != 0) { + fprintf(stderr, "\n\033[0;31mAn error occured: %s\033[0m\n", + strerror(errno)); + } return EXIT_FAILURE; } - - uint8_t out[16]; - char hash[32]; - if (c.doBenchmark) { - double duration = - run_benchmark(c.benchmarkingCycles, md2_hash, len, data, out); - printf("Running %d cycles took %f seconds\n", c.benchmarkingCycles, - duration); - } else { - md2_hash(len, data, out); - } - md2_encode_hash(out, hash); printf("Hash: %s\n", hash); - free(data); - - return 0; + return EXIT_SUCCESS; } diff --git a/Implementierung/src/md2.c b/Implementierung/src/md2.c index 8be67f4..da49453 100644 --- a/Implementierung/src/md2.c +++ b/Implementierung/src/md2.c @@ -2,6 +2,7 @@ // include all implementations #include "../lib/md2_impls/md2_0.h" +#include "../lib/md2_impls/md2_2.h" md2_hash_func md2_hash; md2_checksum_func md2_checksum; @@ -22,6 +23,11 @@ bool md2_choose_implementation(int i) { md2_checksum = md2_checksum_0; return true; + case 2: + md2_hash = md2_hash_2; + md2_checksum = md2_checksum_2; + return true; + default: return false; } diff --git a/Implementierung/src/md2_impls/md2_2.c b/Implementierung/src/md2_impls/md2_2.c new file mode 100644 index 0000000..1349c0f --- /dev/null +++ b/Implementierung/src/md2_impls/md2_2.c @@ -0,0 +1,89 @@ +#include "../../lib/md2_impls/md2_2.h" + +#include "../../lib/md2_impls/md2_common.h" + +void process_block_hash(uint8_t block[16], uint8_t messageDigestBuf[48]) { + for (int j = 0; j < 16; j++) { + messageDigestBuf[16 + j] = block[j]; + messageDigestBuf[32 + j] = (messageDigestBuf[16 + j] ^ messageDigestBuf[j]); + } + + u_int8_t t = 0; + + for (int j = 0; j < 18; j++) { + for (int k = 0; k < 48; k++) { + t = messageDigestBuf[k] = messageDigestBuf[k] ^ MD2_PI_SUBST[t]; + } + t = (t + j) % 256; + } +} + +void process_block_checksum(uint8_t block[16], uint8_t checksum[16], + uint8_t* l) { + for (int j = 0; j < 16; j++) { + u_int8_t c = block[j]; + // reference is wrong. It says: Set C[j] to S[c xor L]. But it should be: + (*l) = checksum[j] ^= MD2_PI_SUBST[c ^ (*l)]; + } +} + +void apply_padding(size_t len, uint8_t buf[16]) { + int paddingNeeded = 16 - (len % 16); + uint8_t originalPadding = paddingNeeded; + len += paddingNeeded; + + while (paddingNeeded > 0) { + buf[len - paddingNeeded] = originalPadding; + paddingNeeded--; + } +} + +// unused! +void md2_checksum_2(size_t, uint8_t*) {} + +void md2_hash_2(size_t len, const uint8_t buf[len], uint8_t out[16]) { + FILE* file; + struct stat file_stat; + if (!open_file((char*)buf, &file, &file_stat)) { + return; + } + + // === step 3 === + uint8_t* messageDigestBuf = calloc(48, sizeof(uint8_t)); + + // === step 4 === + uint8_t l = 0; + uint8_t* checksum = calloc(16, sizeof(uint8_t)); + + uint8_t* data = malloc(16); + size_t bytes_left_to_read = file_stat.st_size; + size_t bytes_left_to_process = 0; + + while (bytes_left_to_read != 0) { + bytes_left_to_process = bytes_left_to_read >= 16 ? 16 : bytes_left_to_read; + + fread(data, 1, bytes_left_to_process, file); + if (ferror(file) || feof(file)) { + if (errno == 0) errno = EIO; + return; + } + + process_block_checksum(data, checksum, &l); + process_block_hash(data, messageDigestBuf); + + bytes_left_to_read -= bytes_left_to_process; + }; + + fclose(file); + + apply_padding(bytes_left_to_process % 16, data); + process_block_checksum(data, checksum, &l); + process_block_hash(data, messageDigestBuf); + + process_block_hash(checksum, messageDigestBuf); + memcpy(out, messageDigestBuf, 16); + + free(data); + free(messageDigestBuf); + free(checksum); +}