// encrypt.c// contains all encryption code necessary for MSUAM encryption#include <string.h>#include "encrypt.h"#include "UAMDebug.h"/*-------------------------------------------------------------------*\		DES defines.\*-------------------------------------------------------------------*/unsigned char *IP;unsigned char *FP;unsigned char *PC1_C;unsigned char *PC1_D;unsigned char *PC2_C;unsigned char *PC2_D;unsigned char *SHIFTS;unsigned char *E;unsigned char S[8][64];unsigned char *P;/*-------------------------------------------------------------------*\		DES structure.\*-------------------------------------------------------------------*/typedef struct _desdata {	char header[4];	unsigned char IP[64];	unsigned char FP[64];	unsigned char PC1_C[28];	unsigned char PC1_D[28];	unsigned char SHIFTS[16];	unsigned char PC2_C[24];	unsigned char PC2_D[24];	 	unsigned char E[48];	unsigned char S[8][64];	unsigned char P[32];} desdata, *PDesData, **HDesData;static Handle ghMSUAMDesData = NULL; // static global handle (e.g. this file global only)// ---------------------------------------------------------------------------//		¥ SetupUAMEncrypt()// ---------------------------------------------------------------------------// Setup the table.//// Returns TRUE if the data resource was successfully read into memory, FALSE// otherwise.Boolean SetupUAMEncrypt( void ){	PDesData pdd;		ghMSUAMDesData = GetResource('data', 2);	if (ghMSUAMDesData == NULL)	{		DbgPrint_((DBGBUFF, "Couldn't get 'data' resource"));		return(false);	}		HLock(ghMSUAMDesData);	HNoPurge(ghMSUAMDesData);		pdd 	= *(HDesData)ghMSUAMDesData;	IP 		= pdd->IP;	FP 		= pdd->FP;	PC1_C 	= pdd->PC1_C;	PC1_D 	= pdd->PC1_D;	SHIFTS 	= pdd->SHIFTS;	PC2_C 	= pdd->PC2_C;	PC2_D 	= pdd->PC2_D;	E 		= pdd->E;		BlockMove(pdd->S, S, 8*64);		P = pdd->P;		return(true);}// ---------------------------------------------------------------------------//		¥ CleanupUAMEncrypt()// ---------------------------------------------------------------------------void CleanupUAMEncrypt( void ){	if (ghMSUAMDesData)	{		HUnlock(ghMSUAMDesData);		HPurge(ghMSUAMDesData);				ReleaseResource(ghMSUAMDesData);	}}// ---------------------------------------------------------------------------//		¥ UprCString()// ---------------------------------------------------------------------------void UprCString(char* psz){	c2pstr(psz);	UpperString(*(Str255 *)psz, true); // really a pstr right now	p2cstr((StringPtr)psz);}// ---------------------------------------------------------------------------//		¥ OneWayFunction()// ---------------------------------------------------------------------------//     Inputs  - P14//     Outputs - P22////     Let P14 be the plain text password obtained at logon time, *passed in as a//	 zero-terminated string and null padded herein to max length*.////     P14 is used to encrypt the standard text, S8, and get P21.//	 Encryption of standard text is accomplished with an option (ENCR_STD)//	 to CryptIOCTL_2.////     P21[0..7] = E(P14[0..6], S8)//     P21[8..15] = E(P14[7..13], S8)//     P21[16..20] = 0unsigned char *OneWayFunction(unsigned char *pucPwd, unsigned char *pucDest, short scb){	SInt16 len = strlen((char *)pucPwd);		Assert_(pucPwd != NULL);	Assert_(pucDest != NULL);		if (len > scb)	{		Assert_(0);		return (pucDest);	}		memset((char *)pucPwd+len, '\0', scb-len);		CryptIOCTL2(ENCR_STD, pucPwd, nil, pucDest);	CryptIOCTL2(ENCR_STD, pucPwd+7, nil, pucDest+8);		memset((char *)pucDest + 16, '\0', 5);	return(pucDest);}// ---------------------------------------------------------------------------//		¥ Encrypt()// ---------------------------------------------------------------------------//     Inputs  - P21 (from OneWayChallenge())//     Outputs - P24////     P21 is used to encrypt the challenge, C8 sent by the server, to//     get P24, which is the response sent back  to the server.////     P24[0..7] = E(P21[0..6], C8)//     P24[8..15] = E(P21[7..13], C8)//     P24[16..23] = E(P21[14..20], C8)unsigned char *Encrypt(unsigned char *key, unsigned char *source, unsigned char *dest){	Assert_(key != NULL);	Assert_(source != NULL);	Assert_(dest != NULL);		CryptIOCTL2(ENCR_KEY, source, key, dest);	CryptIOCTL2(ENCR_KEY, source+7, key, dest+8);	CryptIOCTL2(ENCR_KEY, source+14, key, dest+16);		return(dest);}/************* Macintosh RDEV-environment version hacked by Wayne F. Tackabury, Pacer Software. 			  Adapted from OS/2 version by Narendra Gidwani.			  			  Primary modifications: 			  		--  StdEncrPwd turned into #define					--  Allocation of a large table for underlying DES code to store its						encryption tables. 											Primary motivation:  in this environment, we have no global data 					context to work with. 			Copyright (c) 1992 Microsoft Corp.************//*  Standard text for the ENCR_STD operation   */// ---------------------------------------------------------------------------//		¥ CryptIOCTL2()// ---------------------------------------------------------------------------unsigned pascal CryptIOCTL2(			unsigned 		Option,			unsigned char* 	Key,			unsigned char*	Src,			unsigned char*	Dst){	unsigned char	Buffer[8];	unsigned char	CBuffer[8];	KeyTbl*			allocatedKeyTable;	if (Dst == NULL)	{		Assert_(0);		return 1;	}		Dst[0] = 0;	Dst[7] = 0;		if (!Src && Option != ENCR_STD)	{		Assert_(0);		return(1);	}	//	//Allocate the key table which the underlying routines will need to generate	//their de/en-cryption tables	//	if ((allocatedKeyTable = (KeyTbl *) NewPtrClear(sizeof(KeyTbl))) == nil)		return(1);	if (Option == ENCR_STD)		memcpy(Buffer, StdEncrPwd, 8);	else		memcpy(Buffer, Src, 8);	InitKey(Key, allocatedKeyTable);		switch (Option)	{		case ENCR_KEY:		case ENCR_STD:			des( Buffer, CBuffer, allocatedKeyTable, ENCRYPT );			break;		case DECR_KEY:			des( Buffer, CBuffer, allocatedKeyTable, DECRYPT );			break;		default:			Assert_(0);			DisposePtr((Ptr) allocatedKeyTable);			return(1);	}		//	//We have results.  Copy them across, deallocate our key table heap, and return.	//		memcpy(Dst, CBuffer, 8);	DisposePtr((Ptr) allocatedKeyTable);		return(0);}/*** This file contains all the routines necessary for implementation of** Federal Information Processing Data Encryption Standard (DES).** Sytek Inc., Linden S. Feldman**** This file contains the following high level DES routines:****     setkey(key);        set an 8 byte key for subsequent encrypt/decrypt.**     encrypt(buf);       encrypt an 8 byte binary buffer.**     decrypt(buf);       decrypt an 8 byte binary buffer.**     ede( buf, l, r );   encrypt buf with key encrypting key parts l and r.**     ded( buf, l, r );   decrypt buf with key encrypting key parts l and r.****** Also in this file are the following low level DES routines:****     key_table(key)                   called by setkey() to init key table.**     des(buf,crypt_mode)              called by encrypt() and decrypt().**     des_cipher(buf,crypt_mode)       called by des().*//**			Macintosh rdev/Chooser environment version hacked by Wayne Tackabury,			Pacer Software, Inc. Sunday, August 9, 1992.	Copyright (c) 1992 Pacer Software, Inc.,La Jolla, CA  92037	Copyright (c) 1992 Microsoft Corp.						PRIMARY MODIFICATIONS:						In this environment, we have no global data context, and certainly no capa-			bility for autoinitialization of same.  What we must do instead is to either			externally reference constant tablular/heap information which can be stored			in the outermost assembly-code storage of this containing module, or dynamically			allocate what we actually need to modify.  I cheated even further, stuffing some			tables into automatic storage of routines herein, since in this envrionment, we 			are considerably more blessed with stack space than we are with static heap.					->	the following arrays previously declared globally are now in the routines			indicated						C[], D[]				key_table()			L[], tempL[], f[]		des_cipher();								->	The key selector table, previously just known as KS[][], is now defined in 			typedef KeyTbl.  A pointer to an allocated KeyTbl is now an input parameter to			InitKey(), Key_table(), des(), and des_cipher.					->	Also, SetKey() was deleted since it didn't seem to get called and I would like to			save some code resource space here where I can.					->	Also, function desf(), which was just dealing with far/near insecurities for 			data addressing was removed since we don't worry about that in this environment.					->	last, various PC/Microsoft C-centric typedefs (e.g., "_cdecl") were axed.		**/		// ---------------------------------------------------------------------------//		¥ key_table()// ---------------------------------------------------------------------------// Set up the key table (schedule) from the key.void key_table(unsigned char  *key, KeyTbl *generatedKeyTable){        register int i, j;        unsigned short k, t;	/*	** The C and D arrays used to calculate the key schedule.	*/	unsigned char   C[28];	unsigned char   D[28];    /*    ** First, generate C and D by permuting    ** the key.  The low order bit of each    ** 8-bit unsigned 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]];        D[i] = key[PC1_D[i]];    }        /*    ** 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<SHIFTS[i]; k++)        {            t = C[0];            for (j=0; j<28-1; j++)            	C[j] = C[j+1];            C[27] = (unsigned char) t;            t = D[0];            for (j=0; j<28-1; j++)            	D[j] = D[j+1];            D[27] = (unsigned char) t;        }                /*        ** get Ki. Note C and D are concatenated.        */        for (j=0; j<24; j++)        {        	generatedKeyTable->KS[i][j] = C[PC2_C[j]];			generatedKeyTable->KS[i][j+24] = D[PC2_D[j]];        }    }}// ---------------------------------------------------------------------------//		¥ des_cipher()// ---------------------------------------------------------------------------// The payoff: encrypt or decrypt a block depending on crypt_mode = 0 or 1// respectively.void des_cipher(unsigned char  *block, KeyTbl *keySchedule, int crypt_mode){	register int i, j;	int ii, v, t, k, tblIndex;	/*	** The current block, divided into 2 halves.	*/	unsigned char   L[64];	// unsigned char   R[32];	/*	** R[32] not used.	** Normally L[64] would be set to L[32] and R[32] is not accessed directly	** but indirectly through extended access of L[32+j] where j is 0 - 32.	** Due to INTEL byte swapping some C compilers align arrays on even	** boundaries, some worse yet on paragraph boundaries, so L[32] was	** modified to be L[64] in order to correctly handle the extended accessing.	*/	unsigned char   tempL[32];	unsigned char   f[32];	/*	** The combination of the key and the input, before selection.	*/	unsigned char   preS[48];        /*        ** First, permute the bits in the input        */        for (j=0; j<64; j++)				{				tblIndex = (int)IP[j];                L[j] = block[tblIndex];				}        /*        ** Perform an encryption operation 16 times.        */        for (ii=0; ii<16; ii++) {                /*                ** Set direction                */                if (crypt_mode)                        i = 15-ii;                else                        i = ii;                /*                ** Save the R array,                ** which will be the new L.                */                for (j=0; j<32; j++)                        tempL[j] = L[j+32];                /*                ** Expand R to 48 bits using the E selector;                ** exclusive-or with the current key bits.                */                for (j=0; j<48; j++)                        preS[j] = L[E[j]+32] ^ keySchedule->KS[i][j];                /*                ** The pre-select bits are now considered                ** in 8 groups of 6 bits each.                ** The 8 selection functions map these                ** 6-bit quantities into 4-bit quantities                ** and the results permuted to make an f(R, K).                ** The indexing into the selection functions                ** is peculiar; it could be simplified by                ** rewriting the tables.                */                for (j=0; j<8; j++) {                        t = 6*j;                        v = j;                        k = S[v][(preS[t+0]<<5)+                                (preS[t+1]<<3)+                                (preS[t+2]<<2)+                                (preS[t+3]<<1)+                                (preS[t+4]<<0)+                                (preS[t+5]<<4)];                        t = 4*j;                        f[t+0] = (unsigned char) ((k>>3)&01);                        f[t+1] = (unsigned char) ((k>>2)&01);                        f[t+2] = (unsigned char) ((k>>1)&01);                        f[t+3] = (unsigned char) ((k>>0)&01);                }       /* end of for loop doing the 8 groups of pre-select bits */                /*                ** The new R is L ^ f(R, K).                ** The f here has to be permuted first, though.                */                for (j=0; j<32; j++)                        L[j+32] = L[j] ^ f[P[j]];                /*                ** Finally, the new L (the original R)                ** is copied back.                */                for (j=0; j<32; j++)                        L[j] = tempL[j];        } /* end of encrypted operation (16 times) */        /*        ** The output L and R are reversed.        */        for (j=0; j<32; j++) {                t = L[j];                L[j] = L[j+32];                L[j+32] = (unsigned char) t;        }        /*        ** The final output        ** gets the inverse permutation of the very original.        */        for (j=0; j<64; j++)                block[j] = L[FP[j]];}// ---------------------------------------------------------------------------//		¥ des()// ---------------------------------------------------------------------------void des(unsigned char *inbuf, unsigned char *outbuf, KeyTbl *keySchedule, int crypt_mode){    register int i, j;    unsigned char block[64];        for(i=0; i<64; i++)                block[i] = 0;        /*        ** expand the bytes into a bit table.        */        for(i=0; i<8; i++)                for(j=0; j<8; j++)                        block[8*i+j]=(unsigned char)((inbuf[i] >> (7-j)) & 01);        des_cipher( block, keySchedule, crypt_mode );        for(i=0; i<8; i++) {            /* compress */                outbuf[i] = 0;                for(j=0; j<8; j++) {                        outbuf[i] <<= 1;                        outbuf[i] |= block[8*i+j];                }        }}// ---------------------------------------------------------------------------//		¥ InitKey()// ---------------------------------------------------------------------------void InitKey(unsigned  char  *Key, KeyTbl *generatedKeyTable){   register int   i, j, k;   unsigned char  block[64];   k = 0;   memset((char *)block, 0, 64);   for (i = 0; i < 8 ; i++ ) {      for (j = 0 ; j < 7 ; j++ ) {         block[8*i + j] = GETBIT(Key, k);         k++;      }   }   key_table(block, generatedKeyTable);}