diff options
Diffstat (limited to '')
-rw-r--r-- | private/nw/convert/nwconv/encrypt.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/private/nw/convert/nwconv/encrypt.c b/private/nw/convert/nwconv/encrypt.c new file mode 100644 index 000000000..bfff89fe0 --- /dev/null +++ b/private/nw/convert/nwconv/encrypt.c @@ -0,0 +1,328 @@ + +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + 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: + + Colin Watson [ColinW] 15-Mar-1993 + +Revision History: + +--*/ + + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +// #include <nwsutil.h> +#include <usrprop.h> +#include <crypt.h> +// #include <ncpcomm.h> + +#define SWAPWORD(w) ((WORD)((w & 0xFF) << 8)|(WORD)(w >> 8)) +#define SWAPLONG(l) MAKELONG(SWAPWORD(HIWORD(l)),SWAPWORD(LOWORD(l))) + +#define NCP_WELL_KNOWN_SUPERVISOR_ID (ULONG) 0x00000001 +#define NCP_WELL_KNOWN_SUPERVISOR_ID_SWAPPED (ULONG) 0x01000000 +#define NCP_WELL_KNOWN_SUPERVISOR_ID_CHICAGO (ULONG) 0x00010000 +#define NCP_WELL_KNOWN_PSERVER_ID (ULONG) 0x00000002 + +#define NCP_PSERVER_SIGNATURE L"PS_" + +#define SWAP_OBJECT_ID(id) (id == NCP_WELL_KNOWN_SUPERVISOR_ID) ? \ + NCP_WELL_KNOWN_SUPERVISOR_ID_SWAPPED : \ + MAKELONG(LOWORD(id),SWAPWORD(HIWORD(id))) + + +UCHAR Table[] = +{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]; \ + } \ +} + +int +Scramble( + int iSeed, + UCHAR achBuffer[32] + ); + +VOID +Shuffle( + UCHAR *achObjectId, + UCHAR *szUpperPassword, + int iPasswordLen, + UCHAR *achOutputBuffer + ) + +/*++ + +Routine Description: + + This routine shuffles around the object ID with the password + +Arguments: + + IN achObjectId - Supplies the 4 byte user's bindery object id + + IN 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 + + IN iPasswordLen - length of uppercased password + + OUT achOutputBuffer - Returns the 8 byte sub-calculation + +Return Value: + + none. + +--*/ + +{ + 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. + + RtlCopyMemory( 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 + + RtlZeroMemory( achTemp, 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++) { + + achOutputBuffer[iOutputIndex] = + Table[achTemp[iOutputIndex << 1]] | + (Table[achTemp[(iOutputIndex << 1) + 1]] << 4); + } + + return; +} + +int +Scramble( + int iSeed, + UCHAR achBuffer[32] + ) + +/*++ + +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: + + IN iSeed + IN OUT achBuffer[32] + +Return Value: + + none. + +--*/ + +{ + 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; +} + +NTSTATUS +ReturnNetwareForm( + const char * pszSecretValue, + DWORD dwUserId, + const WCHAR * pchNWPassword, + UCHAR * pchEncryptedNWPassword + ) + +/*++ + +Routine Description: + + This routine takes the ObjectId and encrypts it with the user + supplied password to develop a credential for the intermediate form. + +Arguments: + DWORD dwUserId - Supplies the 4 byte user's object id + const WCHAR * pchNWPassword - Supplies the user's password + + UCHAR * pchEncryptedNWPassword - 16 characters where the result goes. + +Return Value: + + none. + +--*/ + +{ + DWORD dwStatus; + DWORD chObjectId = SWAP_OBJECT_ID (dwUserId); + UNICODE_STRING uniNWPassword; + OEM_STRING oemNWPassword; + + // + // shuffle actually uses 32 bytes, not just 16. It only returns 16 though. + // + + UCHAR pszShuffledNWPassword[NT_OWF_PASSWORD_LENGTH * 2]; + + uniNWPassword.Buffer = (WCHAR *) pchNWPassword; + uniNWPassword.Length = lstrlenW (pchNWPassword)*sizeof(WCHAR); + uniNWPassword.MaximumLength = uniNWPassword.Length; + + if ((dwStatus = RtlUpcaseUnicodeStringToOemString (&oemNWPassword, + &uniNWPassword, + TRUE)) == STATUS_SUCCESS) + { + Shuffle((UCHAR *) &chObjectId, oemNWPassword.Buffer, oemNWPassword.Length, pszShuffledNWPassword); + + // Encrypt with LSA secret. + dwStatus = RtlEncryptNtOwfPwdWithUserKey( + (PNT_OWF_PASSWORD) pszShuffledNWPassword, + (PUSER_SESSION_KEY) pszSecretValue, + (PENCRYPTED_NT_OWF_PASSWORD) pchEncryptedNWPassword); + } + + return (dwStatus); +} |