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