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 72 int 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 81 static 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 99 int MAIN(int, char **); 100 101 int MAIN(int argc, char **argv) 102 { 103 #ifndef OPENSSL_NO_ENGINE 104 ENGINE *e = NULL; 105 #endif 106 static const char magic[]="Salted__"; 107 char mbuf[sizeof magic-1]; 108 char *strbuf=NULL; 109 unsigned char *buff=NULL,*bufsize=NULL; 110 int bsize=BSIZE,verbose=0; 111 int ret=1,inl; 112 int nopad = 0; 113 unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH]; 114 unsigned char salt[PKCS5_SALT_LEN]; 115 char *str=NULL, *passarg = NULL, *pass = NULL; 116 char *hkey=NULL,*hiv=NULL,*hsalt = NULL; 117 int enc=1,printkey=0,i,base64=0; 118 int debug=0,olb64=0,nosalt=0; 119 const EVP_CIPHER *cipher=NULL,*c; 120 char *inf=NULL,*outf=NULL; 121 BIO *in=NULL,*out=NULL,*b64=NULL,*benc=NULL,*rbio=NULL,*wbio=NULL; 122 #define PROG_NAME_SIZE 39 123 char pname[PROG_NAME_SIZE+1]; 124 #ifndef OPENSSL_NO_ENGINE 125 char *engine = NULL; 126 #endif 127 128 apps_startup(); 129 130 if (bio_err == NULL) 131 if ((bio_err=BIO_new(BIO_s_file())) != NULL) 132 BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); 133 134 if (!load_config(bio_err, NULL)) 135 goto end; 136 137 /* first check the program name */ 138 program_name(argv[0],pname,sizeof pname); 139 if (strcmp(pname,"base64") == 0) 140 base64=1; 141 142 cipher=EVP_get_cipherbyname(pname); 143 if (!base64 && (cipher == NULL) && (strcmp(pname,"enc") != 0)) 144 { 145 BIO_printf(bio_err,"%s is an unknown cipher\n",pname); 146 goto bad; 147 } 148 149 argc--; 150 argv++; 151 while (argc >= 1) 152 { 153 if (strcmp(*argv,"-e") == 0) 154 enc=1; 155 else if (strcmp(*argv,"-in") == 0) 156 { 157 if (--argc < 1) goto bad; 158 inf= *(++argv); 159 } 160 else if (strcmp(*argv,"-out") == 0) 161 { 162 if (--argc < 1) goto bad; 163 outf= *(++argv); 164 } 165 else if (strcmp(*argv,"-pass") == 0) 166 { 167 if (--argc < 1) goto bad; 168 passarg= *(++argv); 169 } 170 #ifndef OPENSSL_NO_ENGINE 171 else if (strcmp(*argv,"-engine") == 0) 172 { 173 if (--argc < 1) goto bad; 174 engine= *(++argv); 175 } 176 #endif 177 else if (strcmp(*argv,"-d") == 0) 178 enc=0; 179 else if (strcmp(*argv,"-p") == 0) 180 printkey=1; 181 else if (strcmp(*argv,"-v") == 0) 182 verbose=1; 183 else if (strcmp(*argv,"-nopad") == 0) 184 nopad=1; 185 else if (strcmp(*argv,"-salt") == 0) 186 nosalt=0; 187 else if (strcmp(*argv,"-nosalt") == 0) 188 nosalt=1; 189 else if (strcmp(*argv,"-debug") == 0) 190 debug=1; 191 else if (strcmp(*argv,"-P") == 0) 192 printkey=2; 193 else if (strcmp(*argv,"-A") == 0) 194 olb64=1; 195 else if (strcmp(*argv,"-a") == 0) 196 base64=1; 197 else if (strcmp(*argv,"-base64") == 0) 198 base64=1; 199 else if (strcmp(*argv,"-bufsize") == 0) 200 { 201 if (--argc < 1) goto bad; 202 bufsize=(unsigned char *)*(++argv); 203 } 204 else if (strcmp(*argv,"-k") == 0) 205 { 206 if (--argc < 1) goto bad; 207 str= *(++argv); 208 } 209 else if (strcmp(*argv,"-kfile") == 0) 210 { 211 static char buf[128]; 212 FILE *infile; 213 char *file; 214 215 if (--argc < 1) goto bad; 216 file= *(++argv); 217 infile=fopen(file,"r"); 218 if (infile == NULL) 219 { 220 BIO_printf(bio_err,"unable to read key from '%s'\n", 221 file); 222 goto bad; 223 } 224 buf[0]='\0'; 225 fgets(buf,sizeof buf,infile); 226 fclose(infile); 227 i=strlen(buf); 228 if ((i > 0) && 229 ((buf[i-1] == '\n') || (buf[i-1] == '\r'))) 230 buf[--i]='\0'; 231 if ((i > 0) && 232 ((buf[i-1] == '\n') || (buf[i-1] == '\r'))) 233 buf[--i]='\0'; 234 if (i < 1) 235 { 236 BIO_printf(bio_err,"zero length password\n"); 237 goto bad; 238 } 239 str=buf; 240 } 241 else if (strcmp(*argv,"-K") == 0) 242 { 243 if (--argc < 1) goto bad; 244 hkey= *(++argv); 245 } 246 else if (strcmp(*argv,"-S") == 0) 247 { 248 if (--argc < 1) goto bad; 249 hsalt= *(++argv); 250 } 251 else if (strcmp(*argv,"-iv") == 0) 252 { 253 if (--argc < 1) goto bad; 254 hiv= *(++argv); 255 } 256 else if ((argv[0][0] == '-') && 257 ((c=EVP_get_cipherbyname(&(argv[0][1]))) != NULL)) 258 { 259 cipher=c; 260 } 261 else if (strcmp(*argv,"-none") == 0) 262 cipher=NULL; 263 else 264 { 265 BIO_printf(bio_err,"unknown option '%s'\n",*argv); 266 bad: 267 BIO_printf(bio_err,"options are\n"); 268 BIO_printf(bio_err,"%-14s input file\n","-in <file>"); 269 BIO_printf(bio_err,"%-14s output file\n","-out <file>"); 270 BIO_printf(bio_err,"%-14s pass phrase source\n","-pass <arg>"); 271 BIO_printf(bio_err,"%-14s encrypt\n","-e"); 272 BIO_printf(bio_err,"%-14s decrypt\n","-d"); 273 BIO_printf(bio_err,"%-14s base64 encode/decode, depending on encryption flag\n","-a/-base64"); 274 BIO_printf(bio_err,"%-14s key is the next argument\n","-k"); 275 BIO_printf(bio_err,"%-14s key is the first line of the file argument\n","-kfile"); 276 BIO_printf(bio_err,"%-14s key/iv in hex is the next argument\n","-K/-iv"); 277 BIO_printf(bio_err,"%-14s print the iv/key (then exit if -P)\n","-[pP]"); 278 BIO_printf(bio_err,"%-14s buffer size\n","-bufsize <n>"); 279 #ifndef OPENSSL_NO_ENGINE 280 BIO_printf(bio_err,"%-14s use engine e, possibly a hardware device.\n","-engine e"); 281 #endif 282 283 BIO_printf(bio_err,"Cipher Types\n"); 284 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, 285 show_ciphers, 286 bio_err); 287 BIO_printf(bio_err,"\n"); 288 289 goto end; 290 } 291 argc--; 292 argv++; 293 } 294 295 #ifndef OPENSSL_NO_ENGINE 296 e = setup_engine(bio_err, engine, 0); 297 #endif 298 299 if (bufsize != NULL) 300 { 301 unsigned long n; 302 303 for (n=0; *bufsize; bufsize++) 304 { 305 i= *bufsize; 306 if ((i <= '9') && (i >= '0')) 307 n=n*10+i-'0'; 308 else if (i == 'k') 309 { 310 n*=1024; 311 bufsize++; 312 break; 313 } 314 } 315 if (*bufsize != '\0') 316 { 317 BIO_printf(bio_err,"invalid 'bufsize' specified.\n"); 318 goto end; 319 } 320 321 /* It must be large enough for a base64 encoded line */ 322 if (n < 80) n=80; 323 324 bsize=(int)n; 325 if (verbose) BIO_printf(bio_err,"bufsize=%d\n",bsize); 326 } 327 328 strbuf=OPENSSL_malloc(SIZE); 329 buff=(unsigned char *)OPENSSL_malloc(EVP_ENCODE_LENGTH(bsize)); 330 if ((buff == NULL) || (strbuf == NULL)) 331 { 332 BIO_printf(bio_err,"OPENSSL_malloc failure %ld\n",(long)EVP_ENCODE_LENGTH(bsize)); 333 goto end; 334 } 335 336 in=BIO_new(BIO_s_file()); 337 out=BIO_new(BIO_s_file()); 338 if ((in == NULL) || (out == NULL)) 339 { 340 ERR_print_errors(bio_err); 341 goto end; 342 } 343 if (debug) 344 { 345 BIO_set_callback(in,BIO_debug_callback); 346 BIO_set_callback(out,BIO_debug_callback); 347 BIO_set_callback_arg(in,bio_err); 348 BIO_set_callback_arg(out,bio_err); 349 } 350 351 if (inf == NULL) 352 BIO_set_fp(in,stdin,BIO_NOCLOSE); 353 else 354 { 355 if (BIO_read_filename(in,inf) <= 0) 356 { 357 perror(inf); 358 goto end; 359 } 360 } 361 362 if(!str && passarg) { 363 if(!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { 364 BIO_printf(bio_err, "Error getting password\n"); 365 goto end; 366 } 367 str = pass; 368 } 369 370 if ((str == NULL) && (cipher != NULL) && (hkey == NULL)) 371 { 372 for (;;) 373 { 374 char buf[200]; 375 376 sprintf(buf,"enter %s %s password:", 377 OBJ_nid2ln(EVP_CIPHER_nid(cipher)), 378 (enc)?"encryption":"decryption"); 379 strbuf[0]='\0'; 380 i=EVP_read_pw_string((char *)strbuf,SIZE,buf,enc); 381 if (i == 0) 382 { 383 if (strbuf[0] == '\0') 384 { 385 ret=1; 386 goto end; 387 } 388 str=strbuf; 389 break; 390 } 391 if (i < 0) 392 { 393 BIO_printf(bio_err,"bad password read\n"); 394 goto end; 395 } 396 } 397 } 398 399 400 if (outf == NULL) 401 { 402 BIO_set_fp(out,stdout,BIO_NOCLOSE); 403 #ifdef OPENSSL_SYS_VMS 404 { 405 BIO *tmpbio = BIO_new(BIO_f_linebuffer()); 406 out = BIO_push(tmpbio, out); 407 } 408 #endif 409 } 410 else 411 { 412 if (BIO_write_filename(out,outf) <= 0) 413 { 414 perror(outf); 415 goto end; 416 } 417 } 418 419 rbio=in; 420 wbio=out; 421 422 if (base64) 423 { 424 if ((b64=BIO_new(BIO_f_base64())) == NULL) 425 goto end; 426 if (debug) 427 { 428 BIO_set_callback(b64,BIO_debug_callback); 429 BIO_set_callback_arg(b64,bio_err); 430 } 431 if (olb64) 432 BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); 433 if (enc) 434 wbio=BIO_push(b64,wbio); 435 else 436 rbio=BIO_push(b64,rbio); 437 } 438 439 if (cipher != NULL) 440 { 441 /* Note that str is NULL if a key was passed on the command 442 * line, so we get no salt in that case. Is this a bug? 443 */ 444 if (str != NULL) 445 { 446 /* Salt handling: if encrypting generate a salt and 447 * write to output BIO. If decrypting read salt from 448 * input BIO. 449 */ 450 unsigned char *sptr; 451 if(nosalt) sptr = NULL; 452 else { 453 if(enc) { 454 if(hsalt) { 455 if(!set_hex(hsalt,salt,sizeof salt)) { 456 BIO_printf(bio_err, 457 "invalid hex salt value\n"); 458 goto end; 459 } 460 } else if (RAND_pseudo_bytes(salt, sizeof salt) < 0) 461 goto end; 462 /* If -P option then don't bother writing */ 463 if((printkey != 2) 464 && (BIO_write(wbio,magic, 465 sizeof magic-1) != sizeof magic-1 466 || BIO_write(wbio, 467 (char *)salt, 468 sizeof salt) != sizeof salt)) { 469 BIO_printf(bio_err,"error writing output file\n"); 470 goto end; 471 } 472 } else if(BIO_read(rbio,mbuf,sizeof mbuf) != sizeof mbuf 473 || BIO_read(rbio, 474 (unsigned char *)salt, 475 sizeof salt) != sizeof salt) { 476 BIO_printf(bio_err,"error reading input file\n"); 477 goto end; 478 } else if(memcmp(mbuf,magic,sizeof magic-1)) { 479 BIO_printf(bio_err,"bad magic number\n"); 480 goto end; 481 } 482 483 sptr = salt; 484 } 485 486 EVP_BytesToKey(cipher,EVP_md5(),sptr, 487 (unsigned char *)str, 488 strlen(str),1,key,iv); 489 /* zero the complete buffer or the string 490 * passed from the command line 491 * bug picked up by 492 * Larry J. Hughes Jr. <hughes@indiana.edu> */ 493 if (str == strbuf) 494 OPENSSL_cleanse(str,SIZE); 495 else 496 OPENSSL_cleanse(str,strlen(str)); 497 } 498 if ((hiv != NULL) && !set_hex(hiv,iv,sizeof iv)) 499 { 500 BIO_printf(bio_err,"invalid hex iv value\n"); 501 goto end; 502 } 503 if ((hiv == NULL) && (str == NULL)) 504 { 505 /* No IV was explicitly set and no IV was generated 506 * during EVP_BytesToKey. Hence the IV is undefined, 507 * making correct decryption impossible. */ 508 BIO_printf(bio_err, "iv undefined\n"); 509 goto end; 510 } 511 if ((hkey != NULL) && !set_hex(hkey,key,sizeof key)) 512 { 513 BIO_printf(bio_err,"invalid hex key value\n"); 514 goto end; 515 } 516 517 if ((benc=BIO_new(BIO_f_cipher())) == NULL) 518 goto end; 519 BIO_set_cipher(benc,cipher,key,iv,enc); 520 if (nopad) 521 { 522 EVP_CIPHER_CTX *ctx; 523 BIO_get_cipher_ctx(benc, &ctx); 524 EVP_CIPHER_CTX_set_padding(ctx, 0); 525 } 526 if (debug) 527 { 528 BIO_set_callback(benc,BIO_debug_callback); 529 BIO_set_callback_arg(benc,bio_err); 530 } 531 532 if (printkey) 533 { 534 if (!nosalt) 535 { 536 printf("salt="); 537 for (i=0; i<sizeof salt; i++) 538 printf("%02X",salt[i]); 539 printf("\n"); 540 } 541 if (cipher->key_len > 0) 542 { 543 printf("key="); 544 for (i=0; i<cipher->key_len; i++) 545 printf("%02X",key[i]); 546 printf("\n"); 547 } 548 if (cipher->iv_len > 0) 549 { 550 printf("iv ="); 551 for (i=0; i<cipher->iv_len; i++) 552 printf("%02X",iv[i]); 553 printf("\n"); 554 } 555 if (printkey == 2) 556 { 557 ret=0; 558 goto end; 559 } 560 } 561 } 562 563 /* Only encrypt/decrypt as we write the file */ 564 if (benc != NULL) 565 wbio=BIO_push(benc,wbio); 566 567 for (;;) 568 { 569 inl=BIO_read(rbio,(char *)buff,bsize); 570 if (inl <= 0) break; 571 if (BIO_write(wbio,(char *)buff,inl) != inl) 572 { 573 BIO_printf(bio_err,"error writing output file\n"); 574 goto end; 575 } 576 } 577 if (!BIO_flush(wbio)) 578 { 579 BIO_printf(bio_err,"bad decrypt\n"); 580 goto end; 581 } 582 583 ret=0; 584 if (verbose) 585 { 586 BIO_printf(bio_err,"bytes read :%8ld\n",BIO_number_read(in)); 587 BIO_printf(bio_err,"bytes written:%8ld\n",BIO_number_written(out)); 588 } 589 end: 590 ERR_print_errors(bio_err); 591 if (strbuf != NULL) OPENSSL_free(strbuf); 592 if (buff != NULL) OPENSSL_free(buff); 593 if (in != NULL) BIO_free(in); 594 if (out != NULL) BIO_free_all(out); 595 if (benc != NULL) BIO_free(benc); 596 if (b64 != NULL) BIO_free(b64); 597 if(pass) OPENSSL_free(pass); 598 apps_shutdown(); 599 OPENSSL_EXIT(ret); 600 } 601 602 int set_hex(char *in, unsigned char *out, int size) 603 { 604 int i,n; 605 unsigned char j; 606 607 n=strlen(in); 608 if (n > (size*2)) 609 { 610 BIO_printf(bio_err,"hex string is too long\n"); 611 return(0); 612 } 613 memset(out,0,size); 614 for (i=0; i<n; i++) 615 { 616 j=(unsigned char)*in; 617 *(in++)='\0'; 618 if (j == 0) break; 619 if ((j >= '0') && (j <= '9')) 620 j-='0'; 621 else if ((j >= 'A') && (j <= 'F')) 622 j=j-'A'+10; 623 else if ((j >= 'a') && (j <= 'f')) 624 j=j-'a'+10; 625 else 626 { 627 BIO_printf(bio_err,"non-hex digit\n"); 628 return(0); 629 } 630 if (i&1) 631 out[i/2]|=j; 632 else 633 out[i/2]=(j<<4); 634 } 635 return(1); 636 } 637