static char sccsid[] = "@(#)nbs.c 4.1 (Berkeley) 9/12/82"; # include /* sccs id variable */ static char *nbs_sid = "@(#)nbs.c 1.2"; /* file nbs.c This file has the necessary procedures to use the NBS algorithm to encrypt and decrypt strings of arbitrary length. Basically ciphertext = nbsencrypt(cleartext,secretkey,ciphertext); yields a string ciphertext from string cleartext using the secret string secretkey. Then cleartext = nbsdecrypt(ciphertext,secretkey,cleartext); yields the original string cleartext IF the string secretkey is the same for both calls. The third parameter is filled with the result of the call- it must be (11/8)*size(firstarg). The first and third areguments must be different. The cleartext must be ASCII - the top eighth bit is ignored, so binary data won't work. The plaintext is broken into 8 character sections, encrypted, and concatenated separated by $'s to make the ciphertext. The first 8 letter section uses the secretkey, subsequent sections use the cleartext of the previous section as the key. Thus the ciphertext depends on itself, except for the first section, which depends on the key. This means that sections of the ciphertext, except the first, may not stand alone. Only the first 8 characters of the key matter. */ char *deblknot(), *deblkclr(); char *nbs8decrypt(), *nbs8encrypt(); static char E[48]; char e[]; char *nbsencrypt(str,key,result) char *result; char *str, *key; { static char buf[20],oldbuf[20]; register int j; result[0] = 0; strcpy(oldbuf,key); while(*str){ for(j=0;j<10;j++)buf[j] = 0; for(j=0;j<8 && *str;j++)buf[j] = *str++; strcat(result,nbs8encrypt(buf,oldbuf)); strcat(result,"$"); strcpy(oldbuf,buf); } return(result); } char *nbsdecrypt(cpt,key,result) char *result; char *cpt,*key; { char *s; char c,oldbuf[20]; result[0] = 0; strcpy(oldbuf,key); while(*cpt){ for(s = cpt;*s && *s != '$';s++); c = *s; *s = 0; strcpy(oldbuf,nbs8decrypt(cpt,oldbuf)); strcat(result,oldbuf); if(c == 0)break; cpt = s + 1; } return(result); } /* make key to be sent across the network */ makeuukey(skey,sn,mch) char *skey, *sn, mch; { skey[0] = mch; skey[1] = 0; strcat(skey,sn); } /* all other calls are private */ /* char _sobuf[BUFSIZ]; testing(){ static char res[BUFSIZ]; char *s; char str[BUFSIZ]; setbuf(stdout,_sobuf); while(!feof(stdin)){ fprintf(stderr,"String:\n"); fgets(str,BUFSIZ,stdin); if(feof(stdin))break; strcat(str,"\n"); s = nbsencrypt(str,"hellothere",res); fprintf(stderr,"encrypted:\n%s\n",s); fprintf(stderr,"decrypted:\n"); printf("%s",nbsdecrypt(s,"hellothere",str)); fprintf(stderr,"\n"); } } */ /* To encrypt: The first level of call splits the input strings into strings no longer than 8 characters, for encryption. Then the encryption of 8 characters breaks all but the top bit of each character into a 64-character block, each character with 1 or 0 corresponding to binary. The key is set likewise. The encrypted form is then converted, 6 bits at a time, into an ASCII string. To decrypt: We take the result of the encryption, 6 significant bits per character, and convert it to the block(64-char) fmt. This is decrypted by running the nbs algorithm in reverse, and transformed back into 7bit ASCII. The subroutines to do ASCII blocking and deblocking are .....clr and the funny 6-bit code are .....not. */ char *nbs8encrypt(str,key) char *str, *key; { static char keyblk[100], blk[100]; register int i; enblkclr(keyblk,key); nbssetkey(keyblk); for(i=0;i<48;i++) E[i] = e[i]; enblkclr(blk,str); blkencrypt(blk,0); /* forward dir */ return(deblknot(blk)); } char *nbs8decrypt(crp,key) char *crp, *key; { static char keyblk[100], blk[100]; register int i; enblkclr(keyblk,key); nbssetkey(keyblk); for(i=0;i<48;i++) E[i] = e[i]; enblknot(blk,crp); blkencrypt(blk,1); /* backward dir */ return(deblkclr(blk)); } enblkclr(blk,str) /* ignores top bit of chars in string str */ char *blk,*str; { register int i,j; char c; for(i=0;i<70;i++)blk[i] = 0; for(i=0; (c= *str) && i<64; str++){ for(j=0; j<7; j++, i++) blk[i] = (c>>(6-j)) & 01; i++; } } char *deblkclr(blk) char *blk; { register int i,j; char c; static char iobuf[30]; for(i=0; i<10; i++){ c = 0; for(j=0; j<7; j++){ c <<= 1; c |= blk[8*i+j]; } iobuf[i] = c; } iobuf[i] = 0; return(iobuf); } enblknot(blk,crp) char *blk; char *crp; { register int i,j; char c; for(i=0;i<70;i++)blk[i] = 0; for(i=0; (c= *crp) && i<64; crp++){ if(c>'Z') c -= 6; if(c>'9') c -= 7; c -= '.'; for(j=0; j<6; j++, i++) blk[i] = (c>>(5-j)) & 01; } } char *deblknot(blk) char *blk; { register int i,j; char c; static char iobuf[30]; for(i=0; i<11; i++){ c = 0; for(j=0; j<6; j++){ c <<= 1; c |= blk[6*i+j]; } c += '.'; if(c > '9')c += 7; if(c > 'Z')c += 6; iobuf[i] = c; } iobuf[i] = 0; return(iobuf); } /* * This program implements the * Proposed Federal Information Processing * Data Encryption Standard. * See Federal Register, March 17, 1975 (40FR12134) */ /* * Initial permutation, */ static char IP[] = { 58,50,42,34,26,18,10, 2, 60,52,44,36,28,20,12, 4, 62,54,46,38,30,22,14, 6, 64,56,48,40,32,24,16, 8, 57,49,41,33,25,17, 9, 1, 59,51,43,35,27,19,11, 3, 61,53,45,37,29,21,13, 5, 63,55,47,39,31,23,15, 7, }; /* * Final permutation, FP = IP^(-1) */ static char FP[] = { 40, 8,48,16,56,24,64,32, 39, 7,47,15,55,23,63,31, 38, 6,46,14,54,22,62,30, 37, 5,45,13,53,21,61,29, 36, 4,44,12,52,20,60,28, 35, 3,43,11,51,19,59,27, 34, 2,42,10,50,18,58,26, 33, 1,41, 9,49,17,57,25, }; /* * Permuted-choice 1 from the key bits * to yield C and D. * Note that bits 8,16... are left out: * They are intended for a parity check. */ static char PC1_C[] = { 57,49,41,33,25,17, 9, 1,58,50,42,34,26,18, 10, 2,59,51,43,35,27, 19,11, 3,60,52,44,36, }; static char PC1_D[] = { 63,55,47,39,31,23,15, 7,62,54,46,38,30,22, 14, 6,61,53,45,37,29, 21,13, 5,28,20,12, 4, }; /* * Sequence of shifts used for the key schedule. */ static char shifts[] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1, }; /* * Permuted-choice 2, to pick out the bits from * the CD array that generate the key schedule. */ static char PC2_C[] = { 14,17,11,24, 1, 5, 3,28,15, 6,21,10, 23,19,12, 4,26, 8, 16, 7,27,20,13, 2, }; static char PC2_D[] = { 41,52,31,37,47,55, 30,40,51,45,33,48, 44,49,39,56,34,53, 46,42,50,36,29,32, }; /* * The C and D arrays used to calculate the key schedule. */ static char C[28]; static char D[28]; /* * The key schedule. * Generated from the key. */ static char KS[16][48]; /* * Set up the key schedule from the key. */ nbssetkey(key) char *key; { register i, j, k; int t; /* * First, generate C and D by permuting * the key. The low order bit of each * 8-bit char is not used, so C and D are only 28 * bits apiece. */ for (i=0; i<28; i++) { C[i] = key[PC1_C[i]-1]; D[i] = key[PC1_D[i]-1]; } /* * To generate Ki, rotate C and D according * to schedule and pick up a permutation * using PC2. */ for (i=0; i<16; i++) { /* * rotate. */ for (k=0; k>3)&01; f[t+1] = (k>>2)&01; f[t+2] = (k>>1)&01; f[t+3] = (k>>0)&01; } /* * The new R is L ^ f(R, K). * The f here has to be permuted first, though. */ for (j=0; j<32; j++) R[j] = L[j] ^ f[P[j]-1]; /* * Finally, the new L (the original R) * is copied back. */ for (j=0; j<32; j++) L[j] = tempL[j]; } /* * The output L and R are reversed. */ for (j=0; j<32; j++) { t = L[j]; L[j] = R[j]; R[j] = t; } /* * The final output * gets the inverse permutation of the very original. */ for (j=0; j<64; j++) block[j] = L[FP[j]-1]; }