www.pudn.com > sslref30.zip > des.c
/* des.c */ /* Copyright (C) 1993 Eric Young - see README for more details */ #include#ifdef VMS #include #include #else #ifndef _IRIX #include #endif #include #endif #include "deseay.h" #if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS) #include #define bcopy(f,t,n) memcpy(t,f,(size_t)(n)) #define bzero(s,n) memset(s,0,(size_t)(n)) #define bcmp(a,b,n) memcmp(a, b,(size_t)(n)) #define index(s,c) strchr(s,c) #endif #ifdef PROTO int usage(void); int doencryption(void); int uufwrite(char *data, int size, int num, FILE *fp); int uufwriteEnd(FILE *fp); int uufread(char *out,int size,int num,FILE *fp); int uuencode(unsigned char *in,int num,unsigned char *out); int uudecode(unsigned char *in,int num,unsigned char *out); #else int usage(); int doencryption(); int uufwrite(); int uufwriteEnd(); int uufread(); int uuencode(); int uudecode(); #endif #ifdef VMS #define EXIT(a) exit(a&0x10000000) #else #define EXIT(a) exit(a) #endif #define BUFSIZE (8*1024) #define VERIFY 1 #define KEYSIZ 8 #define KEYSIZB 1024 /* should hit tty line limit first :-) */ char key[KEYSIZB+1]; int do_encrypt,longk=0; char *in=NULL,*out=NULL; FILE *DES_IN,*DES_OUT,*CKSUM_OUT; char uuname[200]; char uubuf[50]; int uubufnum; #define INUUBUFN (45*100) #define OUTUUBUF (65*100) char b[OUTUUBUF]; char bb[300]; des_cblock cksum={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; char cksumname[200]=""; int cflag,eflag,dflag,kflag,bflag,fflag,sflag,uflag,flag3,hflag,error; main(argc,argv) int argc; char *argv[]; { int i; struct stat ins,outs; char *p; cflag=eflag=dflag=kflag=hflag=bflag=fflag=sflag=uflag=flag3=0,error=0; bzero(key,sizeof(key)); for (i=1; i =0; j--) argv[i][j]='\0'; } break; default: fprintf(stderr,"'%c' unknown flag\n",p[-1]); error=1; break; } } } else { if (in == NULL) in=argv[i]; else if (out == NULL) out=argv[i]; else error=1; } } if (error) usage(); /* We either * do checksum or * do encrypt or * do decrypt or * do decrypt then ckecksum or * do checksum then encrypt */ if (((eflag+dflag) == 1) || cflag) { if (eflag) do_encrypt=DES_ENCRYPT; if (dflag) do_encrypt=DES_DECRYPT; } else usage(); if ( (in != NULL) && (out != NULL) && #ifndef MSDOS (stat(in,&ins) != -1) && (stat(out,&outs) != -1) && (ins.st_dev == outs.st_dev) && (ins.st_ino == outs.st_ino)) #else /* MSDOS */ (strcmp(in,out) == 0)) #endif { fputs("input and output file are the same\n",stderr); EXIT(3); } if (!kflag) if (des_read_pw_string(key,KEYSIZB+1,"Enter key:",eflag?VERIFY:0)) { fputs("password error\n",stderr); EXIT(2); } if (in == NULL) DES_IN=stdin; else if ((DES_IN=fopen(in,"r")) == NULL) { perror("opening input file"); EXIT(4); } CKSUM_OUT=stdout; if (out == NULL) { DES_OUT=stdout; CKSUM_OUT=stderr; } else if ((DES_OUT=fopen(out,"w")) == NULL) { perror("opening output file"); EXIT(5); } #ifdef MSDOS /* This should set the file to binary mode. */ { #include if (!(uflag && dflag)) setmode(fileno(DES_IN),O_BINARY); if (!(uflag && eflag)) setmode(fileno(DES_OUT),O_BINARY); } #endif doencryption(); fclose(DES_IN); fclose(DES_OUT); EXIT(0); } usage() { char **u; static char *usage[]={ "des [input-file [output-file]]", "options:", "-e : encrypt using sunOS compatible user key to DES key conversion.", "-E : encrypt ", "-d : decrypt using sunOS compatible user key to DES key conversion.", "-D : decrypt ", "-c[ckname] : generate a cbc_cksum using sunOS compatible user key to", " DES key conversion and output to ckname (stdout default,", " stderr if data being output on stdout). The checksum is", " generated before encryption and after decryption if used", " in conjunction with -[eEdD].", "-C[ckname] : generate a cbc_cksum as for -c but compatible with -[ED].", "-k key : use key 'key'", "-h : the key that is entered will be a hexidecimal number", "-u[uuname] : input file is uudecoded if -[dD] or output uuencoded", " data if -[eE] (uuname is the filename to put in the", " uuencode header).", "-b : encrypt using DES in ecb encryption mode, the defaut is", " cbc mode.", "-3 : encrypt using tripple DES encryption. This uses 2 keys", " generated from the input key. If the input key is less", " than 8 characters long, this is equivelent to normal", " encryption. Default is tripple cbc, -b makes it tripple ecb.", NULL }; for (u=usage; *u; u++) { fputs(*u,stderr); fputc('\n',stderr); } EXIT(1); } doencryption() { register int i; des_key_schedule ks,ks2; unsigned char iv[8],iv2[8],iv3[8]; char *p; int num=0,j,k,l,rem,ll,len,last,ex=0; des_cblock kk,k2; FILE *O; int Exit=0; #ifndef MSDOS static unsigned char buf[BUFSIZE+8],obuf[BUFSIZE+8]; #else static unsigned char *buf=NULL,*obuf=NULL; if (buf == NULL) { if ( (( buf=(unsigned char *)malloc(BUFSIZE+8)) == NULL) || ((obuf=(unsigned char *)malloc(BUFSIZE+8)) == NULL)) { fputs("Not enough memory\n",stderr); Exit=10; goto problems; } } #endif if (hflag) { j=(flag3?16:8); p=key; for (i=0; i = '0')) k=(*p-'0')<<4; else if ((*p <= 'f') && (*p >= 'a')) k=(*p-'a'+10)<<4; else if ((*p <= 'F') && (*p >= 'A')) k=(*p-'A'+10)<<4; else { fputs("Bad hex key\n",stderr); Exit=9; goto problems; } p++; if ((*p <= '9') && (*p >= '0')) k|=(*p-'0'); else if ((*p <= 'f') && (*p >= 'a')) k|=(*p-'a'+10); else if ((*p <= 'F') && (*p >= 'A')) k|=(*p-'A'+10); else { fputs("Bad hex key\n",stderr); Exit=9; goto problems; } p++; if (i < 8) kk[i]=k; else k2[i-8]=k; } des_set_key((C_Block *)k2,ks2); bzero(k2,sizeof(k2)); } else if (longk || flag3) { if (flag3) { des_string_to_2keys(key,(C_Block *)kk,(C_Block *)k2); des_set_key((C_Block *)k2,ks2); bzero(k2,sizeof(k2)); } else des_string_to_key(key,(C_Block *)kk); } else for (i=0; i >=1; } if (l & 1) kk[i]=key[i]&0x7f; else kk[i]=key[i]|0x80; } des_set_key((C_Block *)kk,ks); bzero(key,sizeof(key)); bzero(kk,sizeof(kk)); /* woops - A bug that does not showup under unix :-( */ bzero(iv,sizeof(iv)); bzero(iv2,sizeof(iv2)); bzero(iv3,sizeof(iv3)); l=1; rem=0; /* first read */ if (eflag || (!dflag && cflag)) { for (;;) { num=l=fread(&(buf[rem]),1,BUFSIZE,DES_IN); l+=rem; num+=rem; if (l < 0) { perror("read error"); Exit=6; goto problems; } rem=l%8; len=l-rem; if (feof(DES_IN)) { srand(time(NULL)); for (i=7-rem; i>0; i--) buf[l++]=rand()&0xff; buf[l++]=rem; ex=1; len+=rem; } else l-=rem; if (cflag) { des_cbc_cksum((C_Block *)buf,(C_Block *)cksum, (long)len,ks,(C_Block *)cksum); if (!eflag) { if (feof(DES_IN)) break; else continue; } } if (bflag && !flag3) for (i=0; i = 8) bcopy(&(obuf[l-8]),iv,8); } if (rem) bcopy(&(buf[l]),buf,rem); i=0; while (i < l) { if (uflag) j=uufwrite(obuf,1,l-i,DES_OUT); else j=fwrite(obuf,1,l-i,DES_OUT); if (j == -1) { perror("Write error"); Exit=7; goto problems; } i+=j; } if (feof(DES_IN)) { if (uflag) uufwriteEnd(DES_OUT); break; } } } else /* decrypt */ { ex=1; for (;;) { if (ex) { if (uflag) l=uufread(buf,1,BUFSIZE,DES_IN); else l=fread(buf,1,BUFSIZE,DES_IN); ex=0; rem=l%8; l-=rem; } if (l < 0) { perror("read error"); Exit=6; goto problems; } if (bflag && !flag3) for (i=0; i = 8) bcopy(&(buf[l-8]),iv,8); } if (uflag) ll=uufread(&(buf[rem]),1,BUFSIZE,DES_IN); else ll=fread(&(buf[rem]),1,BUFSIZE,DES_IN); ll+=rem; rem=ll%8; ll-=rem; if (feof(DES_IN) && (ll == 0)) { last=obuf[l-1]; if ((last > 7) || (last < 0)) { fputs("The file was not decrypted correctly.\n", stderr); /*Exit=8; goto problems;*/ last=0; } l=l-8+last; } i=0; if (cflag) des_cbc_cksum((C_Block *)obuf, (C_Block *)cksum,(long)l/8*8,ks, (C_Block *)cksum); while (i != l) { j=fwrite(obuf,1,l-i,DES_OUT); if (j == -1) { perror("Write error"); Exit=7; goto problems; } i+=j; } l=ll; if ((l == 0) && feof(DES_IN)) break; } } if (cflag) { l=0; if (cksumname[0] != '\0') { if ((O=fopen(cksumname,"w")) != NULL) { CKSUM_OUT=O; l=1; } } for (i=0; i<8; i++) fprintf(CKSUM_OUT,"%02X",cksum[i]); fprintf(CKSUM_OUT,"\n"); if (l) fclose(CKSUM_OUT); } problems: bzero(buf,sizeof(buf)); bzero(obuf,sizeof(obuf)); bzero(ks,sizeof(ks)); bzero(ks2,sizeof(ks2)); bzero(iv,sizeof(iv)); bzero(iv2,sizeof(iv2)); bzero(iv3,sizeof(iv3)); bzero(kk,sizeof(kk)); bzero(k2,sizeof(k2)); bzero(uubuf,sizeof(uubuf)); bzero(b,sizeof(b)); bzero(bb,sizeof(bb)); bzero(cksum,sizeof(cksum)); if (Exit) EXIT(Exit); } int uufwrite(data,size,num,fp) char *data; int size; /* We ignore this parameter but it should be > ~50 I believe */ int num; FILE *fp; { int i,j,left,rem,ret=num; static int start=1; if (start) { fprintf(fp,"begin 600 %s\n", (uuname[0] == '\0')?"text.d":uuname); start=0; } if (uubufnum) { if (uubufnum+num < 45) { bcopy(data,&(uubuf[uubufnum]),num); uubufnum+=num; return(num); } else { i=45-uubufnum; bcopy(data,&(uubuf[uubufnum]),i); j=uuencode(uubuf,45,b); fwrite(b,1,j,fp); uubufnum=0; data+=i; num-=i; } } for (i=0; i<(num-INUUBUFN); i+=INUUBUFN) { j=uuencode(&(data[i]),INUUBUFN,b); fwrite(b,1,j,fp); } rem=(num-i)%45; left=(num-i-rem); if (left) { j=uuencode(&(data[i]),left,b); fwrite(b,1,j,fp); i+=left; } if (i != num) { bcopy(&(data[i]),uubuf,rem); uubufnum=rem; } return(ret); } int uufwriteEnd(fp) FILE *fp; { int j; static char *end=" \nend\n"; if (uubufnum != 0) { uubuf[uubufnum]='\0'; uubuf[uubufnum+1]='\0'; uubuf[uubufnum+2]='\0'; j=uuencode(uubuf,uubufnum,b); fwrite(b,1,j,fp); } fwrite(end,1,strlen(end),fp); } int uufread(out,size,num,fp) char *out; int size; /* should always be > ~ 60; I actually ignore this parameter :-) */ int num; FILE *fp; { int i,j,tot; static int done=0; static int valid=0; static int start=1; if (start) { for (;;) { b[0]='\0'; fgets(b,300,fp); if (b[0] == '\0') { fprintf(stderr,"no 'begin' found in uuencoded input\n"); return(-1); } if (strncmp(b,"begin ",6) == 0) break; } start=0; } if (done) return(0); tot=0; if (valid) { bcopy(bb,out,valid); tot=valid; valid=0; } for (;;) { b[0]='\0'; fgets(b,300,fp); if (b[0] == '\0') break; i=strlen(b); if ((b[0] == 'e') && (b[1] == 'n') && (b[2] == 'd')) { done=1; while (!feof(fp)) { fgets(b,300,fp); } break; } i=uudecode(b,i,bb); if (i < 0) break; if ((i+tot+8) > num) { /* num to copy to make it a multiple of 8 */ j=(num/8*8)-tot-8; bcopy(bb,&(out[tot]),j); tot+=j; bcopy(&(bb[j]),bb,i-j); valid=i-j; break; } bcopy(bb,&(out[tot]),i); tot+=i; } return(tot); } #define ccc2l(c,l) (l =((unsigned long)(*((c)++)))<<16, \ l|=((unsigned long)(*((c)++)))<< 8, \ l|=((unsigned long)(*((c)++)))) #define l2ccc(l,c) (*((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff)) int uuencode(in,num,out) unsigned char *in; int num; unsigned char *out; { int j,i,k,n,tot=0; unsigned long l; register unsigned char *p; p=out; for (j=0; j num) i=(num-j); else i=45; *(p++)=i+' '; for (n=0; n>18)&0x3f)+' '; *(p++)=((l>>12)&0x3f)+' '; *(p++)=((l>> 6)&0x3f)+' '; *(p++)=((l )&0x3f)+' '; tot+=4; } *(p++)='\n'; tot+=2; } *p='\0'; l=0; return(tot); } int uudecode(in,num,out) unsigned char *in; int num; unsigned char *out; { int j,i,k; unsigned int n,space=0; unsigned long l; unsigned long w,x,y,z; unsigned int blank='\n'-' '; for (j=0; j 60) { fprintf(stderr,"uuencoded line length too long\n"); return(-1); } j++; for (i=0; i 63) || (x > 63) || (y > 63) || (z > 63)) { k=0; if (w == blank) k=1; if (x == blank) k=2; if (y == blank) k=3; if (z == blank) k=4; space=1; switch (k) { case 1: w=0; in--; case 2: x=0; in--; case 3: y=0; in--; case 4: z=0; in--; break; case 0: space=0; fprintf(stderr,"bad uuencoded data values\n"); w=x=y=z=0; return(-1); break; } } l=(w<<18)|(x<<12)|(y<< 6)|(z ); l2ccc(l,out); } if (*(in++) != '\n') { fprintf(stderr,"missing nl in uuencoded line\n"); w=x=y=z=0; return(-1); } j++; } *out='\0'; w=x=y=z=0; return(n); }