windows-nt/Source/XPSP1/NT/net/sfm/uam/uam5src/uamsrc/encrypt.c
2020-09-26 16:20:57 +08:00

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);
}