commit: 69fb55f56946a123432cc3c037cba4b6becb8a5b
parent c3db17bb363526d0bea816085428f6e8d4c2dc25
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sat, 14 Sep 2024 06:38:19 +0200
cmd/sha512sum: new
Diffstat:
5 files changed, 369 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
@@ -195,5 +195,8 @@ cmd/sha1sum: cmd/sha1sum.c lib/sha1.c lib/sha1.h lib/bytes2hex.c lib/strconv.h M
cmd/sha256sum: cmd/sha256sum.c lib/sha256.c lib/sha256.h lib/bytes2hex.c lib/strconv.h Makefile
$(CC) -std=c99 $(CFLAGS) -o $@ cmd/sha256sum.c lib/sha256.c lib/bytes2hex.c $(LDFLAGS) $(LDSTATIC)
+cmd/sha512sum: cmd/sha512sum.c lib/sha512.c lib/sha512.h lib/bytes2hex.c lib/strconv.h Makefile
+ $(CC) -std=c99 $(CFLAGS) -o $@ cmd/sha512sum.c lib/sha512.c lib/bytes2hex.c $(LDFLAGS) $(LDSTATIC)
+
test-cmd/pathchk-getlimits: test-cmd/pathchk-getlimits.c Makefile
$(CC) -std=c99 $(CFLAGS) -o $@ test-cmd/pathchk-getlimits.c $(LDFLAGS) $(LDSTATIC)
diff --git a/cmd/sha512sum.1 b/cmd/sha512sum.1
@@ -0,0 +1,34 @@
+.\" utils-std: Collection of commonly available Unix tools
+.\" Copyright 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+.\" SPDX-License-Identifier: MPL-2.0
+.Dd 2024-08-15
+.Dt SHA512SUM 1
+.Os
+.Sh NAME
+.Nm sha512sum
+.Nd write and verify sha512 checksums
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Op Ar file...
+.Sh DESCRIPTION
+.Nm
+reads each
+.Ar file ,
+or standard input if none were specified,
+and prints each of their SHA512 checksum.
+.Sh OPTIONS
+.Bl -tag -width _c
+.It Fl c
+Verify checksums contained in each
+.Ar file .
+Currently supported format being checksum, whitespace, an optional asterisk
+.Ql *
+and finally a filename.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh STANDARDS
+SHA512 is standardized both in FIPS 180-4 and RFC 6234.
+.Sh AUTHORS
+.An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me
diff --git a/cmd/sha512sum.c b/cmd/sha512sum.c
@@ -0,0 +1,279 @@
+// utils-std: Collection of commonly available Unix tools
+// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+// SPDX-License-Identifier: MPL-2.0
+
+#define _POSIX_C_SOURCE 200809L
+#include "../lib/sha512.h" // sha512_*
+#include "../lib/strconv.h" // bytes2hex
+
+#include <assert.h>
+#include <ctype.h> // isxdigit
+#include <errno.h>
+#include <fcntl.h> // open, O_*
+#include <stdbool.h>
+#include <stdio.h> // fprintf
+#include <stdlib.h> // free
+#include <string.h> // strerror
+#include <unistd.h> // read, write, close, getopt
+
+#define SHA512SUM_LEN SHA512_DIGEST_LENGTH * 2 + 1
+
+static int
+sha512sum(int fd, const char *fdname, char sum[SHA512SUM_LEN])
+{
+ struct sha512 ctx;
+
+ sha512_init(&ctx);
+
+ uint8_t buf[BUFSIZ];
+ ssize_t nread = -1;
+ while((nread = read(fd, buf, BUFSIZ)) > 0)
+ {
+ sha512_update(&ctx, buf, nread);
+ }
+ if(nread < 0)
+ {
+ fprintf(stderr,
+ "sha512sum: I/O Error while reading file '%s': %s\n",
+ fdname ? fdname : "<stdin>",
+ strerror(errno));
+ return -1;
+ }
+
+ uint8_t res[SHA512_DIGEST_LENGTH] = "";
+ sha512_sum(&ctx, res);
+
+ bytes2hex(res, SHA512_DIGEST_LENGTH, sum, SHA512SUM_LEN);
+
+ return 0;
+}
+
+#define STR(s) #s
+#define XSTR(s) STR(s)
+
+static int
+check(FILE *file, const char *filename)
+{
+ int err = 0;
+
+ ssize_t nread = -1;
+ char *line = NULL;
+ size_t len = 0;
+ errno = 0;
+ while((nread = getline(&line, &len, file)) > 0)
+ {
+ assert(errno == 0);
+ if(line[nread - 1] == '\n') line[nread - 1] = '\0';
+
+ ssize_t i = 0;
+ for(; i < nread; i++)
+ {
+ if(isxdigit(line[i])) continue;
+
+ if(line[i] == ' ')
+ {
+ line[i] = '\0';
+ break;
+ }
+
+ fprintf(stderr,
+ "sha512sum: Error: Invalid character '%c' while reading hash in line: %s\n",
+ line[i],
+ line);
+ if(len > 0) free(line);
+ return -1;
+ }
+ if(line[i++] != '\0')
+ {
+ fprintf(stderr, "sha512sum: Error: Invalid line: %s\n", line);
+ if(len > 0) free(line);
+ return -1;
+ }
+
+ if(i != SHA512SUM_LEN)
+ {
+ fprintf(stderr,
+ "sha512sum: Error: Got %zd hexadecimal digits while expected %d for a SHA512\n",
+ i,
+ SHA512SUM_LEN);
+ if(len > 0) free(line);
+ return -1;
+ }
+
+ while(i < nread && line[i] == ' ')
+ i++;
+
+ if(i < nread && line[i] == '*') i++;
+
+ char *target = line + i;
+
+ int fd = open(target, O_RDONLY | O_NOCTTY);
+ if(fd < 0)
+ {
+ fprintf(stderr, "sha512sum: Error: Failed opening file '%s': %s\n", target, strerror(errno));
+
+ if(len > 0) free(line);
+ return -1;
+ }
+
+ int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+ if(ret != 0)
+ fprintf(stderr,
+ "sha512sum: Warning: posix_fadvise failed on file '%s': %s\n",
+ target,
+ strerror(ret));
+
+ char got[SHA512SUM_LEN] = "";
+ if(sha512sum(fd, target, got) < 0) err = 1;
+ if(memcmp(line, got, SHA512SUM_LEN) == 0)
+ {
+ printf("%s: OK\n", target);
+ }
+ else
+ {
+ err = 1;
+ printf("%s: FAILED\n", target);
+ }
+
+ if(close(fd) < 0)
+ {
+ fprintf(stderr, "sha512sum: Failed closing file '%s': %s\n", filename, strerror(errno));
+
+ if(len > 0) free(line);
+ return -1;
+ }
+ }
+ if(nread < 0 && errno != 0)
+ {
+ err = 1;
+ fprintf(
+ stderr, "sha512sum: Failed reading line from file '%s': %s\n", filename, strerror(errno));
+ }
+ if(len > 0) free(line);
+
+ return err;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bool opt_c = false;
+
+ int c = -1;
+ while((c = getopt(argc, argv, "c")) != -1)
+ {
+ switch(c)
+ {
+ case 'c':
+ opt_c = true;
+ break;
+ default:
+ fprintf(stderr, "sha512sum: Unhandled option '-%c'\n", c);
+ return 1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(opt_c)
+ {
+ if(argc == 0)
+ {
+ if(check(stdin, "<stdin>") != 0) return 1;
+
+ return 0;
+ }
+
+ int err = 0;
+
+ for(int i = 0; i < argc; i++)
+ {
+ FILE *file = NULL;
+ const char *filename = argv[i];
+
+ if(filename[0] == '-' && filename[1] == '\0')
+ {
+ filename = "<stdin>";
+ file = stdin;
+ }
+ else
+ {
+ file = fopen(filename, "rb");
+ if(file == NULL)
+ {
+ fprintf(stderr,
+ "sha512sum: Error: Failed opening file '%s': %s\n",
+ filename,
+ strerror(errno));
+ return 1;
+ }
+ }
+
+ if(check(file, filename) != 0) err = 1;
+
+ if(fclose(file) < 0)
+ {
+ fprintf(stderr, "sha512sum: Failed closing file '%s': %s\n", filename, strerror(errno));
+ return 1;
+ }
+ }
+
+ return err;
+ }
+
+ if(argc == 0)
+ {
+
+ char sum[SHA512SUM_LEN] = "";
+ if(sha512sum(STDIN_FILENO, NULL, sum) < 0) return 1;
+
+ puts(sum);
+
+ return 0;
+ }
+
+ for(int i = 0; i < argc; i++)
+ {
+ int fd = -1;
+ const char *filename = argv[i];
+ if(filename[0] == '-' && filename[1] == '\0')
+ {
+ filename = "<stdin>";
+ fd = STDIN_FILENO;
+ }
+ else
+ {
+ fd = open(filename, O_RDONLY | O_NOCTTY);
+ if(fd < 0)
+ {
+ fprintf(
+ stderr, "sha512sum: Error: Failed opening file '%s': %s\n", filename, strerror(errno));
+ return 1;
+ }
+
+ int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+ if(ret != 0)
+ fprintf(stderr,
+ "sha512sum: Warning: posix_fadvise failed on file '%s': %s\n",
+ filename,
+ strerror(ret));
+ }
+
+ int err = 0;
+
+ char sum[SHA512SUM_LEN] = "";
+ if(sha512sum(fd, filename, sum) < 0) err = 1;
+ printf("%s %s\n", sum, filename);
+
+ if(close(fd) < 0)
+ {
+ fprintf(stderr, "sha512sum: Failed closing file '%s': %s\n", filename, strerror(errno));
+ return 1;
+ }
+
+ if(err == 1) return 1;
+ }
+
+ return 0;
+}
diff --git a/coreutils.txt b/coreutils.txt
@@ -72,7 +72,7 @@ sha1sum: Done
sha224sum: No
sha256sum: Done
sha384sum: No
-sha512sum: No
+sha512sum: Done
shred: ?
shuf: Todo
sleep: Done
diff --git a/test-cmd/sha512sum.sh b/test-cmd/sha512sum.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+# SPDX-License-Identifier: MPL-2.0
+
+WD="$(dirname "$0")"
+target="${WD}/../cmd/sha512sum"
+plans=16
+. "$(dirname "$0")/tap.sh"
+
+if test "$(uname -s)" = "FreeBSD"
+then
+ skip devnull 'FreeBSD treats posix_fadvise on /dev/null as invalid'
+else
+ t devnull '/dev/null' 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e /dev/null
+'
+fi
+t empty "$WD/inputs/empty" "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e $WD/inputs/empty
+"
+t --input='' 'empty_stdin' '' 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
+'
+
+t --input='abc' 'abc' '' 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
+'
+
+t --exit=1 'enoent' '/var/empty/e/no/ent' "sha512sum: Error: Failed opening file '/var/empty/e/no/ent': No such file or directory
+"
+
+t --input="cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e $WD/inputs/empty" 'check:empty' '-c' "$WD/inputs/empty: OK
+"
+t --input="cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e *$WD/inputs/empty" 'bin_check:empty' '-c' "$WD/inputs/empty: OK
+"
+t --input="cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e *$WD/inputs/empty" 'bin_check:empty:dash' '-c -' "$WD/inputs/empty: OK
+"
+
+t --exit=1 --input="ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f $WD/inputs/empty" 'xfail_check:empty' '-c' "$WD/inputs/empty: FAILED
+"
+t --exit=1 --input="ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f *$WD/inputs/empty" 'xfail_bin_check:empty' '-c' "$WD/inputs/empty: FAILED
+"
+
+t --exit=1 --input='cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e /var/empty/e/no/ent' 'xfail_check:enoent' '-c' "sha512sum: Error: Failed opening file '/var/empty/e/no/ent': No such file or directory
+"
+t --exit=1 --input='cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e */var/empty/e/no/ent' 'xfail_bin_check:enoent' '-c' "sha512sum: Error: Failed opening file '/var/empty/e/no/ent': No such file or directory
+"
+
+t --exit=1 --input="# $WD/inputs/empty" 'invalid_chars:#' '-c' "sha512sum: Error: Invalid character '#' while reading hash in line: # $WD/inputs/empty
+"
+t --exit=1 --input="cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" 'missing_file' '-c' "sha512sum: Error: Failed opening file '': No such file or directory
+"
+t --exit=1 --input="cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3 $WD/inputs/empty" 'truncated_hash' '-c' 'sha512sum: Error: Got 128 hexadecimal digits while expected 129 for a SHA512
+'
+t --exit=1 --input="cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3ed $WD/inputs/empty" 'elongated_hash' '-c' 'sha512sum: Error: Got 130 hexadecimal digits while expected 129 for a SHA512
+'