util/mkerr.pl: fix perl warning
[openssl.git] / fips / des / fips_desmovs.c
1 /* ====================================================================
2  * Copyright (c) 2004 The OpenSSL Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the OpenSSL Project
19  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
20  *
21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    openssl-core@openssl.org.
25  *
26  * 5. Products derived from this software may not be called "OpenSSL"
27  *    nor may "OpenSSL" appear in their names without prior written
28  *    permission of the OpenSSL Project.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the OpenSSL Project
33  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  *
48  */
49 /*---------------------------------------------
50   NIST DES Modes of Operation Validation System
51   Test Program
52
53   Based on the AES Validation Suite, which was:
54   Donated to OpenSSL by:
55   V-ONE Corporation
56   20250 Century Blvd, Suite 300
57   Germantown, MD 20874
58   U.S.A.
59   ----------------------------------------------*/
60
61 #define OPENSSL_FIPSAPI
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <errno.h>
67 #include <assert.h>
68 #include <ctype.h>
69 #include <openssl/crypto.h>
70 #include <openssl/des.h>
71 #include <openssl/evp.h>
72 #include <openssl/bn.h>
73
74 #include <openssl/err.h>
75 #include "e_os.h"
76
77 #ifndef OPENSSL_FIPS
78
79 int main(int argc, char *argv[])
80 {
81     printf("No FIPS DES support\n");
82     return(0);
83 }
84
85 #else
86
87 #include "fips_utl.h"
88 #include <openssl/fips.h>
89
90 #define DES_BLOCK_SIZE 8
91
92 #define VERBOSE 0
93
94 static int DESTest(EVP_CIPHER_CTX *ctx,
95             char *amode, int akeysz, unsigned char *aKey, 
96             unsigned char *iVec, 
97             int dir,  /* 0 = decrypt, 1 = encrypt */
98             unsigned char *out, unsigned char *in, int len)
99     {
100     const EVP_CIPHER *cipher = NULL;
101
102     if (akeysz != 192)
103         {
104         printf("Invalid key size: %d\n", akeysz);
105         return 0;
106         }
107
108     if (fips_strcasecmp(amode, "CBC") == 0)
109         cipher = EVP_des_ede3_cbc();
110     else if (fips_strcasecmp(amode, "ECB") == 0)
111         cipher = EVP_des_ede3_ecb();
112     else if (fips_strcasecmp(amode, "CFB64") == 0)
113         cipher = EVP_des_ede3_cfb64();
114     else if (fips_strncasecmp(amode, "OFB", 3) == 0)
115         cipher = EVP_des_ede3_ofb();
116     else if(!fips_strcasecmp(amode,"CFB8"))
117         cipher = EVP_des_ede3_cfb8();
118     else if(!fips_strcasecmp(amode,"CFB1"))
119         cipher = EVP_des_ede3_cfb1();
120     else
121         {
122         printf("Unknown mode: %s\n", amode);
123         return 0;
124         }
125
126     if (FIPS_cipherinit(ctx, cipher, aKey, iVec, dir) <= 0)
127         return 0;
128     if(!fips_strcasecmp(amode,"CFB1"))
129         M_EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS);
130     FIPS_cipher(ctx, out, in, len);
131
132     return 1;
133     }
134 #if 0
135 static void DebugValue(char *tag, unsigned char *val, int len)
136     {
137     char obuf[2048];
138     int olen;
139     olen = bin2hex(val, len, obuf);
140     printf("%s = %.*s\n", tag, olen, obuf);
141     }
142 #endif
143 static void shiftin(unsigned char *dst,unsigned char *src,int nbits)
144     {
145     int n;
146
147     /* move the bytes... */
148     memmove(dst,dst+nbits/8,3*8-nbits/8);
149     /* append new data */
150     memcpy(dst+3*8-nbits/8,src,(nbits+7)/8);
151     /* left shift the bits */
152     if(nbits%8)
153         for(n=0 ; n < 3*8 ; ++n)
154             dst[n]=(dst[n] << (nbits%8))|(dst[n+1] >> (8-nbits%8));
155     }   
156
157 /*-----------------------------------------------*/
158 char *tdes_t_tag[2] = {"PLAINTEXT", "CIPHERTEXT"};
159 char *tdes_t_mode[6] = {"CBC","ECB","OFB","CFB1","CFB8","CFB64"};
160 enum tdes_Mode {TCBC, TECB, TOFB, TCFB1, TCFB8, TCFB64};
161 int Sizes[6]={64,64,64,1,8,64};
162
163 static int do_tmct(char *amode, 
164             int akeysz, int numkeys, unsigned char *akey,unsigned char *ivec,
165             int dir, unsigned char *text, int len,
166             FILE *rfp)
167     {
168     int i,imode;
169     unsigned char nk[4*8]; /* longest key+8 */
170     unsigned char text0[8];
171
172     for (imode=0 ; imode < 6 ; ++imode)
173         if(!strcmp(amode,tdes_t_mode[imode]))
174             break;
175     if (imode == 6)
176         { 
177         printf("Unrecognized mode: %s\n", amode);
178         return 0;
179         }
180     for(i=0 ; i < 400 ; ++i)
181         {
182         int j;
183         int n;
184         int kp=akeysz/64;
185         unsigned char old_iv[8];
186         EVP_CIPHER_CTX ctx;
187         FIPS_cipher_ctx_init(&ctx);
188
189         fprintf(rfp,RESP_EOL "COUNT = %d" RESP_EOL,i);
190         if(kp == 1)
191             OutputValue("KEY",akey,8,rfp,0);
192         else
193             for(n=0 ; n < kp ; ++n)
194                 {
195                 fprintf(rfp,"KEY%d",n+1);
196                 OutputValue("",akey+n*8,8,rfp,0);
197                 }
198
199         if(imode != TECB)
200             OutputValue("IV",ivec,8,rfp,0);
201         OutputValue(tdes_t_tag[dir^1],text,len,rfp,imode == TCFB1);
202 #if 0
203         /* compensate for endianness */
204         if(imode == TCFB1)
205             text[0]<<=7;
206 #endif
207         memcpy(text0,text,8);
208
209         for(j=0 ; j < 10000 ; ++j)
210             {
211             unsigned char old_text[8];
212
213             memcpy(old_text,text,8);
214             if(j == 0)
215                 {
216                 memcpy(old_iv,ivec,8);
217                 DESTest(&ctx,amode,akeysz,akey,ivec,dir,text,text,len);
218                 }
219             else
220                 {
221                 memcpy(old_iv,ctx.iv,8);
222                 FIPS_cipher(&ctx,text,text,len);
223                 }
224             if(j == 9999)
225                 {
226                 OutputValue(tdes_t_tag[dir],text,len,rfp,imode == TCFB1);
227                 /*              memcpy(ivec,text,8); */
228                 }
229             /*      DebugValue("iv",ctx.iv,8); */
230             /* accumulate material for the next key */
231             shiftin(nk,text,Sizes[imode]);
232             /*      DebugValue("nk",nk,24);*/
233             if((dir && (imode == TCFB1 || imode == TCFB8
234                         || imode == TCFB64 || imode == TCBC)) || imode == TOFB)
235                 memcpy(text,old_iv,8);
236
237             if(!dir && (imode == TCFB1 || imode == TCFB8 || imode == TCFB64))
238                 {
239                 /* the test specifies using the output of the raw DES operation
240                    which we don't have, so reconstruct it... */
241                 for(n=0 ; n < 8 ; ++n)
242                     text[n]^=old_text[n];
243                 }
244             }
245         for(n=0 ; n < 8 ; ++n)
246             akey[n]^=nk[16+n];
247         for(n=0 ; n < 8 ; ++n)
248             akey[8+n]^=nk[8+n];
249         for(n=0 ; n < 8 ; ++n)
250             akey[16+n]^=nk[n];
251         if(numkeys < 3)
252             memcpy(&akey[2*8],akey,8);
253         if(numkeys < 2)
254             memcpy(&akey[8],akey,8);
255         DES_set_odd_parity((DES_cblock *)akey);
256         DES_set_odd_parity((DES_cblock *)(akey+8));
257         DES_set_odd_parity((DES_cblock *)(akey+16));
258         memcpy(ivec,ctx.iv,8);
259
260         /* pointless exercise - the final text doesn't depend on the
261            initial text in OFB mode, so who cares what it is? (Who
262            designed these tests?) */
263         if(imode == TOFB)
264             for(n=0 ; n < 8 ; ++n)
265                 text[n]=text0[n]^old_iv[n];
266         FIPS_cipher_ctx_cleanup(&ctx);
267         }
268     return 1;
269     }
270     
271 static int tproc_file(char *rqfile, char *rspfile)
272     {
273     char afn[256], rfn[256];
274     FILE *afp = NULL, *rfp = NULL;
275     char ibuf[2048], tbuf[2048];
276     int len;
277     char amode[8] = "";
278     char atest[100] = "";
279     int akeysz=0;
280     unsigned char iVec[20], aKey[40];
281     int dir = -1, err = 0, step = 0, echo = 1;
282     unsigned char plaintext[2048];
283     unsigned char ciphertext[2048];
284     char *rp;
285     EVP_CIPHER_CTX ctx;
286     int numkeys=1;
287     FIPS_cipher_ctx_init(&ctx);
288
289     if (!rqfile || !(*rqfile))
290         {
291         printf("No req file\n");
292         return -1;
293         }
294     strcpy(afn, rqfile);
295
296     if ((afp = fopen(afn, "r")) == NULL)
297         {
298         printf("Cannot open file: %s, %s\n", 
299                afn, strerror(errno));
300         return -1;
301         }
302     if (!rspfile)
303         {
304         strcpy(rfn,afn);
305         rp=strstr(rfn,"req/");
306 #ifdef OPENSSL_SYS_WIN32
307         if (!rp)
308             rp=strstr(rfn,"req\\");
309 #endif
310         assert(rp);
311         memcpy(rp,"rsp",3);
312         rp = strstr(rfn, ".req");
313         memcpy(rp, ".rsp", 4);
314         rspfile = rfn;
315         }
316     if ((rfp = fopen(rspfile, "w")) == NULL)
317         {
318         printf("Cannot open file: %s, %s\n", 
319                rfn, strerror(errno));
320         fclose(afp);
321         afp = NULL;
322         return -1;
323         }
324     while (!err && (fgets(ibuf, sizeof(ibuf), afp)) != NULL)
325         {
326         tidy_line(tbuf, ibuf);
327         /*      printf("step=%d ibuf=%s",step,ibuf);*/
328         if(step == 3 && !strcmp(amode,"ECB"))
329             {
330             memset(iVec, 0, sizeof(iVec));
331             step = (dir)? 4: 5;  /* no ivec for ECB */
332             }
333         switch (step)
334             {
335         case 0:  /* read preamble */
336             if (ibuf[0] == '\n')
337                 { /* end of preamble */
338                 if (*amode == '\0')
339                     {
340                     printf("Missing Mode\n");
341                     err = 1;
342                     }
343                 else
344                     {
345                     copy_line(ibuf, rfp);
346                     ++ step;
347                     }
348                 }
349             else if (ibuf[0] != '#')
350                 {
351                 printf("Invalid preamble item: %s\n", ibuf);
352                 err = 1;
353                 }
354             else
355                 { /* process preamble */
356                 char *xp, *pp = ibuf+2;
357                 int n;
358                 if(*amode)
359                     { /* insert current time & date */
360                     time_t rtim = time(0);
361                     fputs("# ", rfp);
362                     copy_line(ctime(&rtim), rfp);
363                     }
364                 else
365                     {
366                     copy_line(ibuf, rfp);
367                     if(!strncmp(pp,"INVERSE ",8) || !strncmp(pp,"DES ",4)
368                        || !strncmp(pp,"TDES ",5)
369                        || !strncmp(pp,"PERMUTATION ",12)
370                        || !strncmp(pp,"SUBSTITUTION ",13)
371                        || !strncmp(pp,"VARIABLE ",9))
372                         {
373                         /* get test type */
374                         if(!strncmp(pp,"DES ",4))
375                             pp+=4;
376                         else if(!strncmp(pp,"TDES ",5))
377                             pp+=5;
378                         xp = strchr(pp, ' ');
379                         n = xp-pp;
380                         strncpy(atest, pp, n);
381                         atest[n] = '\0';
382                         /* get mode */
383                         xp = strrchr(pp, ' '); /* get mode" */
384                         n = strlen(xp+1)-1;
385                         strncpy(amode, xp+1, n);
386                         amode[n] = '\0';
387                         if (!strcmp(atest, "Monte"))
388                                 echo = 0;
389                         /* amode[3] = '\0'; */
390                         if (VERBOSE)
391                                 printf("Test=%s, Mode=%s\n",atest,amode);
392                         }
393                     }
394                 }
395             break;
396
397         case 1:  /* [ENCRYPT] | [DECRYPT] */
398             if(ibuf[0] == '\n')
399                 break;
400             if (ibuf[0] == '[')
401                 {
402                 copy_line(ibuf, rfp);
403                 ++step;
404                 if (fips_strncasecmp(ibuf, "[ENCRYPT]", 9) == 0)
405                     dir = 1;
406                 else if (fips_strncasecmp(ibuf, "[DECRYPT]", 9) == 0)
407                     dir = 0;
408                 else
409                     {
410                     printf("Invalid keyword: %s\n", ibuf);
411                     err = 1;
412                     }
413                 break;
414                 }
415             else if (dir == -1)
416                 {
417                 err = 1;
418                 printf("Missing ENCRYPT/DECRYPT keyword\n");
419                 break;
420                 }
421             else 
422                 step = 2;
423
424         case 2: /* KEY = xxxx */
425             if(*ibuf == '\n')
426                 {
427                 copy_line(ibuf, rfp);
428                 break;
429                 }
430             if(!fips_strncasecmp(ibuf,"COUNT = ",8))
431                 {
432                 copy_line(ibuf, rfp);
433                 break;
434                 }
435             if(!fips_strncasecmp(ibuf,"COUNT=",6))
436                 {
437                 copy_line(ibuf, rfp);
438                 break;
439                 }
440             if(!fips_strncasecmp(ibuf,"NumKeys = ",10))
441                 {
442                 numkeys=atoi(ibuf+10);
443                 break;
444                 }
445             if (echo) 
446                 copy_line(ibuf, rfp);
447             if(!fips_strncasecmp(ibuf,"KEY = ",6))
448                 {
449                 akeysz=64;
450                 len = hex2bin((char*)ibuf+6, aKey);
451                 if (len < 0)
452                     {
453                     printf("Invalid KEY\n");
454                     err=1;
455                     break;
456                     }
457                 PrintValue("KEY", aKey, len);
458                 ++step;
459                 }
460             else if(!fips_strncasecmp(ibuf,"KEYs = ",7))
461                 {
462                 akeysz=64*3;
463                 len=hex2bin(ibuf+7,aKey);
464                 if(len != 8)
465                     {
466                     printf("Invalid KEY\n");
467                     err=1;
468                     break;
469                     }
470                 memcpy(aKey+8,aKey,8);
471                 memcpy(aKey+16,aKey,8);
472                 ibuf[4]='\0';
473                 PrintValue("KEYs",aKey,len);
474                 ++step;
475                 }
476             else if(!fips_strncasecmp(ibuf,"KEY",3))
477                 {
478                 int n=ibuf[3]-'1';
479
480                 akeysz=64*3;
481                 len=hex2bin(ibuf+7,aKey+n*8);
482                 if(len != 8)
483                     {
484                     printf("Invalid KEY\n");
485                     err=1;
486                     break;
487                     }
488                 ibuf[4]='\0';
489                 PrintValue(ibuf,aKey,len);
490                 if(n == 2)
491                     ++step;
492                 }
493             else
494                 {
495                 printf("Missing KEY\n");
496                 err = 1;
497                 }
498             break;
499
500         case 3: /* IV = xxxx */
501             if (echo)
502                 copy_line(ibuf, rfp);
503             if (fips_strncasecmp(ibuf, "IV = ", 5) != 0)
504                 {
505                 printf("Missing IV\n");
506                 err = 1;
507                 }
508             else
509                 {
510                 len = hex2bin((char*)ibuf+5, iVec);
511                 if (len < 0)
512                     {
513                     printf("Invalid IV\n");
514                     err =1;
515                     break;
516                     }
517                 PrintValue("IV", iVec, len);
518                 step = (dir)? 4: 5;
519                 }
520             break;
521
522         case 4: /* PLAINTEXT = xxxx */
523             if (echo)
524                 copy_line(ibuf, rfp);
525             if (fips_strncasecmp(ibuf, "PLAINTEXT = ", 12) != 0)
526                 {
527                 printf("Missing PLAINTEXT\n");
528                 err = 1;
529                 }
530             else
531                 {
532                 int nn = strlen(ibuf+12);
533                 if(!strcmp(amode,"CFB1"))
534                     len=bint2bin(ibuf+12,nn-1,plaintext);
535                 else
536                     len=hex2bin(ibuf+12, plaintext);
537                 if (len < 0)
538                     {
539                     printf("Invalid PLAINTEXT: %s", ibuf+12);
540                     err =1;
541                     break;
542                     }
543                 if (len >= (int)sizeof(plaintext))
544                     {
545                     printf("Buffer overflow\n");
546                     }
547                 PrintValue("PLAINTEXT", (unsigned char*)plaintext, len);
548                 if (strcmp(atest, "Monte") == 0)  /* Monte Carlo Test */
549                     {
550                     if (!do_tmct(amode,akeysz,numkeys,aKey,iVec,
551                                         dir,plaintext,len,rfp))
552                         return -1;
553                     }
554                 else
555                     {
556                     assert(dir == 1);
557                     DESTest(&ctx, amode, akeysz, aKey, iVec, 
558                                   dir,  /* 0 = decrypt, 1 = encrypt */
559                                   ciphertext, plaintext, len);
560                     OutputValue("CIPHERTEXT",ciphertext,len,rfp,
561                                 !strcmp(amode,"CFB1"));
562                     }
563                 step = 6;
564                 }
565             break;
566
567         case 5: /* CIPHERTEXT = xxxx */
568             if (echo)
569                 copy_line(ibuf, rfp);
570             if (fips_strncasecmp(ibuf, "CIPHERTEXT = ", 13) != 0)
571                 {
572                 printf("Missing KEY\n");
573                 err = 1;
574                 }
575             else
576                 {
577                 if(!strcmp(amode,"CFB1"))
578                     len=bint2bin(ibuf+13,strlen(ibuf+13)-1,ciphertext);
579                 else
580                     len = hex2bin(ibuf+13,ciphertext);
581                 if (len < 0)
582                     {
583                     printf("Invalid CIPHERTEXT\n");
584                     err =1;
585                     break;
586                     }
587                 
588                 PrintValue("CIPHERTEXT", ciphertext, len);
589                 if (strcmp(atest, "Monte") == 0)  /* Monte Carlo Test */
590                     {
591                     do_tmct(amode, akeysz, numkeys, aKey, iVec, 
592                            dir, ciphertext, len, rfp);
593                     }
594                 else
595                     {
596                     assert(dir == 0);
597                     DESTest(&ctx, amode, akeysz, aKey, iVec, 
598                                   dir,  /* 0 = decrypt, 1 = encrypt */
599                                   plaintext, ciphertext, len);
600                     OutputValue("PLAINTEXT",(unsigned char *)plaintext,len,rfp,
601                                 !strcmp(amode,"CFB1"));
602                     }
603                 step = 6;
604                 }
605             break;
606
607         case 6:
608             if (ibuf[0] != '\n')
609                 {
610                 err = 1;
611                 printf("Missing terminator\n");
612                 }
613             else if (strcmp(atest, "MCT") != 0)
614                 { /* MCT already added terminating nl */
615                 copy_line(ibuf, rfp);
616                 }
617             step = 1;
618             break;
619             }
620         }
621     if (rfp)
622         fclose(rfp);
623     if (afp)
624         fclose(afp);
625     FIPS_cipher_ctx_cleanup(&ctx);
626     return err;
627     }
628
629 /*--------------------------------------------------
630   Processes either a single file or 
631   a set of files whose names are passed in a file.
632   A single file is specified as:
633     aes_test -f xxx.req
634   A set of files is specified as:
635     aes_test -d xxxxx.xxx
636   The default is: -d req.txt
637 --------------------------------------------------*/
638 #ifdef FIPS_ALGVS
639 int fips_desmovs_main(int argc, char **argv)
640 #else
641 int main(int argc, char **argv)
642 #endif
643     {
644     char *rqlist = "req.txt", *rspfile = NULL;
645     FILE *fp = NULL;
646     char fn[250] = "", rfn[256] = "";
647     int d_opt = 1;
648
649     fips_algtest_init();
650     if (argc > 1)
651         {
652         if (fips_strcasecmp(argv[1], "-d") == 0)
653             {
654             d_opt = 1;
655             }
656         else if (fips_strcasecmp(argv[1], "-f") == 0)
657             {
658             d_opt = 0;
659             }
660         else
661             {
662             printf("Invalid parameter: %s\n", argv[1]);
663             return 0;
664             }
665         if (argc < 3)
666             {
667             printf("Missing parameter\n");
668             return 0;
669             }
670         if (d_opt)
671             rqlist = argv[2];
672         else
673             {
674             strcpy(fn, argv[2]);
675             rspfile = argv[3];
676             }
677         }
678     if (d_opt)
679         { /* list of files (directory) */
680         if (!(fp = fopen(rqlist, "r")))
681             {
682             printf("Cannot open req list file\n");
683             return -1;
684             }
685         while (fgets(fn, sizeof(fn), fp))
686             {
687             strtok(fn, "\r\n");
688             strcpy(rfn, fn);
689             printf("Processing: %s\n", rfn);
690             if (tproc_file(rfn, rspfile))
691                 {
692                 printf(">>> Processing failed for: %s <<<\n", rfn);
693                 return -1;
694                 }
695             }
696         fclose(fp);
697         }
698     else /* single file */
699         {
700         if (VERBOSE)
701                 printf("Processing: %s\n", fn);
702         if (tproc_file(fn, rspfile))
703             {
704             printf(">>> Processing failed for: %s <<<\n", fn);
705             }
706         }
707     return 0;
708     }
709
710 #endif