master xplshn/aruu / shared / libutil / crypt.c
  1/* See LICENSE file for copyright and license details. */
  2#include <fcntl.h>
  3#include <stdint.h>
  4#include <stdio.h>
  5#include <stdlib.h>
  6#include <string.h>
  7#include <unistd.h>
  8
  9#include "../crypt.h"
 10#include "../text.h"
 11#include "../util.h"
 12
 13static int
 14hexdec(int c)
 15{
 16  if (c >= '0' && c <= '9')
 17    return c - '0';
 18  else if (c >= 'A' && c <= 'F')
 19    return c - 'A' + 10;
 20  else if (c >= 'a' && c <= 'f')
 21    return c - 'a' + 10;
 22  return -1; /* unknown character */
 23}
 24
 25static int
 26mdcheckline(const char *s, uint8_t *md, size_t sz)
 27{
 28  size_t i;
 29  int    b1, b2;
 30
 31  for (i = 0; i < sz; i++) {
 32    if (!*s || (b1 = hexdec(*s++)) < 0)
 33      return -1; /* invalid format */
 34    if (!*s || (b2 = hexdec(*s++)) < 0)
 35      return -1; /* invalid format */
 36    if ((uint8_t)((b1 << 4) | b2) != md[i])
 37      return 1; /* value mismatch */
 38  }
 39  return (i == sz) ? 0 : 1;
 40}
 41
 42static void
 43mdchecklist(
 44    FILE             *listfp,
 45    struct crypt_ops *ops,
 46    uint8_t          *md,
 47    size_t            sz,
 48    int              *formatsucks,
 49    int              *noread,
 50    int              *nonmatch
 51)
 52{
 53  int    fd;
 54  size_t bufsiz = 0;
 55  int    r;
 56  char  *line = NULL, *file, *p;
 57
 58  while (getline(&line, &bufsiz, listfp) > 0) {
 59    file = strchr(line, ' ');
 60    if (file == NULL || (file[1] != ' ' && file[1] != '*')) {
 61      (*formatsucks)++;
 62      continue;
 63    }
 64    if ((size_t)(file - line) != sz * 2) {
 65      (*formatsucks)++; /* checksum length mismatch */
 66      continue;
 67    }
 68    *file = '\0';
 69    file += 2;
 70    for (p = file; *p && *p != '\n' && *p != '\r'; p++)
 71      ; /* strip newline */
 72    *p = '\0';
 73    if ((fd = open(file, O_RDONLY)) < 0) {
 74      weprintf("open %s:", file);
 75      (*noread)++;
 76      continue;
 77    }
 78    if (cryptsum(ops, fd, file, md)) {
 79      (*noread)++;
 80      continue;
 81    }
 82    r = mdcheckline(line, md, sz);
 83    if (r == 0) {
 84      printf("%s: OK\n", file);
 85    } else if (r == 1) {
 86      printf("%s: FAILED\n", file);
 87      (*nonmatch)++;
 88    } else {
 89      (*formatsucks)++;
 90    }
 91    close(fd);
 92  }
 93  free(line);
 94}
 95
 96int
 97cryptcheck(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
 98{
 99  FILE *fp;
100  int   formatsucks = 0, noread = 0, nonmatch = 0, ret = 0;
101
102  if (argc == 0) {
103    mdchecklist(stdin, ops, md, sz, &formatsucks, &noread, &nonmatch);
104  } else {
105    for (; *argv; argc--, argv++) {
106      if ((*argv)[0] == '-' && !(*argv)[1]) {
107        fp = stdin;
108      } else if (!(fp = fopen(*argv, "r"))) {
109        weprintf("fopen %s:", *argv);
110        ret = 1;
111        continue;
112      }
113      mdchecklist(fp, ops, md, sz, &formatsucks, &noread, &nonmatch);
114      if (fp != stdin)
115        fclose(fp);
116    }
117  }
118
119  if (formatsucks) {
120    weprintf("%d improperly formatted line%s\n", formatsucks, formatsucks > 1 ? "s" : "");
121    ret = 1;
122  }
123  if (noread) {
124    weprintf("%d listed file%s could not be read\n", noread, noread > 1 ? "s" : "");
125    ret = 1;
126  }
127  if (nonmatch) {
128    weprintf("%d computed checksum%s did NOT match\n", nonmatch, nonmatch > 1 ? "s" : "");
129    ret = 1;
130  }
131
132  return ret;
133}
134
135int
136cryptmain(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
137{
138  int fd;
139  int ret = 0;
140
141  if (argc == 0) {
142    if (cryptsum(ops, 0, "<stdin>", md))
143      ret = 1;
144    else
145      mdprint(md, "<stdin>", sz);
146  } else {
147    for (; *argv; argc--, argv++) {
148      if ((*argv)[0] == '-' && !(*argv)[1]) {
149        *argv = "<stdin>";
150        fd    = 0;
151      } else if ((fd = open(*argv, O_RDONLY)) < 0) {
152        weprintf("open %s:", *argv);
153        ret = 1;
154        continue;
155      }
156      if (cryptsum(ops, fd, *argv, md))
157        ret = 1;
158      else
159        mdprint(md, *argv, sz);
160      if (fd != 0)
161        close(fd);
162    }
163  }
164
165  return ret;
166}
167
168int
169cryptsum(struct crypt_ops *ops, int fd, const char *f, uint8_t *md)
170{
171  uint8_t buf[BUFSIZ];
172  ssize_t n;
173
174  ops->init(ops->s);
175  while ((n = read(fd, buf, sizeof(buf))) > 0)
176    ops->update(ops->s, buf, n);
177  if (n < 0) {
178    weprintf("%s: read error:", f);
179    return 1;
180  }
181  ops->sum(ops->s, md);
182  return 0;
183}
184
185void
186mdprint(const uint8_t *md, const char *f, size_t len)
187{
188  size_t i;
189
190  for (i = 0; i < len; i++)
191    printf("%02x", md[i]);
192  printf("  %s\n", f);
193}