busybox/coreutils/md5_sha1_sum.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 *  Copyright (C) 2003 Glenn L. McGrath
   4 *  Copyright (C) 2003-2004 Erik Andersen
   5 *
   6 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
   7 */
   8
   9#include "libbb.h"
  10
  11typedef enum { HASH_SHA1, HASH_MD5 } hash_algo_t;
  12
  13#define FLAG_SILENT     1
  14#define FLAG_CHECK      2
  15#define FLAG_WARN       4
  16
  17/* This might be useful elsewhere */
  18static unsigned char *hash_bin_to_hex(unsigned char *hash_value,
  19                                unsigned hash_length)
  20{
  21        /* xzalloc zero-terminates */
  22        char *hex_value = xzalloc((hash_length * 2) + 1);
  23        bin2hex(hex_value, (char*)hash_value, hash_length);
  24        return (unsigned char *)hex_value;
  25}
  26
  27static uint8_t *hash_file(const char *filename, hash_algo_t hash_algo)
  28{
  29        int src_fd, hash_len, count;
  30        union _ctx_ {
  31                sha1_ctx_t sha1;
  32                md5_ctx_t md5;
  33        } context;
  34        uint8_t *hash_value = NULL;
  35        RESERVE_CONFIG_UBUFFER(in_buf, 4096);
  36        void FAST_FUNC (*update)(const void*, size_t, void*);
  37        void FAST_FUNC (*final)(void*, void*);
  38
  39        src_fd = open_or_warn_stdin(filename);
  40        if (src_fd < 0) {
  41                return NULL;
  42        }
  43
  44        /* figure specific hash algorithims */
  45        if (ENABLE_MD5SUM && hash_algo==HASH_MD5) {
  46                md5_begin(&context.md5);
  47                update = (void*)md5_hash;
  48                final = (void*)md5_end;
  49                hash_len = 16;
  50        } else if (ENABLE_SHA1SUM && hash_algo==HASH_SHA1) {
  51                sha1_begin(&context.sha1);
  52                update = (void*)sha1_hash;
  53                final = (void*)sha1_end;
  54                hash_len = 20;
  55        } else {
  56                bb_error_msg_and_die("algorithm not supported");
  57        }
  58
  59        while (0 < (count = safe_read(src_fd, in_buf, 4096))) {
  60                update(in_buf, count, &context);
  61        }
  62
  63        if (count == 0) {
  64                final(in_buf, &context);
  65                hash_value = hash_bin_to_hex(in_buf, hash_len);
  66        }
  67
  68        RELEASE_CONFIG_BUFFER(in_buf);
  69
  70        if (src_fd != STDIN_FILENO) {
  71                close(src_fd);
  72        }
  73
  74        return hash_value;
  75}
  76
  77int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  78int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv)
  79{
  80        int return_value = EXIT_SUCCESS;
  81        uint8_t *hash_value;
  82        unsigned flags;
  83        hash_algo_t hash_algo = ENABLE_MD5SUM
  84                ? (ENABLE_SHA1SUM ? (applet_name[0] == 'm' ? HASH_MD5 : HASH_SHA1) : HASH_MD5)
  85                : HASH_SHA1;
  86
  87        if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK)
  88                flags = getopt32(argv, "scw");
  89        else optind = 1;
  90        argv += optind;
  91        //argc -= optind;
  92        if (!*argv)
  93                *--argv = (char*)"-";
  94
  95        if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) {
  96                if (flags & FLAG_SILENT) {
  97                        bb_error_msg_and_die
  98                                ("-%c is meaningful only when verifying checksums", 's');
  99                } else if (flags & FLAG_WARN) {
 100                        bb_error_msg_and_die
 101                                ("-%c is meaningful only when verifying checksums", 'w');
 102                }
 103        }
 104
 105        if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) {
 106                FILE *pre_computed_stream;
 107                int count_total = 0;
 108                int count_failed = 0;
 109                char *line;
 110
 111                if (argv[1]) {
 112                        bb_error_msg_and_die
 113                                ("only one argument may be specified when using -c");
 114                }
 115
 116                pre_computed_stream = xfopen_stdin(argv[0]);
 117
 118                while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) {
 119                        char *filename_ptr;
 120
 121                        count_total++;
 122                        filename_ptr = strstr(line, "  ");
 123                        /* handle format for binary checksums */
 124                        if (filename_ptr == NULL) {
 125                                filename_ptr = strstr(line, " *");
 126                        }
 127                        if (filename_ptr == NULL) {
 128                                if (flags & FLAG_WARN) {
 129                                        bb_error_msg("invalid format");
 130                                }
 131                                count_failed++;
 132                                return_value = EXIT_FAILURE;
 133                                free(line);
 134                                continue;
 135                        }
 136                        *filename_ptr = '\0';
 137                        filename_ptr += 2;
 138
 139                        hash_value = hash_file(filename_ptr, hash_algo);
 140
 141                        if (hash_value && (strcmp((char*)hash_value, line) == 0)) {
 142                                if (!(flags & FLAG_SILENT))
 143                                        printf("%s: OK\n", filename_ptr);
 144                        } else {
 145                                if (!(flags & FLAG_SILENT))
 146                                        printf("%s: FAILED\n", filename_ptr);
 147                                count_failed++;
 148                                return_value = EXIT_FAILURE;
 149                        }
 150                        /* possible free(NULL) */
 151                        free(hash_value);
 152                        free(line);
 153                }
 154                if (count_failed && !(flags & FLAG_SILENT)) {
 155                        bb_error_msg("WARNING: %d of %d computed checksums did NOT match",
 156                                                 count_failed, count_total);
 157                }
 158                /*
 159                if (fclose_if_not_stdin(pre_computed_stream) == EOF) {
 160                        bb_perror_msg_and_die("cannot close file %s", file_ptr);
 161                }
 162                */
 163        } else {
 164                do {
 165                        hash_value = hash_file(*argv, hash_algo);
 166                        if (hash_value == NULL) {
 167                                return_value = EXIT_FAILURE;
 168                        } else {
 169                                printf("%s  %s\n", hash_value, *argv);
 170                                free(hash_value);
 171                        }
 172                } while (*++argv);
 173        }
 174        return return_value;
 175}
 176