toybox/toys/lsb/md5sum.c
<<
>>
Prefs
   1/* md5sum.c - Calculate RFC 1321 md5 hash and sha1 hash.
   2 *
   3 * Copyright 2012 Rob Landley <rob@landley.net>
   4 *
   5 * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/md5sum.html
   6 * and http://www.ietf.org/rfc/rfc1321.txt
   7 *
   8 * They're combined this way to share infrastructure, and because md5sum is
   9 * and LSB standard command (but sha1sum and newer hashes are a good idea,
  10 * see http://valerieaurora.org/hash.html).
  11 *
  12 * We optionally use openssl (or equivalent) to access assembly optimized
  13 * versions of these functions, but provide a built-in version to reduce
  14 * required dependencies.
  15 *
  16 * coreutils supports --status but not -s, busybox supports -s but not --status
  17
  18USE_MD5SUM(NEWTOY(md5sum, "bc(check)s(status)[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
  19USE_SHA1SUM(NEWTOY(sha1sum, "bc(check)s(status)[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
  20USE_TOYBOX_LIBCRYPTO(USE_SHA224SUM(OLDTOY(sha224sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
  21USE_TOYBOX_LIBCRYPTO(USE_SHA256SUM(OLDTOY(sha256sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
  22USE_TOYBOX_LIBCRYPTO(USE_SHA384SUM(OLDTOY(sha384sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
  23USE_TOYBOX_LIBCRYPTO(USE_SHA512SUM(OLDTOY(sha512sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
  24
  25config MD5SUM
  26  bool "md5sum"
  27  default y
  28  help
  29    usage: md5sum [-bcs] [FILE]...
  30
  31    Calculate md5 hash for each input file, reading from stdin if none.
  32    Output one hash (32 hex digits) for each input file, followed by filename.
  33
  34    -b  Brief (hash only, no filename)
  35    -c  Check each line of each FILE is the same hash+filename we'd output
  36    -s  No output, exit status 0 if all hashes match, 1 otherwise
  37
  38config SHA1SUM
  39  bool "sha1sum"
  40  default y
  41  help
  42    usage: sha?sum [-bcs] [FILE]...
  43
  44    Calculate sha hash for each input file, reading from stdin if none. Output
  45    one hash (40 hex digits for sha1, 56 for sha224, 64 for sha256, 96 for sha384,
  46    and 128 for sha512) for each input file, followed by filename.
  47
  48    -b  Brief (hash only, no filename)
  49    -c  Check each line of each FILE is the same hash+filename we'd output
  50    -s  No output, exit status 0 if all hashes match, 1 otherwise
  51
  52config SHA224SUM
  53  bool "sha224sum"
  54  default y
  55  depends on TOYBOX_LIBCRYPTO
  56  help
  57    See sha1sum
  58
  59config SHA256SUM
  60  bool "sha256sum"
  61  default y
  62  depends on TOYBOX_LIBCRYPTO
  63  help
  64    See sha1sum
  65
  66config SHA384SUM
  67  bool "sha384sum"
  68  default y
  69  depends on TOYBOX_LIBCRYPTO
  70  help
  71    See sha1sum
  72
  73config SHA512SUM
  74  bool "sha512sum"
  75  default y
  76  depends on TOYBOX_LIBCRYPTO
  77  help
  78    See sha1sum
  79*/
  80
  81#define FORCE_FLAGS
  82#define FOR_md5sum
  83#include "toys.h"
  84
  85#if CFG_TOYBOX_LIBCRYPTO
  86#include <openssl/md5.h>
  87#include <openssl/sha.h>
  88#else
  89typedef int SHA512_CTX;
  90#endif
  91
  92GLOBALS(
  93  int sawline;
  94
  95  unsigned *md5table;
  96  // Crypto variables blanked after summing
  97  unsigned state[5], oldstate[5];
  98  unsigned long long count;
  99  union {
 100    char c[64];
 101    unsigned i[16];
 102  } buffer;
 103)
 104
 105// Static table for when we haven't got floating point support
 106#if ! CFG_TOYBOX_FLOAT
 107static unsigned md5nofloat[64] = {
 108  0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
 109  0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
 110  0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
 111  0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
 112  0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
 113  0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
 114  0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
 115  0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
 116  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
 117  0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
 118  0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
 119};
 120#else
 121#define md5nofloat 0
 122#endif
 123
 124// Mix next 64 bytes of data into md5 hash
 125
 126static void md5_transform(void)
 127{
 128  unsigned x[4], *b = (unsigned *)TT.buffer.c;
 129  int i;
 130
 131  memcpy(x, TT.state, sizeof(x));
 132
 133  for (i=0; i<64; i++) {
 134    unsigned int in, a, rot, temp;
 135
 136    a = (-i)&3;
 137    if (i<16) {
 138      in = i;
 139      rot = 7+(5*(i&3));
 140      temp = x[(a+1)&3];
 141      temp = (temp & x[(a+2)&3]) | ((~temp) & x[(a+3)&3]);
 142    } else if (i<32) {
 143      in = (1+(5*i))&15;
 144      temp = (i&3)+1;
 145      rot = temp*5;
 146      if (temp&2) rot--;
 147      temp = x[(a+3)&3];
 148      temp = (x[(a+1)&3] & temp) | (x[(a+2)&3] & ~temp);
 149    } else if (i<48) {
 150      in = (5+(3*(i&15)))&15;
 151      rot = i&3;
 152      rot = 4+(5*rot)+((rot+1)&6);
 153      temp = x[(a+1)&3] ^ x[(a+2)&3] ^ x[(a+3)&3];
 154    } else {
 155      in = (7*(i&15))&15;
 156      rot = (i&3)+1;
 157      rot = (5*rot)+(((rot+2)&2)>>1);
 158      temp = x[(a+2)&3] ^ (x[(a+1)&3] | ~x[(a+3)&3]);
 159    }
 160    temp += x[a] + b[in] + TT.md5table[i];
 161    x[a] = x[(a+1)&3] + ((temp<<rot) | (temp>>(32-rot)));
 162  }
 163  for (i=0; i<4; i++) TT.state[i] += x[i];
 164}
 165
 166// Mix next 64 bytes of data into sha1 hash.
 167
 168static const unsigned rconsts[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6};
 169#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
 170
 171static void sha1_transform(void)
 172{
 173  int i, j, k, count;
 174  unsigned *block = TT.buffer.i;
 175  unsigned *rot[5], *temp;
 176
 177  // Copy context->state[] to working vars
 178  for (i=0; i<5; i++) {
 179    TT.oldstate[i] = TT.state[i];
 180    rot[i] = TT.state + i;
 181  }
 182  // 4 rounds of 20 operations each.
 183  for (i=count=0; i<4; i++) {
 184    for (j=0; j<20; j++) {
 185      unsigned work;
 186
 187      work = *rot[2] ^ *rot[3];
 188      if (!i) work = (work & *rot[1]) ^ *rot[3];
 189      else {
 190        if (i==2) work = ((*rot[1]|*rot[2])&*rot[3])|(*rot[1]&*rot[2]);
 191        else work ^= *rot[1];
 192      }
 193
 194      if (!i && j<16)
 195        work += block[count] = (rol(block[count],24)&0xFF00FF00)
 196                             | (rol(block[count],8)&0x00FF00FF);
 197      else
 198        work += block[count&15] = rol(block[(count+13)&15]
 199              ^ block[(count+8)&15] ^ block[(count+2)&15] ^ block[count&15], 1);
 200      *rot[4] += work + rol(*rot[0],5) + rconsts[i];
 201      *rot[1] = rol(*rot[1],30);
 202
 203      // Rotate by one for next time.
 204      temp = rot[4];
 205      for (k=4; k; k--) rot[k] = rot[k-1];
 206      *rot = temp;
 207      count++;
 208    }
 209  }
 210  // Add the previous values of state[]
 211  for (i=0; i<5; i++) TT.state[i] += TT.oldstate[i];
 212}
 213
 214// Fill the 64-byte working buffer and call transform() when full.
 215
 216static void hash_update(char *data, unsigned int len, void (*transform)(void))
 217{
 218  unsigned int i, j;
 219
 220  j = TT.count & 63;
 221  TT.count += len;
 222
 223  for (;;) {
 224    // Grab next chunk of data, return if it's not enough to process a frame
 225    i = 64 - j;
 226    if (i>len) i = len;
 227    memcpy(TT.buffer.c+j, data, i);
 228    if (j+i != 64) break;
 229
 230    // Process a frame
 231    if (IS_BIG_ENDIAN)
 232      for (j=0; j<16; j++) TT.buffer.i[j] = SWAP_LE32(TT.buffer.i[j]);
 233    transform();
 234    j=0;
 235    data += i;
 236    len -= i;
 237  }
 238}
 239
 240// Initialize array tersely
 241#define HASH_INIT(name, prefix) { name, (void *)prefix##_Init, \
 242  (void *)prefix##_Update, (void *)prefix##_Final, \
 243  prefix##_DIGEST_LENGTH, }
 244#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
 245
 246// Call the assembly optimized library code when CFG_TOYBOX_LIBCRYPTO
 247static void do_lib_hash(int fd, char *name)
 248{
 249  // Largest context
 250  SHA512_CTX ctx;
 251  struct hash {
 252    char *name;
 253    int (*init)(void *);
 254    int (*update)(void *, void *, size_t);
 255    int (*final)(void *, void *);
 256    int digest_length;
 257  } algorithms[] = {
 258    USE_TOYBOX_LIBCRYPTO(
 259      USE_MD5SUM(HASH_INIT("md5sum", MD5),)
 260      USE_SHA1SUM(HASH_INIT("sha1sum", SHA1),)
 261      USE_SHA224SUM(HASH_INIT("sha224sum", SHA224),)
 262      USE_SHA256SUM(HASH_INIT("sha256sum", SHA256),)
 263      USE_SHA384SUM(HASH_INIT("sha384sum", SHA384),)
 264      USE_SHA512SUM(HASH_INIT("sha512sum", SHA512),)
 265    )
 266  }, * hash;
 267  int i;
 268
 269  // This should never NOT match, so no need to check
 270  for (i = 0; i<ARRAY_LEN(algorithms); i++)
 271    if (!strcmp(toys.which->name, algorithms[i].name)) break;
 272  hash = algorithms+i;
 273
 274  hash->init(&ctx);
 275  for (;;) {
 276      i = read(fd, toybuf, sizeof(toybuf));
 277      if (i<1) break;
 278      hash->update(&ctx, toybuf, i);
 279  }
 280  hash->final(toybuf+128, &ctx);
 281
 282  for (i = 0; i<hash->digest_length; i++)
 283    sprintf(toybuf+2*i, "%02x", toybuf[i+128]);
 284}
 285
 286// Callback for loopfiles()
 287
 288static void do_builtin_hash(int fd, char *name)
 289{
 290  unsigned long long count;
 291  int i, sha1 = toys.which->name[0]=='s';
 292  char buf, *pp;
 293  void (*transform)(void);
 294
 295  /* SHA1 initialization constants  (md5sum uses first 4) */
 296  TT.state[0] = 0x67452301;
 297  TT.state[1] = 0xEFCDAB89;
 298  TT.state[2] = 0x98BADCFE;
 299  TT.state[3] = 0x10325476;
 300  TT.state[4] = 0xC3D2E1F0;
 301  TT.count = 0;
 302
 303  transform = sha1 ? sha1_transform : md5_transform;
 304  for (;;) {
 305    i = read(fd, toybuf, sizeof(toybuf));
 306    if (i<1) break;
 307    hash_update(toybuf, i, transform);
 308  }
 309
 310  count = TT.count << 3;
 311
 312  // End the message by appending a "1" bit to the data, ending with the
 313  // message size (in bits, big endian), and adding enough zero bits in
 314  // between to pad to the end of the next 64-byte frame.
 315  //
 316  // Since our input up to now has been in whole bytes, we can deal with
 317  // bytes here too.
 318
 319  buf = 0x80;
 320  do {
 321    hash_update(&buf, 1, transform);
 322    buf = 0;
 323  } while ((TT.count & 63) != 56);
 324  count = sha1 ? SWAP_BE64(count) : SWAP_LE64(count);
 325  hash_update((void *)&count, 8, transform);
 326
 327  if (sha1)
 328    for (i = 0; i < 20; i++)
 329      sprintf(toybuf+2*i, "%02x", 255&(TT.state[i>>2] >> ((3-(i & 3)) * 8)));
 330  else for (i=0; i<4; i++) sprintf(toybuf+8*i, "%08x", bswap_32(TT.state[i]));
 331
 332  // Wipe variables. Cryptographer paranoia.
 333  // if we do this with memset(), gcc throws a broken warning, and the (long)
 334  // typecasts stop gcc from breaking "undefined behavior" that isn't.
 335  for (pp = (void *)TT.state; (unsigned long)pp-(unsigned long)TT.state<sizeof(TT)-((unsigned long)TT.state-(unsigned long)&TT); pp++)
 336    *pp = 0;
 337  i = strlen(toybuf)+1;
 338  memset(toybuf+i, 0, sizeof(toybuf)-i);
 339}
 340
 341// Call builtin or lib hash function, then display output if necessary
 342static void do_hash(int fd, char *name)
 343{
 344  if (CFG_TOYBOX_LIBCRYPTO) do_lib_hash(fd, name);
 345  else do_builtin_hash(fd, name);
 346
 347  if (name)
 348    printf(FLAG(b) ? "%s\n" : "%s  %s\n", toybuf, name);
 349}
 350
 351static int do_c_line(char *line)
 352{
 353  int space = 0, fail = 0;
 354  char *name;
 355
 356  for (name = line; *name; name++) {
 357    if (isspace(*name)) {
 358      space++;
 359      *name = 0;
 360    } else if (space) break;
 361  }
 362
 363  if (!space || !*line || !*name) error_msg("bad line %s", line);
 364  else {
 365    int fd = !strcmp(name, "-") ? 0 : open(name, O_RDONLY);
 366
 367    TT.sawline = 1;
 368    if (fd==-1) {
 369      perror_msg_raw(name);
 370      *toybuf = 0;
 371    } else do_hash(fd, 0);
 372    if (strcasecmp(line, toybuf)) toys.exitval = fail = 1;
 373    if (!FLAG(s)) printf("%s: %s\n", name, fail ? "FAILED" : "OK");
 374    if (fd>0) close(fd);
 375  }
 376
 377  return 0;
 378}
 379
 380// Used instead of loopfiles_line to report error on files containing no hashes.
 381static void do_c_file(char *name)
 382{
 383  FILE *fp = !strcmp(name, "-") ? stdin : fopen(name, "r");
 384
 385  if (!fp) {
 386    perror_msg_raw(name);
 387    return;
 388  }
 389
 390  TT.sawline = 0;
 391
 392  for (;;) {
 393    char *line = 0;
 394    ssize_t len;
 395
 396    if ((len = getline(&line, (void *)&len, fp))<1) break;
 397    if (line[len-1]=='\n') line[len-1] = 0;
 398    do_c_line(line);
 399    free(line);
 400  }
 401  if (fp!=stdin) fclose(fp);
 402
 403  if (!TT.sawline) error_msg("%s: no lines", name);
 404}
 405
 406void md5sum_main(void)
 407{
 408  char **arg;
 409  int i;
 410
 411  // Calculate table if we have floating point. Static version should drop
 412  // out at compile time when we don't need it.
 413  if (!CFG_TOYBOX_LIBCRYPTO && toys.which->name[0]=='m') {
 414    if (CFG_TOYBOX_FLOAT) {
 415      TT.md5table = xmalloc(64*4);
 416      for (i = 0; i<64; i++) TT.md5table[i] = fabs(sin(i+1))*(1LL<<32);
 417    } else TT.md5table = md5nofloat;
 418  }
 419
 420  if (FLAG(c)) for (arg = toys.optargs; *arg; arg++) do_c_file(*arg);
 421  else {
 422    if (FLAG(s)) error_exit("-s only with -c");
 423    loopfiles(toys.optargs, do_hash);
 424  }
 425}
 426
 427void sha1sum_main(void)
 428{
 429  md5sum_main();
 430}
 431