1 /* Copyright (C) 2014 2015 Jason Self <j@jxself.org>
3 This file is part of skeinsum.
5 skeinsum is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 skeinsum is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with skeinsum. If not, see <http://www.gnu.org/licenses/>.
32 #include "SHA3api_ref.h"
34 extern const int hashbitlen;
36 #define MaxNmberFiles 10
37 #define skeinVersion "1.3"
38 const size_t input_minbufsize = 32 * 1024;
39 const size_t input_maxbufsize = 32 * 1024 * 1024;
42 char invalidOption = 0;
53 static struct option const long_options[] =
55 { "binary", no_argument, NULL, 'b' },
56 { "check", no_argument, NULL, 'c' },
57 { "quiet", no_argument, NULL, QUIET_OPTION },
58 { "status", no_argument, NULL, STATUS_OPTION },
59 { "text", no_argument, NULL, 't' },
60 { "warn", no_argument, NULL, 'w' },
61 { "tag", no_argument, NULL, TAG_OPTION },
62 { "help", no_argument, NULL, HELP_OPTION },
63 { "version", no_argument, NULL, VERSION_OPTION },
67 void printHexMsg(unsigned char *ptr, int size, char result[])
72 for (i = 0 ; i < size ; i ++)
77 if (High >= 0xA && High <= 0xF)
79 else if(High >= 0x0 && High <= 0x9)
82 if (Low >= 0xA && Low <= 0xF)
84 else if(Low >= 0x0 && Low <= 0x9)
93 int HashWithMode(char file_name[], char MsgDigest[], char mode)
95 /* Try to get file info */
97 if (stat(file_name, &st) < 0) {
98 printf("skein%dsum: %s: STAT FAILED: %s\n", hashbitlen, file_name, strerror(errno));
103 size_t fsize = st.st_size;
104 if (fsize != st.st_size) {
105 printf("skein%dsum: %s: SIZE WARNING: filesize %llu is too big for reading into memory!\n",
106 hashbitlen, file_name, (long long unsigned)st.st_size);
110 FILE *fp_in = fopen(file_name, (mode == 't' ? "r" : "rb") );
112 printf("skein%dsum: %s: OPEN FAILED: %s\n", hashbitlen, file_name, strerror(errno));
116 /* Allocate buffer */
117 size_t bufsize = fsize + 1;
118 if (bufsize < input_minbufsize)
119 bufsize = input_minbufsize;
121 char *readbuf = malloc (bufsize);
122 if (!readbuf && bufsize > input_maxbufsize) { /* ..Try to get contents by smaller portions */
123 bufsize = input_maxbufsize;
124 readbuf = malloc (bufsize);
128 printf("skein%dsum: %s: MEM FAILED: %s\n", hashbitlen, file_name, strerror(errno));
134 size_t readpos = 0, readed, total_readed = 0;
137 size_t maxread = bufsize - readpos;
138 readed = fread(readbuf, 1, maxread, fp_in);
139 if (readed > 0 && readed <= maxread)
140 total_readed += readed;
141 if (readed != maxread)
143 if (getenv("SKEIN_DEBUG"))
144 printf("DEBUG: bufsize=%u (0x%x), readpos=%u (0x%x), maxread=%u (0x%x), total=%u (0x%x)\n",
145 bufsize, bufsize, readpos, readpos, maxread, maxread, total_readed, total_readed);
147 if (bufsize * 2 > bufsize) /* ..check overflow */
148 newbuf = realloc(readbuf, bufsize * 2);
150 printf("skein%dsum: %s: MEM WARNING: %u bytes only readed from %llu\n",
151 hashbitlen, file_name, total_readed, (long long unsigned)st.st_size);
159 if (total_readed < st.st_size && total_readed < bufsize) {
160 printf("skein%dsum: %s: READ WARNING: filesize=%llu, readed=%u, %s\n",
161 hashbitlen, file_name, (long long unsigned)st.st_size, total_readed, strerror(errno));
166 unsigned char output[hashbitlen/4];
167 Hash(hashbitlen, (unsigned char*) readbuf, total_readed, output);
171 printHexMsg(output,hashbitlen/4,MsgDigest);
176 int HashTextMode(char file_name[], char MsgDigest[])
178 return HashWithMode(file_name, MsgDigest, 't');
181 int HashBinaryMode(char file_name[], char MsgDigest[])
183 return HashWithMode(file_name, MsgDigest, 'b');
186 void HashStringMode(char Msg[],char MsgDigest[])
188 unsigned char output[hashbitlen/4];
189 Hash(hashbitlen,(unsigned char*) Msg,sizeof(Msg),output);
190 printHexMsg(output,hashbitlen/4,MsgDigest);
193 void HashStdin(char MsgDigest[], int tag)
196 char longstring[1000];
198 while(fgets(stri,100,stdin))
199 strcat(longstring, stri);
200 HashStringMode(longstring, MsgDigest);
202 printf("skein%d_v%s (-) = %s\n", hashbitlen, skeinVersion, MsgDigest);
204 printf("%s *-\n", MsgDigest);
208 int isProper(char MsgDigest[])
210 if ((strlen(MsgDigest) - hashbitlen/4) != 0)
214 for(index = 0; index < strlen(MsgDigest);index++)
216 c = MsgDigest[index];
217 if(!(( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'F')))
225 int decomposeHashLine(char hash[], char MsgDigest_tmp[], char file_tmp[])
232 while(((c = hash[i])!=' ')&&((c = hash[i])!='_'))
239 sprintf(alg,"skein%d",hashbitlen);
247 strcpy(MsgDigest_tmp,tmp);
249 while((c = hash[i])!= '\n')
251 file_tmp[j] = hash[i];
257 else if((hash[i]=='_')&&(hash[i+1]=='v'))
262 while((c = hash[i])!=' ')
264 version[j] = hash[i];
269 float vers = 0, skeinVers = 0;
270 sscanf(version,"%f",&vers);
271 sscanf(skeinVersion,"%f",&skeinVers);
275 while((c = hash[i])!=')')
277 file_tmp[j] = hash[i];
285 while((c = hash[i])!='\n')
287 MsgDigest_tmp[j] = hash[i];
291 MsgDigest_tmp[j] = 0;
294 {//version newer than mine
297 else if (skeinVers > vers)
298 {//going to use older version than mine
310 void print_version(void)
312 printf("skein%dsum 1.0\n", hashbitlen);
313 printf("License GPLv3+: GNU GPL version 3 or later\n");
314 printf("<http://gnu.org/licenses/gpl.html>\n");
315 printf("This is free software: you are free to change and redistribute it.\n");
316 printf("There is NO WARRANTY, to the extent permitted by law.\n");
320 void print_usage(void)
322 printf("Usage: skein%dsum [OPTION]... [FILE]...\n",hashbitlen);
323 printf("Print or check skein (%d-bit) checksums.\n",hashbitlen);
324 printf("With no FILE, or when FILE is -, read standard input.\n");
326 printf("-b, --binary read in binary mode\n");
327 printf("-c, --check read skein sums from the FILEs and check them\n");
328 printf("--tag create a BSD-style checksum\n");
329 printf("-t, --text read in text mode (default)\n");
331 printf("The following three options are useful only when verifying checksums:\n");
332 printf("--quiet don't print OK for each successfully verified file\n");
333 printf("--status don't output anything, status code shows success\n");
334 printf("-w, --warn warn about improperly formatted checksum lines\n");
336 printf("--strict with --check, exit non-zero for any invalid input\n");
337 printf("--help display this help and exit\n");
338 printf("--version output version information and exit\n");
340 printf("The sums are computed as described in version 1.3 of the Skein\n");
341 printf("specification. When checking, the input should be a former output of\n");
342 printf("this program. The default mode is to print a line with checksum, a\n");
343 printf("character indicating input mode ('*' for binary, space for text), and\n");
344 printf("name for each FILE.\n");
350 int main(int argc, char** argv)
352 char MsgDigest[hashbitlen/2];
353 char *list_files[MaxNmberFiles];
354 int number_files = 0;
365 /*****************************************************************************************
366 ************************************* GETTING DATA ***********************************
367 *****************************************************************************************/
368 while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
371 case 0 : hashString = 1; break;
372 case 'b' : binary = 1; break;
373 case 't' : binary = 0; break;
374 case 'c' : check = 1; break;
375 case 'w' : warn = 1; break;
376 case QUIET_OPTION : quiet = 1; break;
377 case STATUS_OPTION : status = 1; break;
378 case TAG_OPTION : tag = 1; break;
380 case HELP_OPTION : print_usage(); /* ..never returns */
381 case VERSION_OPTION : print_version(); /* ..never returns */
384 printf("Try `skein%dsum --help' for more information.\n",hashbitlen);
389 for (; optind < argc; ++optind)
392 if (stat(argv[optind], &s) < 0)
394 printf("skein%dsum: %s: no such file or directory\n", hashbitlen, argv[optind]);
397 else if (s.st_mode & (S_IFREG|S_IFBLK)) /* ..regular file or block device? */
399 if (number_files < MaxNmberFiles) {
400 list_files[number_files++] = argv[optind];
402 printf("skein%dsum: %s: ignore because filelist is too long\n",
403 hashbitlen, argv[optind]);
406 else if (s.st_mode & S_IFDIR)
408 printf("skein%dsum: %s: is a directory\n",hashbitlen,argv[optind]);
413 printf("skein%dsum: %s: wrong filetype 0x%Xu\n",
414 hashbitlen, argv[optind], s.st_mode);
419 /*****************************************************************************************
420 ************************************* PROCESSING DATA ***********************************
421 *****************************************************************************************/
422 if(argc > 1 && binary == 1)
424 if (check == 1 || quiet == 1 || warn == 1 || status == 1)
426 printf("skein%dsum: the --binary and --text options are meaningless when verifying checksums\n",hashbitlen);
427 printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
433 while(index_files < number_files)
437 printf("skein%dsum: %s: No such file or directory\n",hashbitlen,list_files[index_files]);
441 if(HashBinaryMode(list_files[index_files],MsgDigest)!=-1)
445 printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
449 printf("%s ",MsgDigest);
450 printf("*%s\n",list_files[index_files]);
456 else if(errorFound != 1)
458 HashStdin(MsgDigest, tag);
462 else if (argc > 1 && binary == 0) // Text Mode
464 if (check == 1 || quiet == 1 || warn == 1 || status == 1)
466 printf("skein%dsum: the --binary and --text options are meaningless when verifying checksums\n",hashbitlen);
467 printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
473 while(index_files < number_files)
475 if(HashTextMode(list_files[index_files],MsgDigest)!=-1)
479 printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
483 printf("%s ",MsgDigest);
484 printf("%s\n",list_files[index_files]);
490 else if(errorFound != 1)
492 HashStdin(MsgDigest, tag);
496 else if (argc > 1 && binary == -1)
499 {// hashing stdin entries
500 if(quiet == 1 || status == 1 || warn == 1)
503 printf("skein%dsum: the --quiet option is meaningful only when verifying checksums\n",hashbitlen);
505 printf("skein%dsum: the --status option is meaningful only when verifying checksums\n",hashbitlen);
507 printf("skein%dsum: the --warn option is meaningful only when verifying checksums\n",hashbitlen);
509 printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
515 while(index_files < number_files)
517 if(HashTextMode(list_files[index_files],MsgDigest)!=-1)
521 printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
525 printf("%s ",MsgDigest);
526 printf("%s\n",list_files[index_files]);
532 else if(errorFound != 1)
534 HashStdin(MsgDigest, tag);
541 printf("skein%dsum: the --tag option is meaningless when verifying checksums\n",hashbitlen);
542 printf("Try 'skein%dsum --help' for more information\n",hashbitlen);
546 while(index_files < number_files)
549 char hash[500], file_name[100], file_tmp[100], MsgDigest_tmp[hashbitlen/2];
550 int NoMatch = 0, NotProper = 0, Computed = 0;
551 strcpy(file_name,list_files[index_files]);
554 fp = fopen(file_name,"r");
557 while(fgets(hash,500,fp)!=NULL)
561 unsigned int hashVersion = decomposeHashLine(hash,MsgDigest_tmp,file_tmp);
562 if(hashVersion == -1)
564 printf("skein%d: %s is using newer version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen);
565 printf("You should update your algorithm\n");
568 else if( hashVersion == 0)
570 printf("skein%d: %s is using an older version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen);
571 printf("You should use the older algorithm\n");
576 if(!isProper(MsgDigest_tmp))
578 if(status != 1 && warn == 1)
580 printf("skein%dsum: %s: %d: improperly formatted skein%d checksum line\n",hashbitlen,file_tmp,line,hashbitlen);
586 if(file_tmp[0] == '*')
588 int index_file_tmp = 0;
589 for( ; file_tmp[index_file_tmp+1]!=0 ; index_file_tmp++)
591 file_tmp[index_file_tmp] = file_tmp[index_file_tmp + 1];
593 file_tmp[index_file_tmp] = 0;
594 HashBinaryMode(file_tmp,MsgDigest);
598 HashTextMode(file_tmp,MsgDigest);
601 if(!strcmp(MsgDigest,MsgDigest_tmp))
605 printf("%s: OK\n",file_tmp);
610 printf("%s: FAILED\n",file_tmp);
617 printf("skein%dsum: WARNING: %d of %d computed checksums did NOT match\n",
618 hashbitlen,NoMatch,Computed);
622 printf("skein%dsum: WARNING: %d line is improperly formatted\n",hashbitlen,NotProper);
627 printf("skein%dsum: %s: No such file or directory\n",hashbitlen,file_name);
633 if(number_files == 0)
635 char longstring[1000];
637 char MsgDigest_tmp[hashbitlen/2];
638 int Computed = 0, NotProper = 0, NoMatch = 0 , line = 0;
639 while((fgets(longstring,1000,stdin))!=NULL)
643 decomposeHashLine(longstring,MsgDigest_tmp,file_name);
644 if(!isProper(MsgDigest_tmp))
646 if(status != 1 && warn == 1)
648 printf("skein%dsum: %s: %d: improperly formatted skein%d checksum line\n",hashbitlen,file_name,line,hashbitlen);
654 if(file_name[0] == '*')
656 int index_file_tmp = 0;
657 for( ; file_name[index_file_tmp+1]!=0 ; index_file_tmp++)
659 file_name[index_file_tmp] = file_name[index_file_tmp + 1];
661 file_name[index_file_tmp] = 0;
662 HashBinaryMode(file_name,MsgDigest);
666 HashTextMode(file_name,MsgDigest);
669 if(!strcmp(MsgDigest,MsgDigest_tmp))
673 printf("%s: OK\n",file_name);
678 printf("%s: FAILED\n",file_name);
684 printf("skein%dsum: WARNING: %d of %d computed checksums did NOT match\n",
685 hashbitlen,NoMatch,Computed);
689 printf("skein%dsum: WARNING: %d line is improperly formatted\n",hashbitlen,NotProper);
698 if (!errorFound && (argc == 1 || (hashString == 1 && !number_files)))
699 HashStdin(MsgDigest, 0);