source: trunk/third/openssl/apps/enc.c @ 18442

Revision 18442, 15.3 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18441, which included commits to RCS files with non-trunk default branches.
Line 
1/* apps/enc.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include "apps.h"
63#include <openssl/bio.h>
64#include <openssl/err.h>
65#include <openssl/evp.h>
66#include <openssl/objects.h>
67#include <openssl/x509.h>
68#include <openssl/rand.h>
69#include <openssl/pem.h>
70#include <ctype.h>
71
72int set_hex(char *in,unsigned char *out,int size);
73#undef SIZE
74#undef BSIZE
75#undef PROG
76
77#define SIZE    (512)
78#define BSIZE   (8*1024)
79#define PROG    enc_main
80
81static void show_ciphers(const OBJ_NAME *name,void *bio_)
82        {
83        BIO *bio=bio_;
84        static int n;
85
86        if(!islower((unsigned char)*name->name))
87                return;
88
89        BIO_printf(bio,"-%-25s",name->name);
90        if(++n == 3)
91                {
92                BIO_printf(bio,"\n");
93                n=0;
94                }
95        else
96                BIO_printf(bio," ");
97        }
98
99int MAIN(int, char **);
100
101int MAIN(int argc, char **argv)
102        {
103        ENGINE *e = NULL;
104        static const char magic[]="Salted__";
105        char mbuf[sizeof magic-1];
106        char *strbuf=NULL;
107        unsigned char *buff=NULL,*bufsize=NULL;
108        int bsize=BSIZE,verbose=0;
109        int ret=1,inl;
110        int nopad = 0;
111        unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH];
112        unsigned char salt[PKCS5_SALT_LEN];
113        char *str=NULL, *passarg = NULL, *pass = NULL;
114        char *hkey=NULL,*hiv=NULL,*hsalt = NULL;
115        int enc=1,printkey=0,i,base64=0;
116        int debug=0,olb64=0,nosalt=0;
117        const EVP_CIPHER *cipher=NULL,*c;
118        char *inf=NULL,*outf=NULL;
119        BIO *in=NULL,*out=NULL,*b64=NULL,*benc=NULL,*rbio=NULL,*wbio=NULL;
120#define PROG_NAME_SIZE  39
121        char pname[PROG_NAME_SIZE+1];
122        char *engine = NULL;
123
124        apps_startup();
125
126        if (bio_err == NULL)
127                if ((bio_err=BIO_new(BIO_s_file())) != NULL)
128                        BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
129
130        if (!load_config(bio_err, NULL))
131                goto end;
132
133        /* first check the program name */
134        program_name(argv[0],pname,sizeof pname);
135        if (strcmp(pname,"base64") == 0)
136                base64=1;
137
138        cipher=EVP_get_cipherbyname(pname);
139        if (!base64 && (cipher == NULL) && (strcmp(pname,"enc") != 0))
140                {
141                BIO_printf(bio_err,"%s is an unknown cipher\n",pname);
142                goto bad;
143                }
144
145        argc--;
146        argv++;
147        while (argc >= 1)
148                {
149                if      (strcmp(*argv,"-e") == 0)
150                        enc=1;
151                else if (strcmp(*argv,"-in") == 0)
152                        {
153                        if (--argc < 1) goto bad;
154                        inf= *(++argv);
155                        }
156                else if (strcmp(*argv,"-out") == 0)
157                        {
158                        if (--argc < 1) goto bad;
159                        outf= *(++argv);
160                        }
161                else if (strcmp(*argv,"-pass") == 0)
162                        {
163                        if (--argc < 1) goto bad;
164                        passarg= *(++argv);
165                        }
166                else if (strcmp(*argv,"-engine") == 0)
167                        {
168                        if (--argc < 1) goto bad;
169                        engine= *(++argv);
170                        }
171                else if (strcmp(*argv,"-d") == 0)
172                        enc=0;
173                else if (strcmp(*argv,"-p") == 0)
174                        printkey=1;
175                else if (strcmp(*argv,"-v") == 0)
176                        verbose=1;
177                else if (strcmp(*argv,"-nopad") == 0)
178                        nopad=1;
179                else if (strcmp(*argv,"-salt") == 0)
180                        nosalt=0;
181                else if (strcmp(*argv,"-nosalt") == 0)
182                        nosalt=1;
183                else if (strcmp(*argv,"-debug") == 0)
184                        debug=1;
185                else if (strcmp(*argv,"-P") == 0)
186                        printkey=2;
187                else if (strcmp(*argv,"-A") == 0)
188                        olb64=1;
189                else if (strcmp(*argv,"-a") == 0)
190                        base64=1;
191                else if (strcmp(*argv,"-base64") == 0)
192                        base64=1;
193                else if (strcmp(*argv,"-bufsize") == 0)
194                        {
195                        if (--argc < 1) goto bad;
196                        bufsize=(unsigned char *)*(++argv);
197                        }
198                else if (strcmp(*argv,"-k") == 0)
199                        {
200                        if (--argc < 1) goto bad;
201                        str= *(++argv);
202                        }
203                else if (strcmp(*argv,"-kfile") == 0)
204                        {
205                        static char buf[128];
206                        FILE *infile;
207                        char *file;
208
209                        if (--argc < 1) goto bad;
210                        file= *(++argv);
211                        infile=fopen(file,"r");
212                        if (infile == NULL)
213                                {
214                                BIO_printf(bio_err,"unable to read key from '%s'\n",
215                                        file);
216                                goto bad;
217                                }
218                        buf[0]='\0';
219                        fgets(buf,sizeof buf,infile);
220                        fclose(infile);
221                        i=strlen(buf);
222                        if ((i > 0) &&
223                                ((buf[i-1] == '\n') || (buf[i-1] == '\r')))
224                                buf[--i]='\0';
225                        if ((i > 0) &&
226                                ((buf[i-1] == '\n') || (buf[i-1] == '\r')))
227                                buf[--i]='\0';
228                        if (i < 1)
229                                {
230                                BIO_printf(bio_err,"zero length password\n");
231                                goto bad;
232                                }
233                        str=buf;
234                        }
235                else if (strcmp(*argv,"-K") == 0)
236                        {
237                        if (--argc < 1) goto bad;
238                        hkey= *(++argv);
239                        }
240                else if (strcmp(*argv,"-S") == 0)
241                        {
242                        if (--argc < 1) goto bad;
243                        hsalt= *(++argv);
244                        }
245                else if (strcmp(*argv,"-iv") == 0)
246                        {
247                        if (--argc < 1) goto bad;
248                        hiv= *(++argv);
249                        }
250                else if ((argv[0][0] == '-') &&
251                        ((c=EVP_get_cipherbyname(&(argv[0][1]))) != NULL))
252                        {
253                        cipher=c;
254                        }
255                else if (strcmp(*argv,"-none") == 0)
256                        cipher=NULL;
257                else
258                        {
259                        BIO_printf(bio_err,"unknown option '%s'\n",*argv);
260bad:
261                        BIO_printf(bio_err,"options are\n");
262                        BIO_printf(bio_err,"%-14s input file\n","-in <file>");
263                        BIO_printf(bio_err,"%-14s output file\n","-out <file>");
264                        BIO_printf(bio_err,"%-14s pass phrase source\n","-pass <arg>");
265                        BIO_printf(bio_err,"%-14s encrypt\n","-e");
266                        BIO_printf(bio_err,"%-14s decrypt\n","-d");
267                        BIO_printf(bio_err,"%-14s base64 encode/decode, depending on encryption flag\n","-a/-base64");
268                        BIO_printf(bio_err,"%-14s key is the next argument\n","-k");
269                        BIO_printf(bio_err,"%-14s key is the first line of the file argument\n","-kfile");
270                        BIO_printf(bio_err,"%-14s key/iv in hex is the next argument\n","-K/-iv");
271                        BIO_printf(bio_err,"%-14s print the iv/key (then exit if -P)\n","-[pP]");
272                        BIO_printf(bio_err,"%-14s buffer size\n","-bufsize <n>");
273                        BIO_printf(bio_err,"%-14s use engine e, possibly a hardware device.\n","-engine e");
274
275                        BIO_printf(bio_err,"Cipher Types\n");
276                        OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
277                                               show_ciphers,
278                                               bio_err);
279                        BIO_printf(bio_err,"\n");
280
281                        goto end;
282                        }
283                argc--;
284                argv++;
285                }
286
287        e = setup_engine(bio_err, engine, 0);
288
289        if (bufsize != NULL)
290                {
291                unsigned long n;
292
293                for (n=0; *bufsize; bufsize++)
294                        {
295                        i= *bufsize;
296                        if ((i <= '9') && (i >= '0'))
297                                n=n*10+i-'0';
298                        else if (i == 'k')
299                                {
300                                n*=1024;
301                                bufsize++;
302                                break;
303                                }
304                        }
305                if (*bufsize != '\0')
306                        {
307                        BIO_printf(bio_err,"invalid 'bufsize' specified.\n");
308                        goto end;
309                        }
310
311                /* It must be large enough for a base64 encoded line */
312                if (n < 80) n=80;
313
314                bsize=(int)n;
315                if (verbose) BIO_printf(bio_err,"bufsize=%d\n",bsize);
316                }
317
318        strbuf=OPENSSL_malloc(SIZE);
319        buff=(unsigned char *)OPENSSL_malloc(EVP_ENCODE_LENGTH(bsize));
320        if ((buff == NULL) || (strbuf == NULL))
321                {
322                BIO_printf(bio_err,"OPENSSL_malloc failure %ld\n",(long)EVP_ENCODE_LENGTH(bsize));
323                goto end;
324                }
325
326        in=BIO_new(BIO_s_file());
327        out=BIO_new(BIO_s_file());
328        if ((in == NULL) || (out == NULL))
329                {
330                ERR_print_errors(bio_err);
331                goto end;
332                }
333        if (debug)
334                {
335                BIO_set_callback(in,BIO_debug_callback);
336                BIO_set_callback(out,BIO_debug_callback);
337                BIO_set_callback_arg(in,bio_err);
338                BIO_set_callback_arg(out,bio_err);
339                }
340
341        if (inf == NULL)
342                BIO_set_fp(in,stdin,BIO_NOCLOSE);
343        else
344                {
345                if (BIO_read_filename(in,inf) <= 0)
346                        {
347                        perror(inf);
348                        goto end;
349                        }
350                }
351
352        if(!str && passarg) {
353                if(!app_passwd(bio_err, passarg, NULL, &pass, NULL)) {
354                        BIO_printf(bio_err, "Error getting password\n");
355                        goto end;
356                }
357                str = pass;
358        }
359
360        if ((str == NULL) && (cipher != NULL) && (hkey == NULL))
361                {
362                for (;;)
363                        {
364                        char buf[200];
365
366                        sprintf(buf,"enter %s %s password:",
367                                OBJ_nid2ln(EVP_CIPHER_nid(cipher)),
368                                (enc)?"encryption":"decryption");
369                        strbuf[0]='\0';
370                        i=EVP_read_pw_string((char *)strbuf,SIZE,buf,enc);
371                        if (i == 0)
372                                {
373                                if (strbuf[0] == '\0')
374                                        {
375                                        ret=1;
376                                        goto end;
377                                        }
378                                str=strbuf;
379                                break;
380                                }
381                        if (i < 0)
382                                {
383                                BIO_printf(bio_err,"bad password read\n");
384                                goto end;
385                                }
386                        }
387                }
388
389
390        if (outf == NULL)
391                {
392                BIO_set_fp(out,stdout,BIO_NOCLOSE);
393#ifdef OPENSSL_SYS_VMS
394                {
395                BIO *tmpbio = BIO_new(BIO_f_linebuffer());
396                out = BIO_push(tmpbio, out);
397                }
398#endif
399                }
400        else
401                {
402                if (BIO_write_filename(out,outf) <= 0)
403                        {
404                        perror(outf);
405                        goto end;
406                        }
407                }
408
409        rbio=in;
410        wbio=out;
411
412        if (base64)
413                {
414                if ((b64=BIO_new(BIO_f_base64())) == NULL)
415                        goto end;
416                if (debug)
417                        {
418                        BIO_set_callback(b64,BIO_debug_callback);
419                        BIO_set_callback_arg(b64,bio_err);
420                        }
421                if (olb64)
422                        BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL);
423                if (enc)
424                        wbio=BIO_push(b64,wbio);
425                else
426                        rbio=BIO_push(b64,rbio);
427                }
428
429        if (cipher != NULL)
430                {
431                /* Note that str is NULL if a key was passed on the command
432                 * line, so we get no salt in that case. Is this a bug?
433                 */
434                if (str != NULL)
435                        {
436                        /* Salt handling: if encrypting generate a salt and
437                         * write to output BIO. If decrypting read salt from
438                         * input BIO.
439                         */
440                        unsigned char *sptr;
441                        if(nosalt) sptr = NULL;
442                        else {
443                                if(enc) {
444                                        if(hsalt) {
445                                                if(!set_hex(hsalt,salt,sizeof salt)) {
446                                                        BIO_printf(bio_err,
447                                                                "invalid hex salt value\n");
448                                                        goto end;
449                                                }
450                                        } else if (RAND_pseudo_bytes(salt, sizeof salt) < 0)
451                                                goto end;
452                                        /* If -P option then don't bother writing */
453                                        if((printkey != 2)
454                                           && (BIO_write(wbio,magic,
455                                                         sizeof magic-1) != sizeof magic-1
456                                               || BIO_write(wbio,
457                                                            (char *)salt,
458                                                            sizeof salt) != sizeof salt)) {
459                                                BIO_printf(bio_err,"error writing output file\n");
460                                                goto end;
461                                        }
462                                } else if(BIO_read(rbio,mbuf,sizeof mbuf) != sizeof mbuf
463                                          || BIO_read(rbio,
464                                                      (unsigned char *)salt,
465                                    sizeof salt) != sizeof salt) {
466                                        BIO_printf(bio_err,"error reading input file\n");
467                                        goto end;
468                                } else if(memcmp(mbuf,magic,sizeof magic-1)) {
469                                    BIO_printf(bio_err,"bad magic number\n");
470                                    goto end;
471                                }
472
473                                sptr = salt;
474                        }
475
476                        EVP_BytesToKey(cipher,EVP_md5(),sptr,
477                                (unsigned char *)str,
478                                strlen(str),1,key,iv);
479                        /* zero the complete buffer or the string
480                         * passed from the command line
481                         * bug picked up by
482                         * Larry J. Hughes Jr. <hughes@indiana.edu> */
483                        if (str == strbuf)
484                                OPENSSL_cleanse(str,SIZE);
485                        else
486                                OPENSSL_cleanse(str,strlen(str));
487                        }
488                if ((hiv != NULL) && !set_hex(hiv,iv,sizeof iv))
489                        {
490                        BIO_printf(bio_err,"invalid hex iv value\n");
491                        goto end;
492                        }
493                if ((hiv == NULL) && (str == NULL))
494                        {
495                        /* No IV was explicitly set and no IV was generated
496                         * during EVP_BytesToKey. Hence the IV is undefined,
497                         * making correct decryption impossible. */
498                        BIO_printf(bio_err, "iv undefined\n");
499                        goto end;
500                        }
501                if ((hkey != NULL) && !set_hex(hkey,key,sizeof key))
502                        {
503                        BIO_printf(bio_err,"invalid hex key value\n");
504                        goto end;
505                        }
506
507                if ((benc=BIO_new(BIO_f_cipher())) == NULL)
508                        goto end;
509                BIO_set_cipher(benc,cipher,key,iv,enc);
510                if (nopad)
511                        {
512                        EVP_CIPHER_CTX *ctx;
513                        BIO_get_cipher_ctx(benc, &ctx);
514                        EVP_CIPHER_CTX_set_padding(ctx, 0);
515                        }
516                if (debug)
517                        {
518                        BIO_set_callback(benc,BIO_debug_callback);
519                        BIO_set_callback_arg(benc,bio_err);
520                        }
521
522                if (printkey)
523                        {
524                        if (!nosalt)
525                                {
526                                printf("salt=");
527                                for (i=0; i<sizeof salt; i++)
528                                        printf("%02X",salt[i]);
529                                printf("\n");
530                                }
531                        if (cipher->key_len > 0)
532                                {
533                                printf("key=");
534                                for (i=0; i<cipher->key_len; i++)
535                                        printf("%02X",key[i]);
536                                printf("\n");
537                                }
538                        if (cipher->iv_len > 0)
539                                {
540                                printf("iv =");
541                                for (i=0; i<cipher->iv_len; i++)
542                                        printf("%02X",iv[i]);
543                                printf("\n");
544                                }
545                        if (printkey == 2)
546                                {
547                                ret=0;
548                                goto end;
549                                }
550                        }
551                }
552
553        /* Only encrypt/decrypt as we write the file */
554        if (benc != NULL)
555                wbio=BIO_push(benc,wbio);
556
557        for (;;)
558                {
559                inl=BIO_read(rbio,(char *)buff,bsize);
560                if (inl <= 0) break;
561                if (BIO_write(wbio,(char *)buff,inl) != inl)
562                        {
563                        BIO_printf(bio_err,"error writing output file\n");
564                        goto end;
565                        }
566                }
567        if (!BIO_flush(wbio))
568                {
569                BIO_printf(bio_err,"bad decrypt\n");
570                goto end;
571                }
572
573        ret=0;
574        if (verbose)
575                {
576                BIO_printf(bio_err,"bytes read   :%8ld\n",BIO_number_read(in));
577                BIO_printf(bio_err,"bytes written:%8ld\n",BIO_number_written(out));
578                }
579end:
580        ERR_print_errors(bio_err);
581        if (strbuf != NULL) OPENSSL_free(strbuf);
582        if (buff != NULL) OPENSSL_free(buff);
583        if (in != NULL) BIO_free(in);
584        if (out != NULL) BIO_free_all(out);
585        if (benc != NULL) BIO_free(benc);
586        if (b64 != NULL) BIO_free(b64);
587        if(pass) OPENSSL_free(pass);
588        apps_shutdown();
589        OPENSSL_EXIT(ret);
590        }
591
592int set_hex(char *in, unsigned char *out, int size)
593        {
594        int i,n;
595        unsigned char j;
596
597        n=strlen(in);
598        if (n > (size*2))
599                {
600                BIO_printf(bio_err,"hex string is too long\n");
601                return(0);
602                }
603        memset(out,0,size);
604        for (i=0; i<n; i++)
605                {
606                j=(unsigned char)*in;
607                *(in++)='\0';
608                if (j == 0) break;
609                if ((j >= '0') && (j <= '9'))
610                        j-='0';
611                else if ((j >= 'A') && (j <= 'F'))
612                        j=j-'A'+10;
613                else if ((j >= 'a') && (j <= 'f'))
614                        j=j-'a'+10;
615                else
616                        {
617                        BIO_printf(bio_err,"non-hex digit\n");
618                        return(0);
619                        }
620                if (i&1)
621                        out[i/2]|=j;
622                else
623                        out[i/2]=(j<<4);
624                }
625        return(1);
626        }
Note: See TracBrowser for help on using the repository browser.