pkgsrc/pkgtools/digest/files/digest.c
nia 61c7f725de digest: add the BLAKE2b digest.
BLAKE2 is a further development of the SHA-3 finalist BLAKE by its original
authors that improves its performance. BLAKE2b is the variant optimized for
64-bit systems.

ok riastradh
2018-10-06 14:32:45 +00:00

226 lines
6.4 KiB
C

/* $NetBSD: digest.c,v 1.17 2018/10/06 14:32:45 nia Exp $ */
/*-
* Copyright (c) 2001-2016 Alistair Crooks <agc@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <blake2b.h>
#include <md5.h>
#include <rmd160.h>
#include <sha1.h>
#include <sha2.h>
#include <sha3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tiger.h>
#include <whirlpool.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
typedef void (*HASH_init)(void *);
typedef void (*HASH_update)(void *, const uint8_t *, size_t);
typedef char *(*HASH_end)(void *, char *);
typedef char *(*HASH_file)(char *, char *);
/* this struct defines a message digest algorithm */
typedef struct alg_t {
const char *name;
int hash_len;
HASH_init hash_init;
HASH_update hash_update;
HASH_end hash_end;
HASH_file hash_file;
union {
MD5_CTX m;
SHA1_CTX sha;
RMD160_CTX rmd;
SHA256_CTX sha256;
SHA384_CTX sha384;
SHA3_224_CTX sha3_224;
SHA3_256_CTX sha3_256;
SHA3_384_CTX sha3_384;
SHA3_512_CTX sha3_512;
SHA512_CTX sha512;
tiger_context_t tiger;
whirlpool_context_t whirlpool;
} hash_ctx, hash_ctx2;
} alg_t;
/* list of supported message digest algorithms */
static alg_t algorithms[] = {
{ "BLAKE2B", 64,
(HASH_init) BLAKE2b_Init, (HASH_update) BLAKE2b_Update,
(HASH_end) BLAKE2b_End, (HASH_file) BLAKE2b_File },
{ "MD5", 16,
(HASH_init) MD5Init, (HASH_update) MD5Update,
(HASH_end) MD5End, (HASH_file) MD5File },
{ "RMD160", 20,
(HASH_init) RMD160Init, (HASH_update) RMD160Update,
(HASH_end) RMD160End, (HASH_file) RMD160File },
{ "SHA1", 20,
(HASH_init) SHA1Init, (HASH_update) SHA1Update,
(HASH_end) SHA1End, (HASH_file) SHA1File },
{ "SHA256", SHA256_DIGEST_LENGTH,
(HASH_init) SHA256_Init, (HASH_update) SHA256_Update,
(HASH_end) SHA256_End, (HASH_file) SHA256_File },
{ "SHA3_224", SHA3_224_DIGEST_LENGTH,
(HASH_init) SHA3_224_Init, (HASH_update) SHA3_224_Update,
(HASH_end) SHA3_224_End, (HASH_file) SHA3_224_File },
{ "SHA3_256", SHA3_256_DIGEST_LENGTH,
(HASH_init) SHA3_256_Init, (HASH_update) SHA3_256_Update,
(HASH_end) SHA3_256_End, (HASH_file) SHA3_256_File },
{ "SHA3_384", SHA3_384_DIGEST_LENGTH,
(HASH_init) SHA3_384_Init, (HASH_update) SHA3_384_Update,
(HASH_end) SHA3_384_End, (HASH_file) SHA3_384_File },
{ "SHA3_512", SHA3_512_DIGEST_LENGTH,
(HASH_init) SHA3_512_Init, (HASH_update) SHA3_512_Update,
(HASH_end) SHA3_512_End, (HASH_file) SHA3_512_File },
{ "SHA384", SHA384_DIGEST_LENGTH,
(HASH_init) SHA384_Init, (HASH_update) SHA384_Update,
(HASH_end) SHA384_End, (HASH_file) SHA384_File },
{ "SHA512", SHA512_DIGEST_LENGTH,
(HASH_init) SHA512_Init, (HASH_update) SHA512_Update,
(HASH_end) SHA512_End, (HASH_file) SHA512_File },
{ "TIGER", 24,
(HASH_init) TIGERInit, (HASH_update) TIGERUpdate,
(HASH_end) TIGEREnd, (HASH_file) TIGERFile },
{ "WHIRLPOOL", WHIRLPOOL_DIGEST_BYTES,
(HASH_init) whirlpool_init, (HASH_update) whirlpool_update,
(HASH_end) whirlpool_end, (HASH_file) whirlpool_file },
{ NULL }
};
/* find an algorithm, given a name */
static alg_t *
find_algorithm(const char *a)
{
alg_t *alg;
for (alg = algorithms ; alg->name && strcasecmp(alg->name, a) != 0 ; alg++) {
}
return (alg->name) ? alg : NULL;
}
/* compute a digest, and print the results if successful */
static int
digest_file(char *fn, alg_t *alg)
{
char in[BUFSIZ * 20];
char *digest;
int cc, rc;
digest = malloc(alg->hash_len * 2 + 1);
if (fn == NULL) {
(*alg->hash_init)(&alg->hash_ctx);
while ((cc = read(STDIN_FILENO, in, sizeof(in))) > 0) {
(*alg->hash_update)(&alg->hash_ctx, (uint8_t *)in,
(unsigned) cc);
}
(void) printf("%s\n", (*alg->hash_end)(&alg->hash_ctx, digest));
rc = 1;
} else {
if ((*alg->hash_file)(fn, digest) == NULL) {
rc = 0;
} else {
(void) printf("%s (%s) = %s\n", alg->name, fn, digest);
rc = 1;
}
}
free(digest);
return (rc);
}
int
main(int argc, char **argv)
{
alg_t *alg;
int test;
int ok;
int i;
#ifdef HAVE_SETLOCALE
(void) setlocale(LC_ALL, "");
#endif
test = 0;
while ((i = getopt(argc, argv, "Vt")) != -1) {
switch(i) {
case 'V':
printf("%s\n", VERSION);
return EXIT_SUCCESS;
case 't':
test = 1;
break;
}
}
if (test) {
/* there's room for other tests here -- agc */
printf("self test mode starting\n");
ok = 1;
if (SHA3_Selftest() != 0) {
ok = 0;
}
printf("self test mode completed\n");
return (ok) ? EXIT_SUCCESS : EXIT_FAILURE;
}
/* check for correct usage */
if (argc == optind) {
(void) fprintf(stderr, "Usage: %s algorithm [file...]\n",
argv[0]);
return EXIT_FAILURE;
}
/* check we know the digest algorithm */
if ((alg = find_algorithm(argv[optind])) == NULL) {
(void) fprintf(stderr, "No such algorithm `%s'\n", argv[optind]);
exit(EXIT_FAILURE);
}
ok = 1;
if (argc == optind + 1) {
if (!digest_file(NULL, alg)) {
fprintf(stderr, "stdin\n");
ok = 0;
}
} else {
for (i = optind + 1 ; i < argc ; i++) {
if (!digest_file(argv[i], alg)) {
fprintf(stderr, "%s\n", argv[i]);
ok = 0;
}
}
}
return (ok) ? EXIT_SUCCESS : EXIT_FAILURE;
}