crhash: sha1: add test vectors
[crhash.git] / main.c
blob1c925217ae4c82a87d87faf488855b1d48ae357d
1 #include <fcntl.h>
2 #include <getopt.h>
3 #include <inttypes.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/mman.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
12 #include "hash-md5.h"
13 #include "hash-sha1.h"
14 #include "hash-whirlpool.h"
16 static int rv;
18 static const char *hash;
19 struct hash_algo {
20 const char *name;
21 unsigned int block_size; /* in bits */
22 unsigned int digest_size; /* in bits */
23 void *(*init_context)(void);
24 void (*fini_context)(void *ctx);
25 void (*update)(void *ctx, const uint8_t *m);
26 void (*_update)(void *ctx, const uint8_t *m, unsigned int len);
27 void (*fini)(void *ctx);
28 void (*digest)(void *ctx, uint8_t *digest);
31 static const struct hash_algo _hash_algo[] = {
33 .name = "md5",
34 .block_size = 512,
35 .digest_size = 128,
36 .init_context = md5_init_context,
37 .fini_context = md5_fini_context,
38 .update = md5_update,
39 ._update = _md5_update,
40 .fini = md5_fini,
41 .digest = md5_digest,
44 .name = "sha1",
45 .block_size = 512,
46 .digest_size = 160,
47 .init_context = sha1_init_context,
48 .fini_context = sha1_fini_context,
49 .update = sha1_update,
50 ._update = _sha1_update,
51 .fini = sha1_fini,
52 .digest = sha1_digest,
55 .name = "whirlpool",
56 .block_size = 512,
57 .digest_size = 512,
58 .init_context = whirlpool_init_context,
59 .fini_context = whirlpool_fini_context,
60 .update = whirlpool_update,
61 ._update = _whirlpool_update,
62 .fini = whirlpool_fini,
63 .digest = whirlpool_digest,
67 static const struct hash_algo *find_hash_algo(const char *name)
69 int i;
71 for (i = 0; i < sizeof(_hash_algo) / sizeof(_hash_algo[0]); i++) {
72 if (strcmp(name, _hash_algo[i].name) == 0)
73 return &_hash_algo[i];
75 return NULL;
78 static void _hash_file(const struct hash_algo *hash_algo, const uint8_t *m, uintmax_t len)
80 uint8_t *digest;
81 void *ctx;
83 digest = malloc(hash_algo->digest_size / 8);
84 if (!digest) {
85 perror("malloc");
86 rv = EXIT_FAILURE;
87 return;
90 ctx = hash_algo->init_context();
91 if (!ctx) {
92 perror("->init");
93 free(digest);
94 rv = EXIT_FAILURE;
95 return;
97 while (len >= hash_algo->block_size / 8) {
98 hash_algo->update(ctx, m);
99 m += hash_algo->block_size / 8;
100 len -= hash_algo->block_size / 8;
102 hash_algo->_update(ctx, m, len);
103 hash_algo->fini(ctx);
104 hash_algo->digest(ctx, digest);
105 hash_algo->fini_context(ctx);
107 int i;
109 for (i = 0; i < hash_algo->digest_size / 8; i++)
110 printf("%02x", digest[i]);
111 printf("\n");
115 static void hash_file(const struct hash_algo *hash_algo, const char *filename)
117 int fd;
118 struct stat st;
119 uintmax_t len;
120 uint8_t *p;
122 fd = open(filename, O_RDONLY);
123 if (fd == -1) {
124 perror(filename);
125 rv = EXIT_FAILURE;
126 return;
128 if (fstat(fd, &st) == -1) {
129 perror(filename);
130 rv = EXIT_FAILURE;
131 return;
133 if (st.st_size < 0) {
134 fprintf(stderr, "st_size %" PRIdMAX "\n", (intmax_t)st.st_size);
135 rv = EXIT_FAILURE;
136 close(fd);
137 return;
139 len = (uintmax_t)(intmax_t)st.st_size;
140 if (len != (uintmax_t)(size_t)len) {
141 fprintf(stderr, "st_size %" PRIuMAX "\n", len);
142 rv = EXIT_FAILURE;
143 close(fd);
144 return;
146 if (len == 0) {
147 p = NULL;
148 } else {
149 p = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
150 if (p == MAP_FAILED) {
151 perror("mmap");
152 rv = EXIT_FAILURE;
153 close(fd);
154 return;
156 (void)madvise(p, len, MADV_SEQUENTIAL);
158 close(fd);
160 _hash_file(hash_algo, p, len);
162 if (len != 0)
163 munmap(p, len);
166 int main(int argc, char *argv[])
168 int ch;
169 const struct hash_algo *hash_algo;
171 while ((ch = getopt(argc, argv, "t:")) != -1) {
172 switch (ch) {
173 case 't':
174 hash = optarg;
175 break;
176 default:
177 return EXIT_FAILURE;
181 if (hash) {
182 hash_algo = find_hash_algo(hash);
183 if (!hash_algo) {
184 int i;
186 fprintf(stderr, "unexpected hash algorithm '%s'\n", hash);
187 fprintf(stderr, "expected hash algorithms:");
188 for (i = 0; i < sizeof(_hash_algo) / sizeof(_hash_algo[0]); i++)
189 fprintf(stderr, " %s", _hash_algo[i].name);
190 fprintf(stderr, "\n");
191 exit(EXIT_FAILURE);
193 } else {
194 fprintf(stderr, "hash algorithm required (-t)\n");
195 exit(EXIT_FAILURE);
198 rv = EXIT_SUCCESS;
199 while (optind < argc) {
200 hash_file(hash_algo, argv[optind]);
201 optind++;
203 return rv;