782 lines
20 KiB
C
782 lines
20 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Micro Computer Systems, Inc.
|
||
|
||
Module Name:
|
||
|
||
nwlibs\encrypt.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the routines for the NetWare
|
||
redirector to mangle an objectid, challenge key and
|
||
password such that a NetWare server will accept the
|
||
password as valid.
|
||
|
||
This program uses information published in Byte Magazine.
|
||
|
||
Author:
|
||
|
||
Shawn Walker (v-swalk) 10-10-1994
|
||
|
||
Revision History:
|
||
|
||
11-9-1994 Copied from nwslib for login and minimars for
|
||
change password.
|
||
09-7-1995 (AndyHe) Put in proper setpass compatible processing
|
||
|
||
--*/
|
||
#include "dswarn.h"
|
||
#include <windef.h>
|
||
#include "encrypt.h"
|
||
#include <oledsdbg.h>
|
||
|
||
#define STATIC
|
||
#define STRLEN strlen
|
||
#define STRUPR _strupr
|
||
|
||
#define NUM_NYBBLES 34
|
||
|
||
STATIC
|
||
VOID
|
||
RespondToChallengePart1(
|
||
IN PUCHAR pObjectId,
|
||
IN PUCHAR pPassword,
|
||
OUT PUCHAR pResponse
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
RespondToChallengePart2(
|
||
IN PUCHAR pResponsePart1,
|
||
IN PUCHAR pChallenge,
|
||
OUT PUCHAR pResponse
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
Shuffle(
|
||
UCHAR *achObjectId,
|
||
UCHAR *szUpperPassword,
|
||
int iPasswordLen,
|
||
UCHAR *achOutputBuffer,
|
||
UCHAR ChangePassword
|
||
);
|
||
|
||
STATIC
|
||
int
|
||
Scramble(
|
||
int iSeed,
|
||
UCHAR achBuffer[32]
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
ExpandBytes(
|
||
IN PUCHAR InArray,
|
||
OUT PUCHAR OutArray
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
CompressBytes(
|
||
IN PUCHAR InArray,
|
||
OUT PUCHAR OutArray
|
||
);
|
||
|
||
VOID
|
||
CalculateWireFromOldAndNewPasswords(
|
||
UCHAR *Vold,
|
||
UCHAR *Vnew,
|
||
UCHAR *Vc
|
||
);
|
||
|
||
|
||
|
||
/*++
|
||
*******************************************************************
|
||
|
||
EncryptLoginPassword
|
||
|
||
Routine Description:
|
||
|
||
Encrypts the password for login.
|
||
|
||
Arguments:
|
||
|
||
pPassword = The pointer to a plain text null terminated password.
|
||
ObjectId = The object id of the user to encrypt the password.
|
||
pLogKey = The pointer to key to use to encrpyt the password.
|
||
pEncryptedPassword = The pointer to return a 8 byte encrypted
|
||
password.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
*******************************************************************
|
||
--*/
|
||
void
|
||
EncryptLoginPassword(
|
||
unsigned char *pPassword,
|
||
unsigned long ObjectId,
|
||
unsigned char *pLogKey,
|
||
unsigned char *pEncryptedPassword
|
||
)
|
||
{
|
||
INT Index;
|
||
UCHAR achK[32];
|
||
UCHAR achBuf[32];
|
||
|
||
ADsAssert(pPassword);
|
||
|
||
/** The password must be upper case **/
|
||
|
||
pPassword = STRUPR(pPassword);
|
||
|
||
/** Encrypt the password **/
|
||
|
||
Shuffle((UCHAR *) &ObjectId, pPassword, STRLEN(pPassword), achBuf, FALSE);
|
||
Shuffle((UCHAR *) &pLogKey[0], achBuf, 16, &achK[0], FALSE);
|
||
Shuffle((UCHAR *) &pLogKey[4], achBuf, 16, &achK[16], FALSE);
|
||
|
||
for (Index = 0; Index < 16; Index++) {
|
||
achK[Index] ^= achK[31 - Index];
|
||
}
|
||
|
||
for (Index = 0; Index < 8; Index++) {
|
||
pEncryptedPassword[Index] = achK[Index] ^ achK[15 - Index];
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
/*++
|
||
*******************************************************************
|
||
|
||
EncryptChangePassword
|
||
|
||
Routine Description:
|
||
|
||
This function encrypts for change passwords.
|
||
|
||
Arguments:
|
||
|
||
pOldPassword = The pointer to the old password.
|
||
pNewPassword = The pointer to the new password.
|
||
ObjectId = The object id to use to encrypt the password.
|
||
pKey = The challenge key from the server.
|
||
pValidationKey = The 8 byte validation key to return.
|
||
pEncryptNewPassword = The 17 byte encrypted new password to
|
||
return.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
*******************************************************************
|
||
--*/
|
||
VOID
|
||
EncryptChangePassword(
|
||
IN PUCHAR pOldPassword,
|
||
IN PUCHAR pNewPassword,
|
||
IN ULONG ObjectId,
|
||
IN PUCHAR pKey,
|
||
OUT PUCHAR pValidationKey,
|
||
OUT PUCHAR pEncryptNewPassword
|
||
)
|
||
{
|
||
UCHAR Vc[17];
|
||
UCHAR Vold[17];
|
||
UCHAR Vnew[17];
|
||
UCHAR ValidationKey[16];
|
||
UCHAR VcTemp[NUM_NYBBLES];
|
||
UCHAR VoldTemp[NUM_NYBBLES];
|
||
UCHAR VnewTemp[NUM_NYBBLES];
|
||
|
||
ADsAssert(pOldPassword);
|
||
ADsAssert(pNewPassword);
|
||
|
||
/** Uppercase the passwords **/
|
||
|
||
pOldPassword = STRUPR(pOldPassword);
|
||
pNewPassword = STRUPR(pNewPassword);
|
||
|
||
//
|
||
// The old password and object ID make up the 17-byte Vold.
|
||
// This is used later to form the 17-byte Vc for changing
|
||
// password on the server.
|
||
//
|
||
|
||
Shuffle((PUCHAR) &ObjectId, pOldPassword, STRLEN(pOldPassword), Vold, FALSE);
|
||
|
||
//
|
||
// Need to make an 8-byte key which includes the old password
|
||
// The server validates this value before allowing the user to
|
||
// set password.
|
||
//
|
||
|
||
RespondToChallengePart2(Vold, pKey, ValidationKey);
|
||
|
||
//
|
||
// Now determine Vold using the Change PW table rather than verify pw table
|
||
//
|
||
|
||
Shuffle((PUCHAR) &ObjectId, pOldPassword, STRLEN(pOldPassword), Vold, TRUE);
|
||
|
||
//
|
||
// The new password and object ID make up the 17-byte Vnew.
|
||
//
|
||
|
||
RespondToChallengePart1((PUCHAR) &ObjectId, pNewPassword, Vnew);
|
||
|
||
//
|
||
// Expand the 17-byte Vold and Vnew arrays into 34-byte arrays
|
||
// for easy munging.
|
||
//
|
||
ExpandBytes(Vold, VoldTemp);
|
||
ExpandBytes(Vnew, VnewTemp);
|
||
|
||
//
|
||
// leave first two bytes of VcTemp free... we slap in the value based
|
||
// on new password length in below.
|
||
//
|
||
|
||
CalculateWireFromOldAndNewPasswords( VoldTemp, VnewTemp, &VcTemp[2] );
|
||
|
||
//
|
||
// Compress 34-byte array of nibbles into 17-byte array of bytes.
|
||
//
|
||
|
||
CompressBytes(VcTemp, Vc);
|
||
|
||
//
|
||
// Calculate the 1st byte of Vc as a function of the new password length
|
||
// and the old password residue.
|
||
//
|
||
|
||
Vc[0] = ( ( ( Vold[0] ^ Vold[1] ) & 0x7F ) | 0x40 ) ^ STRLEN(pNewPassword);
|
||
|
||
memcpy(pValidationKey, ValidationKey, 8);
|
||
memcpy(pEncryptNewPassword, Vc, 17);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
/*++
|
||
*******************************************************************
|
||
Encryption table.
|
||
*******************************************************************
|
||
--*/
|
||
|
||
//
|
||
// This is the same as LoginTable, just in a slightly different format.
|
||
//
|
||
|
||
UCHAR ChangeTable[] = {
|
||
0x78, 0x08, 0x64, 0xe4, 0x5c, 0x17, 0xbf, 0xa8,
|
||
0xf8, 0xcc, 0x94, 0x1e, 0x46, 0x24, 0x0a, 0xb9,
|
||
0x2f, 0xb1, 0xd2, 0x19, 0x5e, 0x70, 0x02, 0x66,
|
||
0x07, 0x38, 0x29, 0x3f, 0x7f, 0xcf, 0x64, 0xa0,
|
||
0x23, 0xab, 0xd8, 0x3a, 0x17, 0xcf, 0x18, 0x9d,
|
||
0x91, 0x94, 0xe4, 0xc5, 0x5c, 0x8b, 0x23, 0x9e,
|
||
0x77, 0x69, 0xef, 0xc8, 0xd1, 0xa6, 0xed, 0x07,
|
||
0x7a, 0x01, 0xf5, 0x4b, 0x7b, 0xec, 0x95, 0xd1,
|
||
0xbd, 0x13, 0x5d, 0xe6, 0x30, 0xbb, 0xf3, 0x64,
|
||
0x9d, 0xa3, 0x14, 0x94, 0x83, 0xbe, 0x50, 0x52,
|
||
0xcb, 0xd5, 0xd5, 0xd2, 0xd9, 0xac, 0xa0, 0xb3,
|
||
0x53, 0x69, 0x51, 0xee, 0x0e, 0x82, 0xd2, 0x20,
|
||
0x4f, 0x85, 0x96, 0x86, 0xba, 0xbf, 0x07, 0x28,
|
||
0xc7, 0x3a, 0x14, 0x25, 0xf7, 0xac, 0xe5, 0x93,
|
||
0xe7, 0x12, 0xe1, 0xf4, 0xa6, 0xc6, 0xf4, 0x30,
|
||
0xc0, 0x36, 0xf8, 0x7b, 0x2d, 0xc6, 0xaa, 0x8d
|
||
};
|
||
|
||
UCHAR LoginTable[] = {
|
||
0x7,0x8,0x0,0x8,0x6,0x4,0xE,0x4,0x5,0xC,0x1,0x7,0xB,0xF,0xA,0x8,
|
||
0xF,0x8,0xC,0xC,0x9,0x4,0x1,0xE,0x4,0x6,0x2,0x4,0x0,0xA,0xB,0x9,
|
||
0x2,0xF,0xB,0x1,0xD,0x2,0x1,0x9,0x5,0xE,0x7,0x0,0x0,0x2,0x6,0x6,
|
||
0x0,0x7,0x3,0x8,0x2,0x9,0x3,0xF,0x7,0xF,0xC,0xF,0x6,0x4,0xA,0x0,
|
||
0x2,0x3,0xA,0xB,0xD,0x8,0x3,0xA,0x1,0x7,0xC,0xF,0x1,0x8,0x9,0xD,
|
||
0x9,0x1,0x9,0x4,0xE,0x4,0xC,0x5,0x5,0xC,0x8,0xB,0x2,0x3,0x9,0xE,
|
||
0x7,0x7,0x6,0x9,0xE,0xF,0xC,0x8,0xD,0x1,0xA,0x6,0xE,0xD,0x0,0x7,
|
||
0x7,0xA,0x0,0x1,0xF,0x5,0x4,0xB,0x7,0xB,0xE,0xC,0x9,0x5,0xD,0x1,
|
||
0xB,0xD,0x1,0x3,0x5,0xD,0xE,0x6,0x3,0x0,0xB,0xB,0xF,0x3,0x6,0x4,
|
||
0x9,0xD,0xA,0x3,0x1,0x4,0x9,0x4,0x8,0x3,0xB,0xE,0x5,0x0,0x5,0x2,
|
||
0xC,0xB,0xD,0x5,0xD,0x5,0xD,0x2,0xD,0x9,0xA,0xC,0xA,0x0,0xB,0x3,
|
||
0x5,0x3,0x6,0x9,0x5,0x1,0xE,0xE,0x0,0xE,0x8,0x2,0xD,0x2,0x2,0x0,
|
||
0x4,0xF,0x8,0x5,0x9,0x6,0x8,0x6,0xB,0xA,0xB,0xF,0x0,0x7,0x2,0x8,
|
||
0xC,0x7,0x3,0xA,0x1,0x4,0x2,0x5,0xF,0x7,0xA,0xC,0xE,0x5,0x9,0x3,
|
||
0xE,0x7,0x1,0x2,0xE,0x1,0xF,0x4,0xA,0x6,0xC,0x6,0xF,0x4,0x3,0x0,
|
||
0xC,0x0,0x3,0x6,0xF,0x8,0x7,0xB,0x2,0xD,0xC,0x6,0xA,0xA,0x8,0xD
|
||
};
|
||
|
||
UCHAR Keys[32] = {
|
||
0x48,0x93,0x46,0x67,0x98,0x3D,0xE6,0x8D,
|
||
0xB7,0x10,0x7A,0x26,0x5A,0xB9,0xB1,0x35,
|
||
0x6B,0x0F,0xD5,0x70,0xAE,0xFB,0xAD,0x11,
|
||
0xF4,0x47,0xDC,0xA7,0xEC,0xCF,0x50,0xC0
|
||
};
|
||
|
||
#define XorArray( DEST, SRC ) { \
|
||
PULONG D = (PULONG)DEST; \
|
||
PULONG S = (PULONG)SRC; \
|
||
int i; \
|
||
for ( i = 0; i <= 7 ; i++ ) { \
|
||
D[i] ^= S[i]; \
|
||
} \
|
||
}
|
||
|
||
/*++
|
||
*******************************************************************
|
||
|
||
RespondToChallengePart1
|
||
|
||
Routine Description:
|
||
|
||
This routine takes the ObjectId and Challenge key from the server
|
||
and encrypts the user supplied password to develop a credential
|
||
for the server to verify.
|
||
|
||
Arguments:
|
||
|
||
pObjectId - Supplies the 4 byte user's bindery object id
|
||
pPassword - Supplies the user's uppercased password
|
||
pChallenge - Supplies the 8 byte challenge key
|
||
pResponse - Returns the 16 byte response held by the server
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
*******************************************************************
|
||
--*/
|
||
|
||
STATIC
|
||
VOID
|
||
RespondToChallengePart1(
|
||
IN PUCHAR pObjectId,
|
||
IN PUCHAR pPassword,
|
||
OUT PUCHAR pResponse
|
||
)
|
||
{
|
||
UCHAR achBuf[32];
|
||
|
||
Shuffle(pObjectId, pPassword, STRLEN(pPassword), achBuf, TRUE);
|
||
memcpy(pResponse, achBuf, 17);
|
||
|
||
return;
|
||
}
|
||
|
||
/*++
|
||
*******************************************************************
|
||
|
||
RespondToChallengePart2
|
||
|
||
Routine Description:
|
||
|
||
This routine takes the result of Shuffling the ObjectId and
|
||
the Password and processes it with a challenge key.
|
||
|
||
Arguments:
|
||
|
||
pResponsePart1 - Supplies the 16 byte output of
|
||
RespondToChallengePart1.
|
||
pChallenge - Supplies the 8 byte challenge key
|
||
pResponse - Returns the 8 byte response
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
*******************************************************************
|
||
--*/
|
||
|
||
STATIC
|
||
VOID
|
||
RespondToChallengePart2(
|
||
IN PUCHAR pResponsePart1,
|
||
IN PUCHAR pChallenge,
|
||
OUT PUCHAR pResponse
|
||
)
|
||
{
|
||
int index;
|
||
UCHAR achK[32];
|
||
|
||
Shuffle( &pChallenge[0], pResponsePart1, 16, &achK[0], TRUE);
|
||
Shuffle( &pChallenge[4], pResponsePart1, 16, &achK[16], TRUE);
|
||
|
||
for (index = 0; index < 16; index++) {
|
||
achK[index] ^= achK[31-index];
|
||
}
|
||
|
||
for (index = 0; index < 8; index++) {
|
||
pResponse[index] = achK[index] ^ achK[15-index];
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
/*++
|
||
*******************************************************************
|
||
|
||
Shuffle
|
||
|
||
Routine Description:
|
||
|
||
This routine shuffles around the object ID with the password
|
||
|
||
Arguments:
|
||
|
||
achObjectId - Supplies the 4 byte user's bindery object id
|
||
szUpperPassword - Supplies the user's uppercased password on the
|
||
first call to process the password. On the
|
||
second and third calls this parameter contains
|
||
the OutputBuffer from the first call
|
||
iPasswordLen - length of uppercased password
|
||
achOutputBuffer - Returns the 8 byte sub-calculation
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
*******************************************************************
|
||
--*/
|
||
|
||
STATIC
|
||
VOID
|
||
Shuffle(
|
||
UCHAR *achObjectId,
|
||
UCHAR *szUpperPassword,
|
||
int iPasswordLen,
|
||
UCHAR *achOutputBuffer,
|
||
UCHAR ChangePassword
|
||
)
|
||
{
|
||
int iTempIndex;
|
||
int iOutputIndex;
|
||
UCHAR achTemp[32];
|
||
|
||
//
|
||
// Truncate all trailing zeros from the password.
|
||
//
|
||
|
||
while (iPasswordLen > 0 && szUpperPassword[iPasswordLen-1] == 0 ) {
|
||
iPasswordLen--;
|
||
}
|
||
|
||
//
|
||
// Initialize the achTemp buffer. Initialization consists of taking
|
||
// the password and dividing it up into chunks of 32. Any bytes left
|
||
// over are the remainder and do not go into the initialization.
|
||
//
|
||
// achTemp[0] = szUpperPassword[0] ^ szUpperPassword[32] ^ szUpper...
|
||
// achTemp[1] = szUpperPassword[1] ^ szUpperPassword[33] ^ szUpper...
|
||
// etc.
|
||
//
|
||
|
||
if ( iPasswordLen > 32) {
|
||
|
||
// At least one chunk of 32. Set the buffer to the first chunk.
|
||
|
||
memcpy( achTemp, szUpperPassword, 32 );
|
||
|
||
szUpperPassword += 32; // Remove the first chunk
|
||
iPasswordLen -= 32;
|
||
|
||
while ( iPasswordLen >= 32 ) {
|
||
//
|
||
// Xor this chunk with the characters already loaded into
|
||
// achTemp.
|
||
//
|
||
|
||
XorArray( achTemp, szUpperPassword);
|
||
|
||
szUpperPassword += 32; // Remove this chunk
|
||
iPasswordLen -= 32;
|
||
}
|
||
|
||
} else {
|
||
|
||
// No chunks of 32 so set the buffer to zero's
|
||
|
||
memset( achTemp, 0, sizeof(achTemp));
|
||
|
||
}
|
||
|
||
//
|
||
// achTemp is now initialized. Load the remainder into achTemp.
|
||
// The remainder is repeated to fill achTemp.
|
||
//
|
||
// The corresponding character from Keys is taken to seperate
|
||
// each repitition.
|
||
//
|
||
// As an example, take the remainder "ABCDEFG". The remainder is expanded
|
||
// to "ABCDEFGwABCDEFGxABCDEFGyABCDEFGz" where w is Keys[7],
|
||
// x is Keys[15], y is Keys[23] and z is Keys[31].
|
||
//
|
||
//
|
||
|
||
if (iPasswordLen > 0) {
|
||
int iPasswordOffset = 0;
|
||
for (iTempIndex = 0; iTempIndex < 32; iTempIndex++) {
|
||
|
||
if (iPasswordLen == iPasswordOffset) {
|
||
iPasswordOffset = 0;
|
||
achTemp[iTempIndex] ^= Keys[iTempIndex];
|
||
} else {
|
||
achTemp[iTempIndex] ^= szUpperPassword[iPasswordOffset++];
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// achTemp has been loaded with the users password packed into 32
|
||
// bytes. Now take the objectid that came from the server and use
|
||
// that to munge every byte in achTemp.
|
||
//
|
||
|
||
for (iTempIndex = 0; iTempIndex < 32; iTempIndex++)
|
||
achTemp[iTempIndex] ^= achObjectId[ iTempIndex & 3];
|
||
|
||
Scramble( Scramble( 0, achTemp ), achTemp );
|
||
|
||
//
|
||
// Finally take pairs of bytes in achTemp and return the two
|
||
// nibbles obtained from Table. The pairs of bytes used
|
||
// are achTemp[n] and achTemp[n+16].
|
||
//
|
||
|
||
for (iOutputIndex = 0; iOutputIndex < 16; iOutputIndex++) {
|
||
|
||
if (ChangePassword) {
|
||
unsigned int offset = achTemp[iOutputIndex << 1],
|
||
shift = (offset & 0x1) ? 0 : 4 ;
|
||
|
||
achOutputBuffer[iOutputIndex] =
|
||
(ChangeTable[offset >> 1] >> shift) & 0xF ;
|
||
|
||
offset = achTemp[(iOutputIndex << 1)+1],
|
||
shift = (offset & 0x1) ? 4 : 0 ;
|
||
|
||
achOutputBuffer[iOutputIndex] |=
|
||
(ChangeTable[offset >> 1] << shift) & 0xF0;
|
||
} else {
|
||
achOutputBuffer[iOutputIndex] =
|
||
LoginTable[achTemp[iOutputIndex << 1]] |
|
||
(LoginTable[achTemp[(iOutputIndex << 1) + 1]] << 4);
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
/*++
|
||
*******************************************************************
|
||
|
||
Scramble
|
||
|
||
Routine Description:
|
||
|
||
This routine scrambles around the contents of the buffer. Each
|
||
buffer position is updated to include the contents of at least
|
||
two character positions plus an EncryptKey value. The buffer
|
||
is processed left to right and so if a character position chooses
|
||
to merge with a buffer position to its left then this buffer
|
||
position will include bits derived from at least 3 bytes of
|
||
the original buffer contents.
|
||
|
||
Arguments:
|
||
|
||
iSeed =
|
||
achBuffer =
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
*******************************************************************
|
||
--*/
|
||
STATIC
|
||
int
|
||
Scramble(
|
||
int iSeed,
|
||
UCHAR achBuffer[32]
|
||
)
|
||
{
|
||
int iBufferIndex;
|
||
|
||
for (iBufferIndex = 0; iBufferIndex < 32; iBufferIndex++) {
|
||
achBuffer[iBufferIndex] =
|
||
(UCHAR)(
|
||
((UCHAR)(achBuffer[iBufferIndex] + iSeed)) ^
|
||
((UCHAR)( achBuffer[(iBufferIndex+iSeed) & 31] -
|
||
Keys[iBufferIndex] )));
|
||
|
||
iSeed += achBuffer[iBufferIndex];
|
||
}
|
||
return iSeed;
|
||
}
|
||
|
||
//
|
||
// Takes a 17-byte array and makes a 34-byte array out of it by
|
||
// putting each nibble into the space of a byte.
|
||
//
|
||
|
||
STATIC
|
||
void
|
||
ExpandBytes(
|
||
IN PUCHAR InArray,
|
||
OUT PUCHAR OutArray
|
||
)
|
||
{
|
||
unsigned int i;
|
||
|
||
for (i = 0 ; i < (NUM_NYBBLES / 2); i++) {
|
||
OutArray[i * 2] = InArray[i] & 0x0f;
|
||
OutArray[(i * 2) + 1] = (InArray[i] & 0xf0) >> 4;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Takes a 34-byte array and makes a 17-byte array out of it
|
||
// by combining the lower nibbles of two bytes into a byte.
|
||
//
|
||
|
||
STATIC
|
||
void
|
||
CompressBytes(
|
||
IN PUCHAR InArray,
|
||
OUT PUCHAR OutArray
|
||
)
|
||
{
|
||
unsigned int i;
|
||
|
||
for (i = 0; i < (NUM_NYBBLES / 2); i++) {
|
||
OutArray[i] = InArray[i * 2] | (InArray[i * 2 + 1] << 4);
|
||
}
|
||
}
|
||
|
||
|
||
#define N 0x10
|
||
typedef char entry_t;
|
||
|
||
entry_t pinv[N][N] = {
|
||
{ 0xF,0x8,0x5,0x7,0xC,0x2,0xE,0x9,0x0,0x1,0x6,0xD,0x3,0x4,0xB,0xA,},
|
||
{ 0x2,0xC,0xE,0x6,0xF,0x0,0x1,0x8,0xD,0x3,0xA,0x4,0x9,0xB,0x5,0x7,},
|
||
{ 0x5,0x2,0x9,0xF,0xC,0x4,0xD,0x0,0xE,0xA,0x6,0x8,0xB,0x1,0x3,0x7,},
|
||
{ 0xF,0xD,0x2,0x6,0x7,0x8,0x5,0x9,0x0,0x4,0xC,0x3,0x1,0xA,0xB,0xE,},
|
||
{ 0x5,0xE,0x2,0xB,0xD,0xA,0x7,0x0,0x8,0x6,0x4,0x1,0xF,0xC,0x3,0x9,},
|
||
{ 0x8,0x2,0xF,0xA,0x5,0x9,0x6,0xC,0x0,0xB,0x1,0xD,0x7,0x3,0x4,0xE,},
|
||
{ 0xE,0x8,0x0,0x9,0x4,0xB,0x2,0x7,0xC,0x3,0xA,0x5,0xD,0x1,0x6,0xF,},
|
||
{ 0x1,0x4,0x8,0xA,0xD,0xB,0x7,0xE,0x5,0xF,0x3,0x9,0x0,0x2,0x6,0xC,},
|
||
{ 0x5,0x3,0xC,0x8,0xB,0x2,0xE,0xA,0x4,0x1,0xD,0x0,0x6,0x7,0xF,0x9,},
|
||
{ 0x6,0x0,0xB,0xE,0xD,0x4,0xC,0xF,0x7,0x2,0x8,0xA,0x1,0x5,0x3,0x9,},
|
||
{ 0xB,0x5,0xA,0xE,0xF,0x1,0xC,0x0,0x6,0x4,0x2,0x9,0x3,0xD,0x7,0x8,},
|
||
{ 0x7,0x2,0xA,0x0,0xE,0x8,0xF,0x4,0xC,0xB,0x9,0x1,0x5,0xD,0x3,0x6,},
|
||
{ 0x7,0x4,0xF,0x9,0x5,0x1,0xC,0xB,0x0,0x3,0x8,0xE,0x2,0xA,0x6,0xD,},
|
||
{ 0x9,0x4,0x8,0x0,0xA,0x3,0x1,0xC,0x5,0xF,0x7,0x2,0xB,0xE,0x6,0xD,},
|
||
{ 0x9,0x5,0x4,0x7,0xE,0x8,0x3,0x1,0xD,0xB,0xC,0x2,0x0,0xF,0x6,0xA,},
|
||
{ 0x9,0xA,0xB,0xD,0x5,0x3,0xF,0x0,0x1,0xC,0x8,0x7,0x6,0x4,0xE,0x2,},
|
||
};
|
||
|
||
entry_t master_perm[] = {
|
||
0, 3, 0xe, 0xf, 9, 6, 0xa, 7, 0xc, 0xb, 1, 4, 5, 8, 2, 0xd,
|
||
};
|
||
|
||
entry_t key_sched[N][N];
|
||
entry_t perm_sched[N][N];
|
||
|
||
int InverseTableInitialized = 0;
|
||
|
||
void cipher_inv (
|
||
const entry_t *ctxt,
|
||
const entry_t *key,
|
||
entry_t *ptxt
|
||
)
|
||
{
|
||
int sc, r;
|
||
entry_t v;
|
||
|
||
for (sc = 0; sc < N; sc++) {
|
||
v = ctxt[sc];
|
||
for (r = N; --r >= 0; ) {
|
||
v ^= key[key_sched[sc][r]];
|
||
v = pinv[perm_sched[sc][r]][v];
|
||
}
|
||
ptxt[sc] = v;
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
void swab_nybbles (
|
||
entry_t *vec
|
||
)
|
||
{
|
||
int i, j;
|
||
|
||
//
|
||
// swap all columns instead of calling this routine twice.
|
||
//
|
||
|
||
for (i = 0; i < (2 * N); i += 2) {
|
||
j = vec[i];
|
||
vec[i] = vec[i+1];
|
||
vec[i+1] = j;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
VOID
|
||
CalculateWireFromOldAndNewPasswords(
|
||
UCHAR *Vold,
|
||
UCHAR *Vnew,
|
||
UCHAR *Vc
|
||
)
|
||
{
|
||
if (InverseTableInitialized == 0) {
|
||
|
||
UCHAR sc,r;
|
||
|
||
for (sc = 0; sc < N; sc++) {
|
||
key_sched[sc][N-1] = sc; /* terminal subkey */
|
||
key_sched[0][(N+ N-1 - master_perm[sc])%N] = (N+sc-master_perm[sc])%N;
|
||
}
|
||
for (sc = 1; sc < N; sc++) for (r = 0; r < N; r++) {
|
||
key_sched[sc][(r+master_perm[sc])%N] = (key_sched[0][r] + master_perm[sc]) % N;
|
||
}
|
||
for (sc = 0; sc < N; sc++) {
|
||
perm_sched[sc][N-1] = sc;
|
||
perm_sched[0][(N + N-1 - master_perm[sc])%N] = sc;
|
||
}
|
||
for (sc = 1; sc < N; sc++) for (r = 0; r < N; r++) {
|
||
perm_sched[sc][r] = perm_sched[0][(N+r-master_perm[sc])%N];
|
||
}
|
||
|
||
InverseTableInitialized = 1;
|
||
}
|
||
|
||
//
|
||
// already swapped coming in here... don't swap them again.
|
||
//
|
||
|
||
// swab_nybbles(Vold);
|
||
// swab_nybbles(Vnew);
|
||
|
||
cipher_inv( (entry_t *)(&Vnew[0]),
|
||
(entry_t *)(&Vold[0]),
|
||
(entry_t *)(&Vc[0]));
|
||
cipher_inv( (entry_t *)(&Vnew[16]),
|
||
(entry_t *)(&Vold[16]),
|
||
(entry_t *)(&Vc[16]));
|
||
|
||
// swab_nybbles(Vc);
|
||
return;
|
||
}
|
||
|