X-Git-Url: https://jxself.org/git/?p=skeinsum.git;a=blobdiff_plain;f=skein_cli.c;h=706091e4c7359c60046db0c46f9f5ab0f4daae03;hp=c8ae45b48ff37219fd4369ba9011ae10dd5979ca;hb=3dfce07c702e1e59478cc9d4e3afea359a1b62f8;hpb=6ec116da3188186d71484164c2ce430ac5a08966 diff --git a/skein_cli.c b/skein_cli.c index c8ae45b..706091e 100644 --- a/skein_cli.c +++ b/skein_cli.c @@ -31,24 +31,25 @@ along with skeinsum. If not, see . #include #include "SHA3api_ref.h" +#define WARN(msg, ...) fprintf(stderr, "skein%dsum: " msg, hashbitlen, ##__VA_ARGS__) + #define TRYHELP_GOODBYE() do { printf("Try 'skein%dsum --help' for more information.\n", hashbitlen); exit(1); } while(0) +typedef long long unsigned LLU; + extern const int hashbitlen; #define skeinVersion "1.3" + const size_t input_minbufsize = 32 * 1024; const size_t input_maxbufsize = 32 * 1024 * 1024; -char invalidOption = 0; - enum { QUIET_OPTION = 11, STATUS_OPTION, - TAG_OPTION, - HELP_OPTION, - VERSION_OPTION + TAG_OPTION }; static struct option const long_options[] = @@ -60,57 +61,43 @@ static struct option const long_options[] = { "text", no_argument, NULL, 't' }, { "warn", no_argument, NULL, 'w' }, { "tag", no_argument, NULL, TAG_OPTION }, - { "help", no_argument, NULL, HELP_OPTION }, - { "version", no_argument, NULL, VERSION_OPTION }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; -void printHexMsg(unsigned char *ptr, int size, char result[]) +void hash2hexstr(unsigned char hash[], char str[]) { - int i = 0; - int j = 0; - char High, Low; - for (i = 0 ; i < size ; i ++) - { - High = ptr[i]>>4; - Low = ptr[i]&0x0F; - - if (High >= 0xA && High <= 0xF) - High += 0x37; - else if(High >= 0x0 && High <= 0x9) - High += 0x30; - - if (Low >= 0xA && Low <= 0xF) - Low += 0x37; - else if(Low >= 0x0 && Low <= 0x9) - Low += 0x30; - - result[j++] = High; - result[j++] = Low; + int i; + for (i = 0; i < hashbitlen / 8; i++) { + sprintf(&str[i * 2], "%02X", hash[i]); } - result[i] = 0; + str[i * 2 + 1] = '\0'; } -int HashWithMode(const char file_name[], char MsgDigest[], char mode) +int HashFile(const char file_name[], char MsgDigest[], char mode) { + int is_stdin = (strcmp(file_name, "-") == 0); + /* Try to get file info */ struct stat st; - if (stat(file_name, &st) < 0) { - printf("skein%dsum: %s: STAT FAILED: %s\n", hashbitlen, file_name, strerror(errno)); + st.st_size = 0; /* ..needed when reading from stdio */ + if (!is_stdin && stat(file_name, &st) < 0) { + WARN("%s: cannot stat: %s\n", file_name, strerror(errno)); return -1; } /* Get filesize */ size_t fsize = st.st_size; if (fsize != st.st_size) { - printf("skein%dsum: %s: SIZE WARNING: filesize %llu is too big for reading into memory!\n", - hashbitlen, file_name, (long long unsigned)st.st_size); + WARN("%s: SIZE WARNING: filesize %llu is too big for reading into memory!\n", + file_name, (long long unsigned)st.st_size); } /* Open file */ - FILE *fp_in = fopen(file_name, (mode == 't' ? "r" : "rb") ); + FILE *fp_in = is_stdin ? stdin : fopen(file_name, (mode == 't' ? "r" : "rb") ); if (!fp_in) { - printf("skein%dsum: %s: OPEN FAILED: %s\n", hashbitlen, file_name, strerror(errno)); + WARN("%s: cannot open: %s\n", file_name, strerror(errno)); return -1; } @@ -126,30 +113,37 @@ int HashWithMode(const char file_name[], char MsgDigest[], char mode) } if (!readbuf) { - printf("skein%dsum: %s: MEM FAILED: %s\n", hashbitlen, file_name, strerror(errno)); - fclose(fp_in); + WARN("%s: MEM FAILED: error %s\n", file_name, strerror(errno)); + if (!is_stdin) + fclose(fp_in); return -1; } /* Read contents */ - size_t readpos = 0, readed, total_readed = 0; + size_t readpos = 0, total_readed = 0; while (1) { size_t maxread = bufsize - readpos; - readed = fread(readbuf, 1, maxread, fp_in); + size_t readed = fread(readbuf + readpos, 1, maxread, fp_in); if (readed > 0 && readed <= maxread) total_readed += readed; if (readed != maxread) break; if (getenv("SKEIN_DEBUG")) - printf("DEBUG: bufsize=%u (0x%x), readpos=%u (0x%x), maxread=%u (0x%x), total=%u (0x%x)\n", - bufsize, bufsize, readpos, readpos, maxread, maxread, total_readed, total_readed); + printf("DEBUG: bufsize=%llu (0x%llx), readpos=%llu (0x%llx), maxread=%llu (0x%llx), total=%llu (0x%llx)\n", + (LLU)bufsize, (LLU)bufsize, (LLU)readpos, (LLU)readpos, + (LLU)maxread, (LLU)maxread, (LLU)total_readed, (LLU)total_readed); char *newbuf = NULL; if (bufsize * 2 > bufsize) /* ..check overflow */ newbuf = realloc(readbuf, bufsize * 2); if (!newbuf) { - printf("skein%dsum: %s: MEM WARNING: %u bytes only readed from %llu\n", - hashbitlen, file_name, total_readed, (long long unsigned)st.st_size); + if (total_readed < st.st_size) { + WARN("%s: MEM WARNING: %llu bytes only readed from %llu\n", + file_name, (LLU)total_readed, (LLU)st.st_size); + } else { + WARN("%s: MEM WARNING: %llu bytes only readed.\n", + file_name, (LLU)total_readed); + } break; } readbuf = newbuf; @@ -157,27 +151,34 @@ int HashWithMode(const char file_name[], char MsgDigest[], char mode) bufsize *= 2; } - if (total_readed < st.st_size && total_readed < bufsize) { - printf("skein%dsum: %s: READ WARNING: filesize=%llu, readed=%u, %s\n", - hashbitlen, file_name, (long long unsigned)st.st_size, total_readed, strerror(errno)); + if (!is_stdin) + fclose(fp_in); + + if (!is_stdin && total_readed < st.st_size && total_readed < bufsize) { + WARN("%s: READ WARNING: filesize=%llu, readed=%llu, error %d, %s\n", + file_name, (LLU)st.st_size, (LLU)total_readed, errno, strerror(errno)); } - fclose(fp_in); + if (getenv("SKEIN_DUMP")) { + printf("DEBUG: file=%s, bufsize=%llu (0x%llx), total_readed=%llu, buf:\n", + file_name, (LLU)bufsize, (LLU)bufsize, (LLU)total_readed); + fwrite(readbuf, 1, total_readed, stdout); + } unsigned char output[hashbitlen/4]; Hash(hashbitlen, (unsigned char*) readbuf, total_readed, output); free(readbuf); - printHexMsg(output,hashbitlen/4,MsgDigest); + hash2hexstr(output, MsgDigest); return 1; } -int PrintHash(const char filename[], int tag, char mode) +int PrintFileHash(const char filename[], int tag, char mode) { char MsgDigest[hashbitlen/2]; - if (HashWithMode(filename, MsgDigest, mode) < 0) + if (HashFile(filename, MsgDigest, mode) < 0) return -1; if (tag == 1) { printf("skein%d_v%s (%s) = %s\n", hashbitlen, skeinVersion, filename, MsgDigest); @@ -187,29 +188,7 @@ int PrintHash(const char filename[], int tag, char mode) return 1; } -void HashStringMode(const char Msg[], char MsgDigest[]) -{ - unsigned char output[hashbitlen/4]; - Hash(hashbitlen, (unsigned char*) Msg, strlen(Msg), output); - printHexMsg(output,hashbitlen/4,MsgDigest); -} - -void HashStdin(int tag) -{ - char MsgDigest[hashbitlen/2]; - char stri[100]; /* TODO!!! REWRITE THIS HARDCORE!!! */ - char longstring[1000]; - longstring[0] = 0; - while(fgets(stri,100,stdin)) - strcat(longstring, stri); - HashStringMode(longstring, MsgDigest); - if (tag == 1) { - printf("skein%d_v%s (-) = %s\n", hashbitlen, skeinVersion, MsgDigest); - } else { - printf("%s *-\n", MsgDigest); - } -} - +/* Return: -1 = Error, 0 = Mismatch, 1 = Match */ int HashMatch(const char StoredDigest[], const char *filename, int quiet) { char mode = 't'; @@ -219,78 +198,31 @@ int HashMatch(const char StoredDigest[], const char *filename, int quiet) } char MsgDigest[hashbitlen/2]; - if (HashWithMode(filename, MsgDigest, mode) < 0) - return 0; + if (HashFile(filename, MsgDigest, mode) < 0) + return -1; if (strcmp(MsgDigest, StoredDigest)) { printf("%s: FAILED\n", filename); return 0; } + if (quiet > 0) printf("%s: OK\n", filename); return 1; } -int VerifyHashesFromFile(FILE *fp, int status, int warn, int quiet) -{ - char hash[PATH_MAX + hashbitlen/4 + 4]; - char MsgDigest_tmp[hashbitlen/2]; - int NoMatch = 0, NotProper = 0, Computed = 0; - int line = 0; - - while (fgets(hash, sizeof(hash)-1, fp)) - { - char file_tmp[PATH_MAX]; - line ++; - Computed++; - int hashVersion = decomposeHashLine(hash,MsgDigest_tmp,file_tmp); - if (hashVersion == -1) - { - fprintf(stderr, "skein%d: %s is using newer version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen); - fprintf(stderr, "You should update your algorithm\n"); - continue; - } - else if (hashVersion == 0) - { - fprintf(stderr, "skein%d: %s is using an older version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen); - fprintf(stderr, "You should use the older algorithm\n"); - continue; - } - else if (!isProper(MsgDigest_tmp)) - { - if(status != 1 && warn == 1) - fprintf(stderr, "skein%dsum: %s: %d: improperly formatted skein%d checksum line\n",hashbitlen,file_tmp,line,hashbitlen); - NotProper ++; - NoMatch ++; - } - else if (!HashMatch(MsgDigest_tmp, file_tmp, quiet)) - { - NoMatch++; - } - } - if(NoMatch) - { - fprintf(stderr, "skein%dsum: WARNING: %d of %d computed checksums did NOT match\n", - hashbitlen,NoMatch,Computed); - } - if(NotProper) - { - fprintf(stderr, "skein%dsum: WARNING: %d line is improperly formatted\n",hashbitlen,NotProper); - } - return (NotProper || NoMatch) ? -1 : 1; -} - -int isProper(char MsgDigest[]) +int isProper(const char MsgDigest[]) { - if ((strlen(MsgDigest) - hashbitlen/4) != 0) + int len = strlen(MsgDigest); + if (len != (hashbitlen / 4)) return 0; int index = 0; - char c = 0; - for(index = 0; index < strlen(MsgDigest);index++) + for (index = 0; index < len; index++) { - c = MsgDigest[index]; - if(!(( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'F'))) - return 0; + char c = MsgDigest[index]; + if (c >= '0' && c <= '9') continue; + if (c >= 'A' && c <= 'F') continue; + return 0; } return 1; @@ -382,6 +314,58 @@ int decomposeHashLine(char hash[], char MsgDigest_tmp[], char file_tmp[]) } +/* Return: -1 = some errors/mismatches, 1 = all ok */ +int VerifyHashesFromFile(FILE *fp, int status, int warn, int quiet) +{ + char hash[PATH_MAX + hashbitlen/4 + 4]; + char MsgDigest_tmp[hashbitlen/2]; + int NoMatch = 0, NotProper = 0, Computed = 0; + int line = 0; + + while (fgets(hash, sizeof(hash)-1, fp)) + { + char file_tmp[PATH_MAX]; + line ++; + Computed++; + int hashVersion = decomposeHashLine(hash,MsgDigest_tmp,file_tmp); + if (hashVersion == -1) + { + WARN("%s is using newer version of skein%d algorithm\n" + "You should update your algorithm\n", + file_tmp, hashbitlen); + continue; + } + else if (hashVersion == 0) + { + WARN("%s is using an older version of skein%d algorithm\n" + "You should use the older algorithm\n", + file_tmp, hashbitlen); + continue; + } + else if (!isProper(MsgDigest_tmp)) + { + if(status != 1 && warn == 1) + WARN("%s: %d: improperly formatted skein%d checksum line\n",file_tmp,line,hashbitlen); + NotProper ++; + NoMatch ++; + } + else if (HashMatch(MsgDigest_tmp, file_tmp, quiet) <= 0) + { + NoMatch++; + } + } + if(NoMatch) + { + WARN("WARNING: %d of %d computed checksums did NOT match\n", + NoMatch, Computed); + } + if(NotProper) + { + WARN("WARNING: %d line is improperly formatted\n", NotProper); + } + return (NotProper || NoMatch) ? -1 : 1; +} + void print_version(void) { printf("skein%dsum 1.0\n", hashbitlen); @@ -428,26 +412,28 @@ int is_goodfile(const char filename[]) struct stat s; if (stat(filename, &s) < 0) { - fprintf(stderr, "skein%dsum: %s: no such file or directory\n", hashbitlen, filename); + WARN("%s: no such file or directory\n", filename); return 0; } - if (s.st_mode & (S_IFREG|S_IFBLK)) /* ..regular file or block device? */ - return 1; + if (S_ISREG (s.st_mode)) return 1; + if (S_ISCHR (s.st_mode)) return 1; + if (S_ISBLK (s.st_mode)) return 1; + if (S_ISLNK (s.st_mode)) return 1; + if (S_ISFIFO(s.st_mode)) return 1; - if (s.st_mode & S_IFDIR) { - fprintf(stderr, "skein%dsum: %s: is a directory\n", hashbitlen, filename); + if (S_ISDIR (s.st_mode)) { + WARN("%s: is a directory\n", filename); return 0; } - fprintf(stderr, "skein%dsum: %s: wrong filetype 0x%Xu\n", hashbitlen, filename, s.st_mode); - return 0; + WARN("%s: WARNING: unknown filetype 0x%Xu\n", filename, s.st_mode); + return 1; /* try it as good */ } int main(int argc, char** argv) { - int number_files = 0; int first_file = argc; int binary = -1, check = -1, @@ -462,7 +448,7 @@ int main(int argc, char** argv) /***************************************************************************************** ************************************* GETTING DATA *********************************** *****************************************************************************************/ - while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1) + while ((opt = getopt_long (argc, argv, "hVbctw", long_options, NULL)) != -1) { switch (opt) { case 0 : hashString = 1; break; @@ -474,8 +460,8 @@ int main(int argc, char** argv) case STATUS_OPTION : status = 1; break; case TAG_OPTION : tag = 1; break; - case HELP_OPTION : print_usage(); /* ..never returns */ - case VERSION_OPTION : print_version(); /* ..never returns */ + case 'h' : print_usage(); /* ..never returns */ + case 'V' : print_version(); /* ..never returns */ default: TRYHELP_GOODBYE(); } @@ -492,14 +478,16 @@ int main(int argc, char** argv) if (quiet == 1 || warn == 1 || status == 1) { if(quiet == 1) - fprintf(stderr, "skein%dsum: the --quiet option is meaningful only when verifying checksums\n", hashbitlen); + WARN("the --quiet option is meaningful only when verifying checksums\n"); if(status ==1) - fprintf(stderr, "skein%dsum: the --status option is meaningful only when verifying checksums\n", hashbitlen); + WARN("the --status option is meaningful only when verifying checksums\n"); if(warn == 1) - fprintf(stderr, "skein%dsum: the --warn option is meaningful only when verifying checksums\n", hashbitlen); + WARN("the --warn option is meaningful only when verifying checksums\n"); TRYHELP_GOODBYE(); } + char mode = binary > 0 ? 'b' : 't'; + int file_index; for (file_index = first_file; file_index < argc; file_index++) { @@ -508,20 +496,19 @@ int main(int argc, char** argv) errorFound++; continue; } - number_files++; if (binary > 0 && hashString == 1) { - printf("skein%dsum: %s: No such file or directory\n", hashbitlen, filename); + WARN("%s: No such file or directory\n", filename); continue; } - char mode = binary > 0 ? 'b' : 't'; - if (PrintHash(filename, tag, mode) < 0) + if (PrintFileHash(filename, tag, mode) < 0) errorFound++; } - if (!number_files && !errorFound) - HashStdin(tag); + if (first_file >= argc) /* no files in cmdline? hash stdin.. */ + if (PrintFileHash("-", tag, mode) < 0) + errorFound++; return (errorFound ? 1 : 0); } @@ -531,9 +518,9 @@ int main(int argc, char** argv) if (tag == 1 || binary >= 0) { if (tag == 1) - fprintf(stderr, "skein%dsum: the --tag option is meaningless when verifying checksums\n", hashbitlen); + WARN("the --tag option is meaningless when verifying checksums\n"); if (binary >= 0) - fprintf(stderr, "skein%dsum: the --text and --binary options are meaningless when verifying checksums\n", hashbitlen); + WARN("the --text and --binary options are meaningless when verifying checksums\n"); TRYHELP_GOODBYE(); } @@ -545,19 +532,20 @@ int main(int argc, char** argv) errorFound++; continue; } - number_files++; - FILE *fp = fopen(filename, "r"); + FILE *fp = (strcmp(filename, "-") == 0) ? stdin : fopen(filename, "r"); if (!fp) { - printf("skein%dsum: %s: error %d, %s\n", hashbitlen, filename, errno, strerror(errno)); + errorFound++; + WARN("%s: %s\n", filename, strerror(errno)); continue; } if (VerifyHashesFromFile(fp, status, warn, quiet) < 0) errorFound++; - fclose(fp); + if (fp != stdin) + fclose(fp); } - if (!number_files && !errorFound) + if (first_file >= argc) /* no files in cmdline? verify stdin.. */ if (VerifyHashesFromFile(stdin, status, warn, quiet) < 0) errorFound++;