Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
8.1 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. encrypt.c
  5. Abstract:
  6. This module implements the routines for the NetWare
  7. redirector to mangle an objectid, challenge key and
  8. password such that a NetWare server will accept the
  9. password as valid.
  10. This program uses information published in Byte Magazine.
  11. Author:
  12. Colin Watson [ColinW] 15-Mar-1993
  13. Revision History:
  14. --*/
  15. #include <procs.h>
  16. UCHAR Table[] = {
  17. 0x78, 0x08, 0x64, 0xe4, 0x5c, 0x17, 0xbf, 0xa8,
  18. 0xf8, 0xcc, 0x94, 0x1e, 0x46, 0x24, 0x0a, 0xb9,
  19. 0x2f, 0xb1, 0xd2, 0x19, 0x5e, 0x70, 0x02, 0x66,
  20. 0x07, 0x38, 0x29, 0x3f, 0x7f, 0xcf, 0x64, 0xa0,
  21. 0x23, 0xab, 0xd8, 0x3a, 0x17, 0xcf, 0x18, 0x9d,
  22. 0x91, 0x94, 0xe4, 0xc5, 0x5c, 0x8b, 0x23, 0x9e,
  23. 0x77, 0x69, 0xef, 0xc8, 0xd1, 0xa6, 0xed, 0x07,
  24. 0x7a, 0x01, 0xf5, 0x4b, 0x7b, 0xec, 0x95, 0xd1,
  25. 0xbd, 0x13, 0x5d, 0xe6, 0x30, 0xbb, 0xf3, 0x64,
  26. 0x9d, 0xa3, 0x14, 0x94, 0x83, 0xbe, 0x50, 0x52,
  27. 0xcb, 0xd5, 0xd5, 0xd2, 0xd9, 0xac, 0xa0, 0xb3,
  28. 0x53, 0x69, 0x51, 0xee, 0x0e, 0x82, 0xd2, 0x20,
  29. 0x4f, 0x85, 0x96, 0x86, 0xba, 0xbf, 0x07, 0x28,
  30. 0xc7, 0x3a, 0x14, 0x25, 0xf7, 0xac, 0xe5, 0x93,
  31. 0xe7, 0x12, 0xe1, 0xf4, 0xa6, 0xc6, 0xf4, 0x30,
  32. 0xc0, 0x36, 0xf8, 0x7b, 0x2d, 0xc6, 0xaa, 0x8d } ;
  33. UCHAR Keys[32] =
  34. {0x48,0x93,0x46,0x67,0x98,0x3D,0xE6,0x8D,
  35. 0xB7,0x10,0x7A,0x26,0x5A,0xB9,0xB1,0x35,
  36. 0x6B,0x0F,0xD5,0x70,0xAE,0xFB,0xAD,0x11,
  37. 0xF4,0x47,0xDC,0xA7,0xEC,0xCF,0x50,0xC0};
  38. #define XorArray( DEST, SRC ) { \
  39. PULONG D = (PULONG)DEST; \
  40. PULONG S = (PULONG)SRC; \
  41. int i; \
  42. for ( i = 0; i <= 7 ; i++ ) { \
  43. D[i] ^= S[i]; \
  44. } \
  45. }
  46. VOID
  47. Shuffle(
  48. UCHAR *achObjectId,
  49. UCHAR *szUpperPassword,
  50. int iPasswordLen,
  51. UCHAR *achOutputBuffer
  52. );
  53. int
  54. Scramble(
  55. int iSeed,
  56. UCHAR achBuffer[32]
  57. );
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text( PAGE, RespondToChallenge )
  60. #pragma alloc_text( PAGE, Shuffle )
  61. #pragma alloc_text( PAGE, Scramble )
  62. #endif
  63. VOID
  64. RespondToChallenge(
  65. IN PUCHAR achObjectId,
  66. IN POEM_STRING Password,
  67. IN PUCHAR pChallenge,
  68. OUT PUCHAR pResponse
  69. )
  70. /*++
  71. Routine Description:
  72. This routine takes the ObjectId and Challenge key from the server and
  73. encrypts the user supplied password to develop a credential for the
  74. server to verify.
  75. Arguments:
  76. IN PUCHAR achObjectId - Supplies the 4 byte user's bindery object id
  77. IN POEM_STRING Password - Supplies the user's uppercased password
  78. IN PUCHAR pChallenge - Supplies the 8 byte challenge key
  79. OUT PUCHAR pResponse - Returns the 8 byte response
  80. Return Value:
  81. none.
  82. --*/
  83. {
  84. int index;
  85. UCHAR achK[32];
  86. UCHAR achBuf[32];
  87. PAGED_CODE();
  88. Shuffle(achObjectId, Password->Buffer, Password->Length, achBuf);
  89. Shuffle( &pChallenge[0], achBuf, 16, &achK[0] );
  90. Shuffle( &pChallenge[4], achBuf, 16, &achK[16] );
  91. for (index = 0; index < 16; index++)
  92. achK[index] ^= achK[31-index];
  93. for (index = 0; index < 8; index++)
  94. pResponse[index] = achK[index] ^ achK[15-index];
  95. }
  96. VOID
  97. Shuffle(
  98. UCHAR *achObjectId,
  99. UCHAR *szUpperPassword,
  100. int iPasswordLen,
  101. UCHAR *achOutputBuffer
  102. )
  103. /*++
  104. Routine Description:
  105. This routine shuffles around the object ID with the password
  106. Arguments:
  107. IN achObjectId - Supplies the 4 byte user's bindery object id
  108. IN szUpperPassword - Supplies the user's uppercased password on the
  109. first call to process the password. On the second and third calls
  110. this parameter contains the OutputBuffer from the first call
  111. IN iPasswordLen - length of uppercased password
  112. OUT achOutputBuffer - Returns the 8 byte sub-calculation
  113. Return Value:
  114. none.
  115. --*/
  116. {
  117. int iTempIndex;
  118. int iOutputIndex;
  119. UCHAR achTemp[32];
  120. PAGED_CODE();
  121. //
  122. // Truncate all trailing zeros from the password.
  123. //
  124. while (iPasswordLen > 0 && szUpperPassword[iPasswordLen-1] == 0 ) {
  125. iPasswordLen--;
  126. }
  127. //
  128. // Initialize the achTemp buffer. Initialization consists of taking
  129. // the password and dividing it up into chunks of 32. Any bytes left
  130. // over are the remainder and do not go into the initialization.
  131. //
  132. // achTemp[0] = szUpperPassword[0] ^ szUpperPassword[32] ^ szUpper...
  133. // achTemp[1] = szUpperPassword[1] ^ szUpperPassword[33] ^ szUpper...
  134. // etc.
  135. //
  136. if ( iPasswordLen > 32) {
  137. // At least one chunk of 32. Set the buffer to the first chunk.
  138. RtlCopyMemory( achTemp, szUpperPassword, 32 );
  139. szUpperPassword +=32; // Remove the first chunk
  140. iPasswordLen -=32;
  141. while ( iPasswordLen >= 32 ) {
  142. //
  143. // Xor this chunk with the characters already loaded into
  144. // achTemp.
  145. //
  146. XorArray( achTemp, szUpperPassword);
  147. szUpperPassword +=32; // Remove this chunk
  148. iPasswordLen -=32;
  149. }
  150. } else {
  151. // No chunks of 32 so set the buffer to zero's
  152. RtlZeroMemory( achTemp, sizeof(achTemp));
  153. }
  154. //
  155. // achTemp is now initialized. Load the remainder into achTemp.
  156. // The remainder is repeated to fill achTemp.
  157. //
  158. // The corresponding character from Keys is taken to seperate
  159. // each repitition.
  160. //
  161. // As an example, take the remainder "ABCDEFG". The remainder is expanded
  162. // to "ABCDEFGwABCDEFGxABCDEFGyABCDEFGz" where w is Keys[7],
  163. // x is Keys[15], y is Keys[23] and z is Keys[31].
  164. //
  165. //
  166. if (iPasswordLen > 0) {
  167. int iPasswordOffset = 0;
  168. for (iTempIndex = 0; iTempIndex < 32; iTempIndex++) {
  169. if (iPasswordLen == iPasswordOffset) {
  170. iPasswordOffset = 0;
  171. achTemp[iTempIndex] ^= Keys[iTempIndex];
  172. } else {
  173. achTemp[iTempIndex] ^= szUpperPassword[iPasswordOffset++];
  174. }
  175. }
  176. }
  177. //
  178. // achTemp has been loaded with the users password packed into 32
  179. // bytes. Now take the objectid that came from the server and use
  180. // that to munge every byte in achTemp.
  181. //
  182. for (iTempIndex = 0; iTempIndex < 32; iTempIndex++)
  183. achTemp[iTempIndex] ^= achObjectId[ iTempIndex & 3];
  184. Scramble( Scramble( 0, achTemp ), achTemp );
  185. //
  186. // Finally take pairs of bytes in achTemp and return the two
  187. // nibbles obtained from Table. The pairs of bytes used
  188. // are achTemp[n] and achTemp[n+16].
  189. //
  190. for (iOutputIndex = 0; iOutputIndex < 16; iOutputIndex++) {
  191. unsigned int offset = achTemp[iOutputIndex << 1],
  192. shift = (offset & 0x1) ? 0 : 4 ;
  193. achOutputBuffer[iOutputIndex] =
  194. (Table[offset >> 1] >> shift) & 0xF ;
  195. offset = achTemp[(iOutputIndex << 1)+1],
  196. shift = (offset & 0x1) ? 4 : 0 ;
  197. achOutputBuffer[iOutputIndex] |=
  198. (Table[offset >> 1] << shift) & 0xF0;
  199. }
  200. return;
  201. }
  202. int
  203. Scramble(
  204. int iSeed,
  205. UCHAR achBuffer[32]
  206. )
  207. /*++
  208. Routine Description:
  209. This routine scrambles around the contents of the buffer. Each buffer
  210. position is updated to include the contents of at least two character
  211. positions plus an EncryptKey value. The buffer is processed left to right
  212. and so if a character position chooses to merge with a buffer position
  213. to its left then this buffer position will include bits derived from at
  214. least 3 bytes of the original buffer contents.
  215. Arguments:
  216. IN iSeed
  217. IN OUT achBuffer[32]
  218. Return Value:
  219. none.
  220. --*/
  221. {
  222. int iBufferIndex;
  223. PAGED_CODE();
  224. for (iBufferIndex = 0; iBufferIndex < 32; iBufferIndex++) {
  225. achBuffer[iBufferIndex] =
  226. (UCHAR)(
  227. ((UCHAR)(achBuffer[iBufferIndex] + iSeed)) ^
  228. ((UCHAR)( achBuffer[(iBufferIndex+iSeed) & 31] -
  229. Keys[iBufferIndex] )));
  230. iSeed += achBuffer[iBufferIndex];
  231. }
  232. return iSeed;
  233. }
  234.