diff --git a/includes/ft_ssl.h b/includes/ft_ssl.h index a2afb62..dc1fc32 100644 --- a/includes/ft_ssl.h +++ b/includes/ft_ssl.h @@ -15,5 +15,6 @@ struct ssl_config }; enum cli_code cli_parse_arguments(int argc, char **argv, struct ssl_config *config); +int ssl_run(const struct ssl_config *config); #endif diff --git a/includes/internal/ssl/ssl.h b/includes/internal/ssl/ssl.h new file mode 100644 index 0000000..d5b4722 --- /dev/null +++ b/includes/internal/ssl/ssl.h @@ -0,0 +1,19 @@ +#ifndef FT_SSL_SSL_H +#define FT_SSL_SSL_H + +#include + +#include "ft_ssl.h" + +#define MAX_DIGEST_SIZE 64 +#define READ_BUFSIZE 4096 + +int run_string(const struct ssl_config *config); +int run_file(const struct ssl_config *config, const char *path); +int run_stdin(const struct ssl_config *config); +int digest_stream(const struct ssl_config *config, int fd, + const char *label, int show_algo, int echo); +void print_digest(const struct ssl_config *config, const uint8_t *digest, + const char *label, int show_algo); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 3ee173d..2d348e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,12 @@ FORCE: ft_ssl_SOURCES = \ main.c \ + ssl_run.c \ + ssl/run_stdin.c \ + ssl/run_string.c \ + ssl/run_file.c \ + ssl/digest.c \ + ssl/output.c \ cli/parse.c \ cli/handlers/option_map.c \ cli/handlers/handle_help.c \ diff --git a/src/main.c b/src/main.c index 42f8be3..502588f 100644 --- a/src/main.c +++ b/src/main.c @@ -17,10 +17,7 @@ main(int argc, char **argv) ret = cli_parse_arguments(argc, argv, &config); if (CLI_SUCCESS != ret) goto cleanup; - - /* TODO: - * ret = ssl_run(&config); - */ + ret = ssl_run(&config); cleanup: return (CLI_ERROR == ret) ? 2 : EXIT_SUCCESS; diff --git a/src/ssl/digest.c b/src/ssl/digest.c new file mode 100644 index 0000000..0065bce --- /dev/null +++ b/src/ssl/digest.c @@ -0,0 +1,40 @@ +#include + +#include +#include + +#include "ft_ssl.h" +#include "internal/ssl/ssl.h" + +/* Forward declarations */ +static void process_chunk(const struct ssl_config *config, union digest_ctx *ctx, + const uint8_t *buf, size_t n, int echo); +/* ------------------- */ + +int +digest_stream(const struct ssl_config *config, int fd, + const char *label, int show_algo, int echo) +{ + union digest_ctx ctx; + uint8_t buf[READ_BUFSIZE]; + uint8_t digest[MAX_DIGEST_SIZE]; + ssize_t n; + + config->algo->init(&ctx); + while (0 < (n = read(fd, buf, sizeof(buf)))) + process_chunk(config, &ctx, buf, (size_t)n, echo); + if (0 > n) + return CLI_ERROR; + config->algo->final(&ctx, digest); + print_digest(config, digest, label, show_algo); + return CLI_SUCCESS; +} + +static void +process_chunk(const struct ssl_config *config, union digest_ctx *ctx, + const uint8_t *buf, size_t n, int echo) +{ + if (echo) + (void)write(STDOUT_FILENO, buf, n); + config->algo->update(ctx, buf, n); +} diff --git a/src/ssl/output.c b/src/ssl/output.c new file mode 100644 index 0000000..bf04b8f --- /dev/null +++ b/src/ssl/output.c @@ -0,0 +1,109 @@ +#include +#include + +#include + +#include "compiler.h" +#include "ft_ssl.h" +#include "ft_ssl_flags.h" +#include "internal/ssl/ssl.h" + +enum fmt_mode +{ + FMT_STDIN, + FMT_DEFAULT, + FMT_QUIET, + FMT_REVERSE, +}; + +typedef void (*t_formatter)(const char *hex, const char *name_upper, + const char *label); + +/* Forward declarations */ +static enum fmt_mode resolve_fmt(const struct ssl_config *config, + int show_algo); +static void build_hex(char *buf, const uint8_t *digest, size_t size); +static void build_upper(char *buf, const char *src, size_t size); +static inline void fmt_stdin(const char *hex, const char *name_upper, + const char *label); +static inline void fmt_default(const char *hex, const char *name_upper, + const char *label); +static inline void fmt_quiet(const char *hex, const char *name_upper, + const char *label); +static inline void fmt_reverse(const char *hex, const char *name_upper, + const char *label); +/* ------------------- */ + +static const t_formatter s_formatters[] = { + [FMT_STDIN] = fmt_stdin, + [FMT_DEFAULT] = fmt_default, + [FMT_QUIET] = fmt_quiet, + [FMT_REVERSE] = fmt_reverse, +}; + +void +print_digest(const struct ssl_config *config, const uint8_t *digest, + const char *label, int show_algo) +{ + char hex[MAX_DIGEST_SIZE * 2 + 1]; + char name_upper[32]; + + build_hex(hex, digest, config->algo->digest_size); + build_upper(name_upper, config->algo->name, sizeof(name_upper)); + s_formatters[resolve_fmt(config, show_algo)](hex, name_upper, label); +} + +static enum fmt_mode +resolve_fmt(const struct ssl_config *config, int show_algo) +{ + if (HAS_FLAG(config->flags, FLAG_Q)) + return FMT_QUIET; + if (HAS_FLAG(config->flags, FLAG_R)) + return FMT_REVERSE; + return show_algo ? FMT_DEFAULT : FMT_STDIN; +} + +static void +build_hex(char *buf, const uint8_t *digest, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + (void)snprintf(buf + i * 2, 3, "%02x", (unsigned int)digest[i]); +} + +static void +build_upper(char *buf, const char *src, size_t size) +{ + size_t i; + + for (i = 0; i + 1 < size && '\0' != src[i]; i++) + buf[i] = (char)toupper((unsigned char)src[i]); + buf[i] = '\0'; +} + +static inline void +fmt_stdin(const char *hex, __unused const char *name_upper, const char *label) +{ + printf("(%s)= %s\n", label, hex); +} + +static inline void +fmt_default(const char *hex, const char *name_upper, const char *label) +{ + printf("%s (%s) = %s\n", name_upper, label, hex); +} + +static inline void +fmt_quiet(const char *hex, __unused const char *name_upper, + __unused const char *label) +{ + printf("%s\n", hex); +} + +static inline void +fmt_reverse(const char *hex, __unused const char *name_upper, + const char *label) +{ + printf("%s %s\n", hex, label); +} diff --git a/src/ssl/run_file.c b/src/ssl/run_file.c new file mode 100644 index 0000000..6227d75 --- /dev/null +++ b/src/ssl/run_file.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +#include + +#include "ft_ssl.h" +#include "internal/ssl/ssl.h" +#include "version_gen.h" + +int +run_file(const struct ssl_config *config, const char *path) +{ + int fd; + int ret; + + fd = open(path, O_RDONLY); + if (0 > fd) + { + fprintf(stderr, "%s: %s: %s\n", g_prog_name, path, strerror(errno)); + return CLI_ERROR; + } + ret = digest_stream(config, fd, path, 1, 0); + close(fd); + return ret; +} diff --git a/src/ssl/run_stdin.c b/src/ssl/run_stdin.c new file mode 100644 index 0000000..d2ba904 --- /dev/null +++ b/src/ssl/run_stdin.c @@ -0,0 +1,15 @@ +#include + +#include + +#include "compiler.h" +#include "ft_ssl.h" +#include "ft_ssl_flags.h" +#include "internal/ssl/ssl.h" + +int +run_stdin(const struct ssl_config *config) +{ + return digest_stream(config, STDIN_FILENO, "stdin", 0, + HAS_FLAG(config->flags, FLAG_P)); +} diff --git a/src/ssl/run_string.c b/src/ssl/run_string.c new file mode 100644 index 0000000..bc1e7bd --- /dev/null +++ b/src/ssl/run_string.c @@ -0,0 +1,24 @@ +#include +#include + +#include +#include + +#include "ft_ssl.h" +#include "internal/ssl/ssl.h" + +int +run_string(const struct ssl_config *config) +{ + union digest_ctx ctx; + uint8_t digest[MAX_DIGEST_SIZE]; + char label[4096]; + + config->algo->init(&ctx); + config->algo->update(&ctx, (const uint8_t *)config->string, + strlen(config->string)); + config->algo->final(&ctx, digest); + (void)snprintf(label, sizeof(label), "\"%s\"", config->string); + print_digest(config, digest, label, 1); + return CLI_SUCCESS; +} diff --git a/src/ssl_run.c b/src/ssl_run.c new file mode 100644 index 0000000..d63d507 --- /dev/null +++ b/src/ssl_run.c @@ -0,0 +1,56 @@ +#include + +#include +#include + +#include "compiler.h" +#include "ft_ssl.h" +#include "ft_ssl_flags.h" +#include "internal/ssl/ssl.h" +#include "version_gen.h" + +/* Forward declarations */ +static int check_algo(const struct ssl_config *config); +static inline void update_ret(int *ret, int result); +/* ------------------- */ + +int +ssl_run(const struct ssl_config *config) +{ + int ret; + int has_input; + int i; + + if (CLI_SUCCESS != check_algo(config)) + return CLI_ERROR; + ret = CLI_SUCCESS; + has_input = (NULL != config->string || 0 < config->nb_files); + if (HAS_FLAG(config->flags, FLAG_P) || !has_input) + update_ret(&ret, run_stdin(config)); + if (NULL != config->string) + update_ret(&ret, run_string(config)); + for (i = 0; i < config->nb_files; i++) + update_ret(&ret, run_file(config, config->files[i])); + return ret; +} + +static int +check_algo(const struct ssl_config *config) +{ + if (NULL == config->algo->init + || NULL == config->algo->update + || NULL == config->algo->final) + { + fprintf(stderr, "%s: %s: not yet implemented\n", + g_prog_name, config->algo->name); + return CLI_ERROR; + } + return CLI_SUCCESS; +} + +static inline void +update_ret(int *ret, int result) +{ + if (CLI_ERROR == result) + *ret = CLI_ERROR; +}