logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git
commit: 69fb55f56946a123432cc3c037cba4b6becb8a5b
parent c3db17bb363526d0bea816085428f6e8d4c2dc25
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 14 Sep 2024 06:38:19 +0200

cmd/sha512sum: new

Diffstat:

MMakefile3+++
Acmd/sha512sum.134++++++++++++++++++++++++++++++++++
Acmd/sha512sum.c279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcoreutils.txt2+-
Atest-cmd/sha512sum.sh52++++++++++++++++++++++++++++++++++++++++++++++++++++
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 +'