Page MenuHome GnuPG

GPT test
ActivePublic

Authored by aheinecke on Jul 15 2024, 1:32 PM.
/*This program was created by the prompt:
Write a c program that uses libgcrypt to print or check checksums.
The invocation should be: @NAME_OF_THE_PROGRAM@ [OPTION]... [FILE]...
Print or check checksums of the file or files FILE.
With no FILE, or when FILE is -, read standard input.
Options are:
-z, --zero end each output line with NUL, not newline, and disable file name escaping
-c, --check read checksums from the FILEs and check them
-a, --algo the algorithm to use for calculating the hashsum
-l, --list list all available algorithms
The default output is to print a line with: checksum, two spaces,
and name for each FILE.
The program should be called hash, but if its filename is not
hash or hash.exe and the filename matches a known hash algorithm
it should use the filename of the executable as the --algo parameter.
The program should provide all the hash algorithms available in
libgcrypt 1.10
The list option should list all the algrithms which can be used
as for the --algo parameter.
Check should read in a file that matches the output and for
each line should calculate the hash sum of the filenme and
compare it to the checksum in the same line. If the checksum
differs an error should be printed containing the filename
and the program should exit with a nonzero return code.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <gcrypt.h>
#include <getopt.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 4096
void print_usage() {
printf("Usage: hash [OPTION]... [FILE]...\n");
printf("Print or check checksums of the file or files FILE.\n\n");
printf("With no FILE, or when FILE is -, read standard input.\n\n");
printf("Options are:\n");
printf(" -z, --zero end each output line with NUL, not newline, and disable file name escaping\n");
printf(" -c, --check read checksums from the FILEs and check them\n");
printf(" -a, --algo the algorithm to use for calculating the hashsum\n");
printf(" -l, --list list all available algorithms\n");
}
void list_algorithms() {
printf("Available algorithms:\n");
for (int i = 1; i < 400; i++) {
const char *algo_name = gcry_md_algo_name(i);
if (!algo_name) {
break;
}
if (!strcmp(algo_name, "?")) {
continue;
}
printf(" %s\n", algo_name);
}
}
void calculate_checksum(const char *filename, int algo, int zero_end) {
FILE *file = stdin;
if (filename && strcmp(filename, "-") != 0) {
file = fopen(filename, "rb");
if (!file) {
perror("Error opening file");
return;
}
}
gcry_md_hd_t hd;
gcry_md_open(&hd, algo, 0);
char buf[BUF_SIZE];
size_t n;
while ((n = fread(buf, 1, BUF_SIZE, file)) > 0) {
gcry_md_write(hd, buf, n);
}
if (file != stdin) {
fclose(file);
}
unsigned char *hash = gcry_md_read(hd, algo);
size_t hash_len = gcry_md_get_algo_dlen(algo);
for (size_t i = 0; i < hash_len; i++) {
printf("%02x", hash[i]);
}
if (filename && strcmp(filename, "-") != 0) {
printf(" %s%c", filename, zero_end ? '\0' : '\n');
} else {
printf("%c", zero_end ? '\0' : '\n');
}
gcry_md_close(hd);
}
int check_checksums(const char *filename, int algo) {
FILE *file = fopen(filename, "r");
if (!file) {
perror("Error opening file");
return 1;
}
char line[BUF_SIZE];
while (fgets(line, sizeof(line), file)) {
char *hash_str = strtok(line, " ");
strtok(NULL, " ");
char *file_name = strtok(NULL, "\n");
if (!hash_str || !file_name) {
fprintf(stderr, "Malformed line in checksum file: %s\n", line);
fclose(file);
return 1;
}
FILE *check_file = fopen(file_name, "rb");
if (!check_file) {
perror("Error opening file to check");
fclose(file);
return 1;
}
gcry_md_hd_t hd;
gcry_md_open(&hd, algo, 0);
char buf[BUF_SIZE];
size_t n;
while ((n = fread(buf, 1, BUF_SIZE, check_file)) > 0) {
gcry_md_write(hd, buf, n);
}
fclose(check_file);
unsigned char *hash = gcry_md_read(hd, algo);
size_t hash_len = gcry_md_get_algo_dlen(algo);
char computed_hash[hash_len * 2 + 1];
for (size_t i = 0; i < hash_len; i++) {
sprintf(&computed_hash[i * 2], "%02x", hash[i]);
}
if (strcmp(hash_str, computed_hash) != 0) {
fprintf(stderr, "Checksum mismatch for file %s\n", file_name);
gcry_md_close(hd);
fclose(file);
return 1;
}
gcry_md_close(hd);
}
fclose(file);
return 0;
}
int main(int argc, char *argv[]) {
int zero_end = 0;
int check = 0;
int list = 0;
const char *algo_str = NULL;
int algo = GCRY_MD_SHA256; // Default algorithm
static struct option long_options[] = {
{"zero", no_argument, 0, 'z'},
{"check", no_argument, 0, 'c'},
{"algo", required_argument, 0, 'a'},
{"list", no_argument, 0, 'l'},
{0, 0, 0, 0}
};
int c;
while ((c = getopt_long(argc, argv, "zca:l", long_options, NULL)) != -1) {
switch (c) {
case 'z':
zero_end = 1;
break;
case 'c':
check = 1;
break;
case 'a':
algo_str = optarg;
break;
case 'l':
list = 1;
break;
default:
print_usage();
return 1;
}
}
if (list) {
list_algorithms();
return 0;
}
if (algo_str) {
algo = gcry_md_map_name(algo_str);
if (algo == 0) {
fprintf(stderr, "Unknown algorithm: %s\n", algo_str);
return 1;
}
} else {
char *base_name = basename(argv[0]);
if (base_name && strcmp(base_name, "hash") != 0 && strcmp(base_name, "hash.exe") != 0) {
algo = gcry_md_map_name(base_name);
if (algo == 0) {
fprintf(stderr, "Unknown algorithm: %s\n", base_name);
return 1;
}
}
}
if (check) {
if (optind == argc) {
fprintf(stderr, "No checksum file specified for checking\n");
return 1;
}
return check_checksums(argv[optind], algo);
}
if (optind == argc) {
calculate_checksum("-", algo, zero_end);
} else {
for (int i = optind; i < argc; i++) {
calculate_checksum(argv[i], algo, zero_end);
}
}
return 0;
}