1 line
16 KiB
C
1 line
16 KiB
C
// 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);
|
|
}
|