12313362d43d51bc5baf678235ff4aff92635dcd
[skeinsum.git] / skein256.c
1 /* Copyright (C) 2014 Jason Self <j@jxself.org>
2
3 This file is part of skeinsum.
4
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.
9
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.
14
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/>.
17 */
18
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <dirent.h>
24 #include <getopt.h>
25 #include <malloc.h>
26 #include <math.h>
27 #include <glob.h>
28 #include <sys/stat.h>
29 #include "SHA3api_ref.h"
30
31 #define hashbitlen 256
32 #define MaxNmberFiles 10
33 #define skeinVersion "1.3"
34
35
36 char invalidOption = 0;
37
38 enum
39 {
40   QUIET_OPTION = 11,
41   STATUS_OPTION,
42   TAG_OPTION,
43   HELP_OPTION,
44   VERSION_OPTION
45 };
46
47 static struct option const long_options[] =
48 {
49   { "binary", no_argument, NULL, 'b' },
50   { "check", no_argument, NULL, 'c' },
51   { "quiet", no_argument, NULL, QUIET_OPTION },
52   { "status", no_argument, NULL, STATUS_OPTION },
53   { "text", no_argument, NULL, 't' },
54   { "warn", no_argument, NULL, 'w' },
55   { "tag", no_argument, NULL, TAG_OPTION },
56   { "help", no_argument, NULL, HELP_OPTION },
57   { "version", no_argument, NULL, VERSION_OPTION },
58   { NULL, 0, NULL, 0 }
59 };
60
61 void printHexMsg(unsigned char *ptr, int size, char result[])
62 {
63         int i = 0;
64         int j = 0;
65         char High, Low;
66         for (i = 0 ; i < size ; i ++)
67         {
68                 High = ptr[i]>>4;
69                 Low = ptr[i]&0x0F;
70
71                 if (High >= 0xA && High <= 0xF)
72                         High += 0x37;
73                 else if(High >= 0x0 && High <= 0x9)
74                         High += 0x30;
75
76                 if (Low >= 0xA && Low <= 0xF)
77                         Low += 0x37;
78                 else if(Low >= 0x0 && Low <= 0x9)
79                         Low += 0x30;
80
81                 result[j++] = High;
82                 result[j++] = Low;
83         }
84         result[i] = 0;
85 }
86
87 int HashTextMode(char file_name[], char MsgDigest[])
88 {
89         FILE *fp_in = fopen(file_name,"r");
90         struct stat st;
91         stat(file_name, &st);
92         long size_fp_in = st.st_size;
93
94         if(fp_in == NULL)
95         {
96                 printf("skein%dsum:  %s: No such file or directory\n",hashbitlen,file_name);
97                 printf(" %s FAILED open or read\n",file_name);
98                 return -1 ;
99         }
100
101         char *hello;
102         hello = (char*) malloc (size_fp_in);
103         fgets(hello,size_fp_in,fp_in);
104
105         unsigned char output[hashbitlen/4];
106         Hash(hashbitlen,(unsigned char*) hello,size_fp_in,output);
107
108         printHexMsg(output,hashbitlen/4,MsgDigest);
109
110         fclose(fp_in);
111         return 1;
112 }
113
114 int HashBinaryMode(char file_name[],char MsgDigest[])
115 {
116         FILE *fp_in = fopen(file_name,"rb");
117         struct stat st;
118         stat(file_name, &st);
119         long size_fp_in = st.st_size;
120
121         if(fp_in == NULL)
122         {
123                 printf("skein%dsum:  %s: No such file or directory\n",hashbitlen,file_name);
124                 printf(" %s FAILED open or read\n",file_name);
125                 return -1 ;
126         }
127
128         unsigned char *hello;
129         hello = (unsigned char*) malloc (size_fp_in);
130         fread(hello,size_fp_in,1,fp_in);
131
132         unsigned char output[hashbitlen/4];
133         Hash(hashbitlen,hello,size_fp_in,output);
134
135         printHexMsg(output,hashbitlen/4,MsgDigest);
136
137         fclose(fp_in);
138         return 1;
139 }
140
141 int HashStringMode(char Msg[],char MsgDigest[])
142 {
143         unsigned char output[hashbitlen/4];
144         Hash(hashbitlen,(unsigned char*) Msg,sizeof(Msg),output);
145         printHexMsg(output,hashbitlen/4,MsgDigest);
146         return 1;
147 }
148
149 /*
150  *  return 1 : is File
151  *  return 2 : is Directory
152  *  return -1 : Something else.
153  */
154 int isFile(char argument[])
155 {
156         struct stat s;
157         if( stat(argument,&s) == 0 )
158         {
159             if( s.st_mode & S_IFDIR )
160             {
161                 return 2;
162             }
163             else if( s.st_mode & S_IFREG )
164             {
165                 return 1;
166             }
167         }
168         else
169                 return -1;
170         return 0;
171 }
172
173 int isProper(char MsgDigest[])
174 {
175         if ((strlen(MsgDigest) - hashbitlen/4) != 0)
176                 return 0;
177         int index = 0;
178         char c = 0;
179         for(index = 0; index < strlen(MsgDigest);index++)
180         {
181                 c = MsgDigest[index];
182                 if(!(( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'F')))
183                         return 0;
184         }
185
186         return 1;
187 }
188
189
190 int decomposeHashLine(char hash[], char MsgDigest_tmp[], char file_tmp[])
191 {
192         char c = 0;
193         int i = 0 , j =0;
194         int isTagFile = 0;
195         char alg[20];
196         char tmp[1000];
197         while(((c = hash[i])!=' ')&&((c = hash[i])!='_'))
198         {
199                 tmp[i] = hash[i];
200                 i++;
201         }
202         tmp[i] = 0;
203
204         sprintf(alg,"skein%d",hashbitlen);
205         if(!strcmp(alg,tmp))
206         {
207                 isTagFile = 1;
208         }
209
210         if(isTagFile == 0)
211         {
212                 strcpy(MsgDigest_tmp,tmp);
213                 i++;
214                 while((c = hash[i])!= '\n')
215                 {
216                         file_tmp[j] = hash[i];
217                         i++;
218                         j++;
219                 }
220                 file_tmp[j] = 0;
221         }
222         else if((hash[i]=='_')&&(hash[i+1]=='v'))
223         {
224                 i = i + 2;
225                 j = 0;
226                 char version[5];
227                 while((c = hash[i])!=' ')
228                 {
229                         version[j] = hash[i];
230                         i++;
231                         j++;
232                 }
233                 version[i] = 0;
234                 float vers = 0, skeinVers = 0;
235                 sscanf(version,"%f",&vers);
236                 sscanf(skeinVersion,"%f",&skeinVers);
237
238                 j = 0;
239                 i = i + 2;
240                 while((c = hash[i])!=')')
241                 {
242                         file_tmp[j] = hash[i];
243                         i++;
244                         j++;
245                 }
246                 file_tmp[j] = 0;
247
248                 i = i + 4;
249                 j = 0;
250                 while((c = hash[i])!='\n')
251                 {
252                         MsgDigest_tmp[j] = hash[i];
253                         i++;
254                         j++;
255                 }
256                 MsgDigest_tmp[j] = 0;
257
258                 if(skeinVers < vers)
259                 {//version newer than mine
260                         return (-1);
261                 }
262                 else if (skeinVers > vers)
263                 {//going to use older version than mine
264                         return (0) ;
265                 }
266                 else
267                 { //versions match
268                         return (1);
269                 }
270         }
271         return 1;
272
273 }
274
275
276
277 int main(int argc, char** argv)
278 {
279         char MsgDigest[hashbitlen/2];
280         char **list_files = (char**) malloc(MaxNmberFiles* sizeof(char*));
281         int number_files = 0;
282         int binary = -1,
283                  check = -1,
284                  quiet = -1,
285                  warn = -1,
286                  status = -1,
287                  help = -1,
288                  version = -1,
289                  tag = -1,
290                  hashString = -1,
291                  badParam = -1;
292
293         int errorFound = 0;
294         int opt = 0;
295 /*****************************************************************************************
296  ************************************* GETTING DATA ***********************************
297  *****************************************************************************************/
298   while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
299   {
300           switch (opt)
301           {
302                         case 'b' :
303                         {
304                                 binary = 1;
305                                 break;
306                         }
307                         case 't' :
308                         {
309                                 binary = 0;
310                                 break;
311                         }
312                         case 'c' :
313                         {
314                                 check = 1;
315                                 break;
316                         }
317                         case QUIET_OPTION :
318                         {
319                                 quiet = 1;
320                                 break;
321                         }
322                         case 'w' :
323                         {
324                                 warn = 1;
325                                 break;
326                         }
327                         case STATUS_OPTION :
328                         {
329                                 status = 1;
330                                 break;
331                         }
332                         case HELP_OPTION :
333                         {
334                                 help = 1;
335                                 break;
336                         }
337                         case VERSION_OPTION :
338                         {
339                                 version = 1;
340                                 break;
341                         }
342                         case TAG_OPTION :
343                         {
344                                 tag = 1;
345                                 break;
346                         }
347                         case 0 :
348                         {
349                                 hashString = 1;
350                                 break;
351                         }
352                         default :
353                         {
354                                 badParam = 1;
355                                 break;
356                         }
357           }
358         }
359
360   if(badParam == 1)
361         {
362                 printf("Try `skein%dsum --help' for more information.\n",hashbitlen);
363                 exit(1);
364         }
365
366   for (; optind < argc; ++optind)
367   {
368                 switch (opt)
369                 {
370                         case -1:
371                         {// no options found, test if there is a file and hash it
372                                 if(isFile(argv[optind]) == 1)
373                                 {
374                                         char *file_name = malloc(sizeof(argv[optind]));
375                                         file_name = argv[optind];
376                                         list_files[number_files] = (char*) malloc (sizeof(file_name));
377                                         list_files[number_files] = file_name;
378                                         number_files ++;
379                                 }
380                                 else if (isFile(argv[optind]) == 2)
381                                 {
382                                         printf("skein%dsum: %s Is a directory\n",hashbitlen,argv[optind]);
383                                         errorFound = 1;
384                                 }
385                                 else
386                                 {
387                                         printf("skein%dsum: %s: No such file or directory\n",hashbitlen,argv[optind]);
388                                         errorFound = 1;
389                                 }
390                                 break;
391                         }
392                 }
393         }
394 /*****************************************************************************************
395  ************************************* PROCESSING DATA ***********************************
396  *****************************************************************************************/
397         if(argc > 1 && version == 1)
398         {
399                 printf("skein256sum 1.0\n");
400                 printf("License GPLv3+: GNU GPL version 3 or later\n");
401                 printf("<http://gnu.org/licenses/gpl.html>\n");
402                 printf("This is free software: you are free to change and redistribute it.\n");
403                 printf("There is NO WARRANTY, to the extent permitted by law.\n");
404                 exit(1);
405         }
406         if(argc > 1 && help == 1)
407         {
408
409                 printf("Usage: skein%dsum [OPTION]... [FILE]...\n",hashbitlen);
410                 printf("Print or check skein (%d-bit) checksums.\n",hashbitlen);
411                 printf("With no FILE, or when FILE is -, read standard input.\n");
412                 printf("\n");
413                 printf("-b, --binary         read in binary mode\n");
414                 printf("-c, --check          read skein sums from the FILEs and check them\n");
415                 printf("--tag            create a BSD-style checksum\n");
416                 printf("-t, --text           read in text mode (default)\n");
417                 printf("\n");
418                 printf("The following three options are useful only when verifying checksums:\n");
419                 printf("--quiet          don't print OK for each successfully verified file\n");
420                 printf("--status         don't output anything, status code shows success\n");
421                 printf("-w, --warn           warn about improperly formatted checksum lines\n");
422                 printf("\n");
423                 printf("--strict         with --check, exit non-zero for any invalid input\n");
424                 printf("--help     display this help and exit\n");
425                 printf("--version  output version information and exit\n");
426                 printf("\n");
427                 printf("The sums are computed as described in version 1.3 of the Skein\n");
428                 printf("specification. When checking, the input should be a former output of\n");
429                 printf("this program. The default mode is to print a line with checksum, a\n");
430                 printf("character indicating input mode ('*' for binary, space for text), and\n");
431                 printf("name for each FILE.\n");
432                 exit(1);
433         }
434
435         if(argc > 1 && binary == 1)
436         {
437                 if (check == 1 || quiet == 1 || warn == 1 || status == 1)
438                 {
439                         printf("skein%dsum: the --binary and --text options are meaningless when verifying checksums\n",hashbitlen);
440                         printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
441                         exit(0);
442                 }
443                 if(number_files > 0)
444                 {
445                         int index_files = 0;
446                         while(index_files < number_files)
447                         {
448                                 if(hashString == 1)
449                                 {
450                                         printf("skein%dsum: %s: No such file or directory\n",hashbitlen,list_files[index_files]);
451                                         index_files++;
452                                         continue;
453                                 }
454                                 if(HashBinaryMode(list_files[index_files],MsgDigest)!=-1)
455                                 {
456                                         if(tag == 1)
457                                         {
458                                                 printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
459                                         }
460                                         else
461                                         {
462                                                 printf("%s ",MsgDigest);
463                                                 printf("*%s\n",list_files[index_files]);
464                                         }
465                                 }
466                                 index_files++;
467                         }
468                 }
469                 else if(errorFound != 1)
470                 { // read stdin for strings
471                         char stri[100];
472                         char longstring[1000];
473                         longstring[0] = 0;
474                         while((fgets(stri,100,stdin))!=NULL)
475                         {
476                                 strcat(longstring,stri);
477                         }
478                         HashStringMode(longstring,MsgDigest);
479                         if(tag == 1)
480                         {
481                                 printf("skein%d_v%s (-) = %s\n",hashbitlen,skeinVersion,MsgDigest);
482                         }
483                         else
484                         {
485                                 printf("%s *-\n",MsgDigest);
486                         }
487                 }
488         }
489
490         else if (argc > 1 && binary == 0) // Text Mode
491         {
492                 if (check == 1 || quiet == 1 || warn == 1 || status == 1)
493                 {
494                         printf("skein%dsum: the --binary and --text options are meaningless when verifying checksums\n",hashbitlen);
495                         printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
496                         exit(0);
497                 }
498                 if(number_files > 0)
499                 {
500                         int index_files = 0;
501                         while(index_files < number_files)
502                         {
503                                 if(HashTextMode(list_files[index_files],MsgDigest)!=-1)
504                                 {
505                                         if(tag == 1)
506                                         {
507                                                 printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
508                                         }
509                                         else
510                                         {
511                                                 printf("%s ",MsgDigest);
512                                                 printf("%s\n",list_files[index_files]);
513                                         }
514                                 }
515                                 index_files++;
516                         }
517                 }
518                 else if(errorFound != 1)
519                 { // read stdin for strings
520                         char stri[100];
521                         char longstring[1000];
522                         longstring[0] = 0;
523                         while((fgets(stri,100,stdin))!=NULL)
524                         {
525                                 strcat(longstring,stri);
526                         }
527                         HashStringMode(longstring,MsgDigest);
528                         if(tag == 1)
529                         {
530                                 printf("skein%d_v%s (-) = %s\n",hashbitlen,skeinVersion,MsgDigest);
531                         }
532                         else
533                         {
534                                 printf("%s -\n",MsgDigest);
535                         }
536                 }
537         }
538
539         else if (argc > 1 && binary == -1)
540         {
541                 if(check == -1)
542                 {// hashing stdin entries
543                         if(quiet == 1 || status == 1 || warn == 1)
544                         {
545                                 if(quiet == 1)
546                                         printf("skein%dsum: the --quiet option is meaningful only when verifying checksums\n",hashbitlen);
547                                 if(status ==1)
548                                         printf("skein%dsum: the --status option is meaningful only when verifying checksums\n",hashbitlen);
549                                 if(warn == 1)
550                                         printf("skein%dsum: the --warn option is meaningful only when verifying checksums\n",hashbitlen);
551
552                                 printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
553                                 exit(1);
554                         }
555                         if(number_files > 0)
556                         {// hashing files
557                                 int index_files = 0;
558                                 while(index_files < number_files)
559                                 {
560                                         if(HashTextMode(list_files[index_files],MsgDigest)!=-1)
561                                         {
562                                                 if(tag == 1)
563                                                 {
564                                                         printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
565                                                 }
566                                                 else
567                                                 {
568                                                         printf("%s ",MsgDigest);
569                                                         printf("%s\n",list_files[index_files]);
570                                                 }
571                                         }
572                                         index_files++;
573                                 }
574                         }
575                         else if(errorFound != 1)
576                         { // hasing strings read from  stdin
577                                 char stri[100];
578                                 char longstring[1000];
579                                 longstring[0] = 0;
580                                 while((fgets(stri,100,stdin))!=NULL)
581                                 {
582                                         strcat(longstring,stri);
583                                 }
584                                 HashStringMode(longstring,MsgDigest);
585                                 if(tag == 1)
586                                 {
587                                         printf("skein%d_v%s (-) = %s\n",hashbitlen,skeinVersion,MsgDigest);
588                                 }
589                                 else
590                                 {
591                                         printf("%s -\n",MsgDigest);
592                                 }
593                         }
594                 }
595                 else if(check == 1)
596                 {
597                         if(tag == 1)
598                         {
599                                 printf("skein%dsum: the --tag option is meaningless when verifying checksums\n",hashbitlen);
600                                 printf("Try 'skein%dsum --help' for more information\n",hashbitlen);
601                                 exit(1);
602                         }
603                         int index_files = 0;
604                         while(index_files < number_files)
605                         {
606                                 FILE *fp;
607                                 char hash[100], file_name[100], file_tmp[100], MsgDigest_tmp[hashbitlen/2];
608                                 int NoMatch = 0, NotProper = 0, Computed = 0;
609                                 strcpy(file_name,list_files[index_files]);
610                                 //show everything
611                                 int line = 0;
612                                 fp = fopen(file_name,"r");
613                                 if(fp!=NULL)
614                                 {
615                                         while(fgets(hash,500,fp)!=NULL)
616                                         {
617                                                 line ++;
618                                                 Computed++;
619                                                 unsigned int hashVersion = decomposeHashLine(hash,MsgDigest_tmp,file_tmp);
620                                                 if(hashVersion == -1)
621                                                 {
622                                                         printf("skein%d: %s is using newer version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen);
623                                                         printf("You should update your algorithm\n");
624                                                         continue;
625                                                 }
626                                                 else if( hashVersion == 0)
627                                                 {
628                                                         printf("skein%d: %s is using an older version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen);
629                                                         printf("You should use the older algorithm\n");
630                                                         continue;
631                                                 }
632                                                 else
633                                                 {
634                                                         if(!isProper(MsgDigest_tmp))
635                                                         {
636                                                                 if(status != 1 && warn == 1)
637                                                                 {
638                                                                         printf("skein%dsum: %s: %d: improperly formatted skein%d checksum line\n",hashbitlen,file_tmp,line,hashbitlen);
639                                                                 }
640                                                                 NotProper ++;
641                                                                 NoMatch ++;
642                                                                 continue;
643                                                         }
644                                                         if(file_tmp[0] == '*')
645                                                         {
646                                                                 int index_file_tmp = 0;
647                                                                 for( ; file_tmp[index_file_tmp+1]!=0 ; index_file_tmp++)
648                                                                 {
649                                                                         file_tmp[index_file_tmp] = file_tmp[index_file_tmp + 1];
650                                                                 }
651                                                                 file_tmp[index_file_tmp] = 0;
652                                                                 HashBinaryMode(file_tmp,MsgDigest);
653                                                         }
654                                                         else
655                                                         {
656                                                                 HashTextMode(file_tmp,MsgDigest);
657                                                         }
658
659                                                         if(!strcmp(MsgDigest,MsgDigest_tmp))
660                                                         {
661                                                                 if(quiet != 1)
662                                                                 {
663                                                                         printf("%s: OK\n",file_tmp);
664                                                                 }
665                                                         }
666                                                         else
667                                                         {
668                                                                 printf("%s: FAILED\n",file_tmp);
669                                                                 NoMatch ++;
670                                                         }
671                                                 }
672                                         }
673                                         if(NoMatch)
674                                         {
675                                                 printf("skein%dsum: WARNING: %d of %d computed checksums did NOT match\n",
676                                                                 hashbitlen,NoMatch,Computed);
677                                         }
678                                         if(NotProper)
679                                         {
680                                                 printf("skein%dsum: WARNING: %d line is improperly formatted\n",hashbitlen,NotProper);
681                                         }
682                                 }
683                                 else
684                                 {
685                                         printf("skein%dsum: %s: No such file or directory\n",hashbitlen,file_name);
686                                 }
687                                 index_files++;
688
689                         }
690
691                         if(number_files  == 0)
692                         {
693                                 char longstring[1000];
694                                 char file_name[30];
695                                 char MsgDigest_tmp[hashbitlen/2];
696                                 int Computed = 0, NotProper = 0, NoMatch = 0 , line = 0;
697                                 while((fgets(longstring,1000,stdin))!=NULL)
698                                 {
699                                         Computed++;
700                                         line ++;
701                                         decomposeHashLine(longstring,MsgDigest_tmp,file_name);
702                                         if(!isProper(MsgDigest_tmp))
703                                         {
704                                                 if(status != 1 && warn == 1)
705                                                 {
706                                                         printf("skein%dsum: %s: %d: improperly formatted skein%d checksum line\n",hashbitlen,file_name,line,hashbitlen);
707                                                 }
708                                                 NotProper ++;
709                                                 NoMatch ++;
710                                                 continue;
711                                         }
712                                         if(file_name[0] == '*')
713                                         {
714                                                 int index_file_tmp = 0;
715                                                 for( ; file_name[index_file_tmp+1]!=0 ; index_file_tmp++)
716                                                 {
717                                                         file_name[index_file_tmp] = file_name[index_file_tmp + 1];
718                                                 }
719                                                 file_name[index_file_tmp] = 0;
720                                                 HashBinaryMode(file_name,MsgDigest);
721                                         }
722                                         else
723                                         {
724                                                 HashTextMode(file_name,MsgDigest);
725                                         }
726
727                                         if(!strcmp(MsgDigest,MsgDigest_tmp))
728                                         {
729                                                 if(quiet != 1)
730                                                 {
731                                                         printf("%s: OK\n",file_name);
732                                                 }
733                                         }
734                                         else
735                                         {
736                                                 printf("%s: FAILED\n",file_name);
737                                                 NoMatch ++;
738                                         }
739                                 }
740                                 if(NoMatch)
741                                 {
742                                         printf("skein%dsum: WARNING: %d of %d computed checksums did NOT match\n",
743                                                         hashbitlen,NoMatch,Computed);
744                                 }
745                                 if(NotProper)
746                                 {
747                                         printf("skein%dsum: WARNING: %d line is improperly formatted\n",hashbitlen,NotProper);
748                                 }
749
750                         }
751
752
753                 }
754         }
755
756         if ((errorFound != 1) && (argc == 1 || (hashString == 1 && number_files == 0)))
757         {
758                 char stri[100];
759                 char longstring[1000];
760                 longstring[0] = 0;
761                 while((fgets(stri,100,stdin))!=NULL)
762                 {
763                                 strcat(longstring,stri);
764                 }
765                 HashStringMode(longstring,MsgDigest);
766                 printf("%s -\n",MsgDigest);
767         }
768
769         return 1;
770 }