/* sharnd.c - Create cryptographically secure random file

Copyright (C) 2004, Matt Mahoney, mattmahoneyfl@gmail.com
License: MIT <http://spdx.org/licenses/MIT>

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

(License changed from GPL v2 to MIT on Mar. 6, 2012).

The command:

   sharnd key

prints the SHA1 hash of the key, which can be any ASCII string.
If the string has spaces, then enclose it in quotes.

   sharnd key n

works as above and also creates the file sharnd.out with length n bytes
containing cryptographically secure pseudo random numbers.  Given all
but one bit of the file, it is not possible to guess the remaining
bit with probability greater than 1/2 unless you know the key.

The output is a series of 20 byte strings, x[1], x[2], ... x[n/20]
such that:

  x[i] = SHA1(x[i-1] + key)

where x[0] is a string of 0 bytes, and + denotes concatenation.

For example, "sharnd abc 50" will print:

  Key hash = A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D
  Writing 50 random bytes to sharnd.out...

The contents of sharnd.out should be:

  7D DF 37 9E  DB 9F 0E 14  1F 6D AD EF  EC 28 F0 60
  2B 2A 76 A8  49 54 13 F2  6E DA 0F 19  CD D9 26 6C
  46 8A 2D 17  8B 76 24 C0  0D D1 80 4F  E7 22 6C 2A
  9A C9


To compile, first get sha1.h and sha1.c from RFC3174,
http://www.faqs.org/rfcs/rfc3174.html

If you don't have <stdint.h> then replace the following line in sha1.h

  #include <stdint.h>

with the following 3 lines:

  typedef unsigned long uint32_t;
  typedef unsigned char uint8_t;
  typedef int int_least16_t;

Then compile as follows (for DJGPP or Borland)

   gcc -O sharnd.c sha1.c -o sharnd.exe
   bcc32 -O sharnd.c sha1.c

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sha1.h"  /* from RFC3174 */

/* Test for nonzero error code, exit with message if so */
void test(int err, const char* msg) {
  if (err) {
    fprintf(stderr, "%s: error %d\n", msg, err);
    exit(1);
  }
}

int main(int argc, char** argv) {
  int n, i, len;
  FILE* f;
  static unsigned char buf[20] = {0};
  SHA1Context sha;
  
  /* Get args */
  if (argc < 2) {
    fprintf(stderr, "To generate n secure random bytes: sharnd key n\n");
    exit(1);
  }
  n = argc > 2 ? atoi(argv[2]) : 0;  /* Number of bytes to output */

  /* Print a hash of the key */
  len = strlen(argv[1]);  /* key length */
  test(SHA1Reset(&sha), "SHA1Reset");
  test(SHA1Input(&sha, argv[1], len), "SHA1Input");
  test(SHA1Result(&sha, buf), "SHA1Result");
  printf("Key hash =");
  for (i=0; i<20; ++i)
    printf(" %02X", buf[i]);
  printf("\n");

  /* Open output file */
  if (n < 1)
    return 0;
  f = fopen("sharnd.out", "wb");
  if (!f) {
    perror("sharnd.out");
    exit(1);
  }

  /* Generate random data */
  printf("Writing %d random bytes to sharnd.out...\n", n);
  while (n > 0) {
    test(SHA1Reset(&sha), "SHA1Reset");
    test(SHA1Input(&sha, buf, 20), "SHA1Input hash");
    test(SHA1Input(&sha, argv[1], len), "SHA1Input key");
    test(SHA1Result(&sha, buf), "SHA1Result");
    fwrite(buf, 1, (n > 20 ? 20 : n), f);
    n -= 20;
  }
  fclose(f);
  return 0;
}

