From a75454703e80556bd2d83ff97cf90bdb02b023ae Mon Sep 17 00:00:00 2001 From: "tanguy.cavagna" <tanguy.cavagna@etu.hesge.ch> Date: Tue, 13 Sep 2022 20:13:27 +0200 Subject: [PATCH] Finished standalone. Need make lib --- Makefile | 20 ++++------ digest/digest.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ digest/digest.h | 22 +++++++++++ main.c | 70 ++++++++++++++++++++++++++++++++-- options/opt.c | 63 +++++++++++++++++++++++++++++++ options/opt.h | 38 +++++++++++++++++++ 6 files changed, 297 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index bd18374..64348f9 100644 --- a/Makefile +++ b/Makefile @@ -8,28 +8,24 @@ LIBS = -lssl -lcrypto BIN = bin # Get source and object -SRCS = $(filter-out $(wildcard mdtest.c), $(wildcard *.c */*.c)) +SRCS = $(filter-out mdtest.c, $(wildcard *.c */*.c)) OBJS = $(addprefix $(BIN)/, $(SRCS:.c=.o)) -SRCS_TEST = $(filter-out $(wildcard main.c */main.c gfx/*), $(wildcard *.c */*.c)) -OBJS_TEST = $(addprefix $(BIN)/, $(SRCS_TEST:.c=.o)) + +.PHONY: digest libdigest all clean # Create the target -main: $(OBJS) - $(CC) $(CFLAGS) -o $(BIN)/$@ $^ $(LIBS) $(LDFLAGS) - ./$(BIN)/$@ $(ARGS) +digest: $(OBJS) + $(CC) $(CFLAGS) -o $(BIN)/digest $(addprefix $(BIN)/, $(notdir $^)) $(LIBS) $(LDFLAGS) -# Convert the source in object, but before all, run `$(BIN)` aka mkdir +# Convert the source in object $(BIN)/%.o: %.c - mkdir -p $(@D) - $(CC) $(CFLAGS) -o $@ -c $< $(LDFLAGS) + mkdir -p $(BIN) + $(CC) $(CFLAGS) -o $(BIN)/$(notdir $@) -c $< $(LDFLAGS) # Echo the source and object values help: @echo "src: $(SRCS)" @echo "obj: $(OBJS)" - @echo "obj_test: $(OBJ_TEST)" clean: rm -rf $(BIN) - -.PHONY: test-draw help clean main diff --git a/digest/digest.c b/digest/digest.c index e69de29..3c19f31 100644 --- a/digest/digest.c +++ b/digest/digest.c @@ -0,0 +1,99 @@ +#include "digest.h" + +#define BUF_MAXSIZE 4096 + +//========================= +// PRIVATE +//========================= + +/** + * @brief Stringify the given bytes digest + * + * @param md_len + * @param md_value + * @return char* + */ +static char *stringify_digest(unsigned int md_len, unsigned char md_value[]) { + size_t hexlen = 2; + size_t outdigestlen = md_len * hexlen; + + char *digest = malloc(outdigestlen + 1); + char *hex = digest; + + for (size_t i = 0; i < md_len; i++) { + hex += sprintf(hex, "%02x", md_value[i]); + } + + return digest; +} + +/** + * @brief Initialize the EVP context + * + * @param digest_method + * @return EVP_MD_CTX* + */ +EVP_MD_CTX *EVP_context_init(char *digest_method) { + EVP_MD_CTX *mdctx; + const EVP_MD *md; + + if (digest_method == NULL) { + fprintf(stderr, "Digest method not provided.\n"); + exit(ENOMSG); + } + + md = EVP_get_digestbyname(digest_method); + if (md == NULL) { + fprintf(stderr, "Digest method not found.\n"); + exit(ENOPROTOOPT); + } + + mdctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex2(mdctx, md, NULL); + + return mdctx; +} + +//========================= +// PUBLIC +//========================= + +char *str_digest(char *foo, char *digest_method) { + EVP_MD_CTX *mdctx = EVP_context_init(digest_method); + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; + + EVP_DigestUpdate(mdctx, foo, strlen(foo)); + EVP_DigestFinal_ex(mdctx, md_value, &md_len); + EVP_MD_CTX_free(mdctx); + + return stringify_digest(md_len, md_value); +} + +char *file_digest(char *filename, char *digest_method) { + EVP_MD_CTX *mdctx = EVP_context_init(digest_method); + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; + + FILE *f; + char buf[BUF_MAXSIZE]; + + // case of STDIN + if (filename == NULL) { + f = stdin; + } else { + if ((f = fopen(filename, "r")) == NULL) { + perror(filename); + exit(ENOENT); + } + } + + while (fgets(buf, BUF_MAXSIZE, f) != NULL) { + EVP_DigestUpdate(mdctx, buf, strlen(buf)); + } + + EVP_DigestFinal_ex(mdctx, md_value, &md_len); + EVP_MD_CTX_free(mdctx); + + return stringify_digest(md_len, md_value); +} diff --git a/digest/digest.h b/digest/digest.h index cb35c12..815f112 100644 --- a/digest/digest.h +++ b/digest/digest.h @@ -1,4 +1,26 @@ #ifndef DIGEST_H #define DIGEST_H +#include <errno.h> +#include <openssl/evp.h> +#include <string.h> + +/** + * @brief Make the digest of the given string + * + * @param foo + * @param digest_method + * @return char* + */ +char *str_digest(char *foo, char *digest_method); + +/** + * @brief Make the digest of the given file + * + * @param filename If null, read STDIN + * @param digest_method + * @return char* + */ +char *file_digest(char *filename, char *digest_method); + #endif // DIGEST_H diff --git a/main.c b/main.c index b24433f..e57b25b 100644 --- a/main.c +++ b/main.c @@ -1,15 +1,79 @@ #include <errno.h> #include <stdio.h> #include <stdlib.h> -#include <unistd.h> #include "digest/digest.h" #include "options/opt.h" +/** + * @brief Join an array of string + * @see https://stackoverflow.com/a/4681415 + * + * @param foo + * @param count + * @return char* + */ +char *join(char *foo[], int count) { + char *out = NULL; + size_t total_len = 0; + + for (int i = 0; i < count; i++) + total_len += strlen(foo[i]); + total_len += count - 1; // seperator + total_len++; // string terminator + + out = malloc(total_len); + out[0] = '\0'; + + for (int i = 0; i < count; i++) { + strcat(out, foo[i]); + if (i < (count - 1)) + strcat(out, " "); + } + + return out; +} + int main(int argc, char *argv[]) { - for (int i = 1; i < argc; i++) { - printf("%s\n", argv[i]); + opt *opts = verify_options(argc, argv); + char *digest; + + switch (opts->flag) { + case W_FLAG: + for (int i = 0; i < opts->extra_count; i++) { + digest = str_digest(opts->extra[i], opts->digest_method); + + printf("%s\t%s\n", digest, opts->extra[i]); + free(digest); + } + break; + + case F_FLAG: + for (int i = 0; i < opts->extra_count; i++) { + digest = file_digest(opts->extra[i], opts->digest_method); + + printf("%s\t%s\n", digest, opts->extra[i]); + free(digest); + } + break; + + case S_FLAG: + digest = file_digest(NULL, opts->digest_method); + + printf("%s\n", digest); + free(digest); + break; + + default: + char *foo = join(opts->extra, opts->extra_count); + digest = str_digest(foo, opts->digest_method); + + printf("%s\t%s\n", digest, foo); + free(digest); + break; } + discard_options(opts); + exit(EXIT_SUCCESS); } diff --git a/options/opt.c b/options/opt.c index e69de29..1d96720 100644 --- a/options/opt.c +++ b/options/opt.c @@ -0,0 +1,63 @@ +#include "opt.h" + +//========================= +// PUBLIC +//========================= + +opt *verify_options(int argc, char *argv[]) { + int option; + opt *verified = malloc(sizeof(opt)); + verified->flag = 0; + verified->digest_method = NULL; + + while ((option = getopt(argc, argv, "wfst:")) != -1) { + // Argument list too long + if (verified->flag != 0 && option != 't') { + printf("Cannot choose mulitple options.\n"); + exit(E2BIG); + } + + switch (option) { + case 'w': + verified->flag = 1 << 0; + break; + + case 'f': + verified->flag = 1 << 1; + break; + + case 's': + verified->flag = 1 << 2; + break; + + case 't': + // optarg hold the value of the current option + verified->digest_method = optarg; + break; + + // Invalid argument + default: + exit(EINVAL); + break; + } + } + + if (verified->digest_method == NULL) { + verified->digest_method = "SHA1"; + } + + verified->extra_count = argc - optind; + verified->extra = malloc(sizeof(char *) * verified->extra_count); + // optind not found in vscode, but the variable simply store the index + // of the first non-argument term passed to the arguments list. + for (int i = optind; i < argc; i++) { + verified->extra[i - optind] = argv[i]; + } + + return verified; +} + +void discard_options(opt *o) { + free(o->extra); + free(o); +} diff --git a/options/opt.h b/options/opt.h index 7bc9baf..c858e38 100644 --- a/options/opt.h +++ b/options/opt.h @@ -1,4 +1,42 @@ #ifndef OPT_H #define OPT_H +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#define W_FLAG 1 << 0 +#define F_FLAG 1 << 1 +#define S_FLAG 1 << 2 + +typedef struct _opt { + char flag; + char **extra; + int extra_count; + char *digest_method; // default SHA1 +} opt; + +/** + * @brief Verify passed options, and returns the corresponding flag. + * + * -w : 0x1 + * -f : 0x2 + * -s : 0x4 + * + * other : error + * + * @param argc + * @param argv + * @return opt + */ +opt *verify_options(int argc, char *argv[]); + +/** + * @brief Discard the given options + * + * @param o + */ +void discard_options(opt *o); + #endif // OPT_H -- GitLab