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.

314 lines
8.5 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. Andy Herron [AndyHe]
  14. Revision History:
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <nwsutil.h>
  21. #include <fpnwcomm.h>
  22. #include <usrprop.h>
  23. #include <crypt.h>
  24. UCHAR Table[] =
  25. {0x7,0x8,0x0,0x8,0x6,0x4,0xE,0x4,0x5,0xC,0x1,0x7,0xB,0xF,0xA,0x8,
  26. 0xF,0x8,0xC,0xC,0x9,0x4,0x1,0xE,0x4,0x6,0x2,0x4,0x0,0xA,0xB,0x9,
  27. 0x2,0xF,0xB,0x1,0xD,0x2,0x1,0x9,0x5,0xE,0x7,0x0,0x0,0x2,0x6,0x6,
  28. 0x0,0x7,0x3,0x8,0x2,0x9,0x3,0xF,0x7,0xF,0xC,0xF,0x6,0x4,0xA,0x0,
  29. 0x2,0x3,0xA,0xB,0xD,0x8,0x3,0xA,0x1,0x7,0xC,0xF,0x1,0x8,0x9,0xD,
  30. 0x9,0x1,0x9,0x4,0xE,0x4,0xC,0x5,0x5,0xC,0x8,0xB,0x2,0x3,0x9,0xE,
  31. 0x7,0x7,0x6,0x9,0xE,0xF,0xC,0x8,0xD,0x1,0xA,0x6,0xE,0xD,0x0,0x7,
  32. 0x7,0xA,0x0,0x1,0xF,0x5,0x4,0xB,0x7,0xB,0xE,0xC,0x9,0x5,0xD,0x1,
  33. 0xB,0xD,0x1,0x3,0x5,0xD,0xE,0x6,0x3,0x0,0xB,0xB,0xF,0x3,0x6,0x4,
  34. 0x9,0xD,0xA,0x3,0x1,0x4,0x9,0x4,0x8,0x3,0xB,0xE,0x5,0x0,0x5,0x2,
  35. 0xC,0xB,0xD,0x5,0xD,0x5,0xD,0x2,0xD,0x9,0xA,0xC,0xA,0x0,0xB,0x3,
  36. 0x5,0x3,0x6,0x9,0x5,0x1,0xE,0xE,0x0,0xE,0x8,0x2,0xD,0x2,0x2,0x0,
  37. 0x4,0xF,0x8,0x5,0x9,0x6,0x8,0x6,0xB,0xA,0xB,0xF,0x0,0x7,0x2,0x8,
  38. 0xC,0x7,0x3,0xA,0x1,0x4,0x2,0x5,0xF,0x7,0xA,0xC,0xE,0x5,0x9,0x3,
  39. 0xE,0x7,0x1,0x2,0xE,0x1,0xF,0x4,0xA,0x6,0xC,0x6,0xF,0x4,0x3,0x0,
  40. 0xC,0x0,0x3,0x6,0xF,0x8,0x7,0xB,0x2,0xD,0xC,0x6,0xA,0xA,0x8,0xD};
  41. UCHAR Keys[32] =
  42. {0x48,0x93,0x46,0x67,0x98,0x3D,0xE6,0x8D,
  43. 0xB7,0x10,0x7A,0x26,0x5A,0xB9,0xB1,0x35,
  44. 0x6B,0x0F,0xD5,0x70,0xAE,0xFB,0xAD,0x11,
  45. 0xF4,0x47,0xDC,0xA7,0xEC,0xCF,0x50,0xC0};
  46. #define XorArray( DEST, SRC ) { \
  47. PULONG D = (PULONG)DEST; \
  48. PULONG S = (PULONG)SRC; \
  49. int i; \
  50. for ( i = 0; i <= 7 ; i++ ) { \
  51. D[i] ^= S[i]; \
  52. } \
  53. }
  54. int
  55. Scramble(
  56. int iSeed,
  57. UCHAR achBuffer[32]
  58. );
  59. VOID
  60. Shuffle(
  61. UCHAR *achObjectId,
  62. UCHAR *szUpperPassword,
  63. int iPasswordLen,
  64. UCHAR *achOutputBuffer
  65. )
  66. /*++
  67. Routine Description:
  68. This routine shuffles around the object ID with the password
  69. Arguments:
  70. IN achObjectId - Supplies the 4 byte user's bindery object id
  71. IN szUpperPassword - Supplies the user's uppercased password on the
  72. first call to process the password. On the second and third calls
  73. this parameter contains the OutputBuffer from the first call
  74. IN iPasswordLen - length of uppercased password
  75. OUT achOutputBuffer - Returns the 8 byte sub-calculation
  76. Return Value:
  77. none.
  78. --*/
  79. {
  80. int iTempIndex;
  81. int iOutputIndex;
  82. UCHAR achTemp[32];
  83. //
  84. // Truncate all trailing zeros from the password.
  85. //
  86. while (iPasswordLen > 0 && szUpperPassword[iPasswordLen-1] == 0 ) {
  87. iPasswordLen--;
  88. }
  89. //
  90. // Initialize the achTemp buffer. Initialization consists of taking
  91. // the password and dividing it up into chunks of 32. Any bytes left
  92. // over are the remainder and do not go into the initialization.
  93. //
  94. // achTemp[0] = szUpperPassword[0] ^ szUpperPassword[32] ^ szUpper...
  95. // achTemp[1] = szUpperPassword[1] ^ szUpperPassword[33] ^ szUpper...
  96. // etc.
  97. //
  98. if ( iPasswordLen > 32) {
  99. // At least one chunk of 32. Set the buffer to the first chunk.
  100. RtlCopyMemory( achTemp, szUpperPassword, 32 );
  101. szUpperPassword +=32; // Remove the first chunk
  102. iPasswordLen -=32;
  103. while ( iPasswordLen >= 32 ) {
  104. //
  105. // Xor this chunk with the characters already loaded into
  106. // achTemp.
  107. //
  108. XorArray( achTemp, szUpperPassword);
  109. szUpperPassword +=32; // Remove this chunk
  110. iPasswordLen -=32;
  111. }
  112. } else {
  113. // No chunks of 32 so set the buffer to zero's
  114. RtlZeroMemory( achTemp, sizeof(achTemp));
  115. }
  116. //
  117. // achTemp is now initialized. Load the remainder into achTemp.
  118. // The remainder is repeated to fill achTemp.
  119. //
  120. // The corresponding character from Keys is taken to seperate
  121. // each repitition.
  122. //
  123. // As an example, take the remainder "ABCDEFG". The remainder is expanded
  124. // to "ABCDEFGwABCDEFGxABCDEFGyABCDEFGz" where w is Keys[7],
  125. // x is Keys[15], y is Keys[23] and z is Keys[31].
  126. //
  127. //
  128. if (iPasswordLen > 0) {
  129. int iPasswordOffset = 0;
  130. for (iTempIndex = 0; iTempIndex < 32; iTempIndex++) {
  131. if (iPasswordLen == iPasswordOffset) {
  132. iPasswordOffset = 0;
  133. achTemp[iTempIndex] ^= Keys[iTempIndex];
  134. } else {
  135. achTemp[iTempIndex] ^= szUpperPassword[iPasswordOffset++];
  136. }
  137. }
  138. }
  139. //
  140. // achTemp has been loaded with the users password packed into 32
  141. // bytes. Now take the objectid that came from the server and use
  142. // that to munge every byte in achTemp.
  143. //
  144. for (iTempIndex = 0; iTempIndex < 32; iTempIndex++)
  145. achTemp[iTempIndex] ^= achObjectId[ iTempIndex & 3];
  146. Scramble( Scramble( 0, achTemp ), achTemp );
  147. //
  148. // Finally take pairs of bytes in achTemp and return the two
  149. // nibbles obtained from Table. The pairs of bytes used
  150. // are achTemp[n] and achTemp[n+16].
  151. //
  152. for (iOutputIndex = 0; iOutputIndex < 16; iOutputIndex++) {
  153. achOutputBuffer[iOutputIndex] =
  154. Table[achTemp[iOutputIndex << 1]] |
  155. (Table[achTemp[(iOutputIndex << 1) + 1]] << 4);
  156. }
  157. return;
  158. }
  159. int
  160. Scramble(
  161. int iSeed,
  162. UCHAR achBuffer[32]
  163. )
  164. /*++
  165. Routine Description:
  166. This routine scrambles around the contents of the buffer. Each buffer
  167. position is updated to include the contents of at least two character
  168. positions plus an EncryptKey value. The buffer is processed left to right
  169. and so if a character position chooses to merge with a buffer position
  170. to its left then this buffer position will include bits derived from at
  171. least 3 bytes of the original buffer contents.
  172. Arguments:
  173. IN iSeed
  174. IN OUT achBuffer[32]
  175. Return Value:
  176. none.
  177. --*/
  178. {
  179. int iBufferIndex;
  180. for (iBufferIndex = 0; iBufferIndex < 32; iBufferIndex++) {
  181. achBuffer[iBufferIndex] =
  182. (UCHAR)(
  183. ((UCHAR)(achBuffer[iBufferIndex] + iSeed)) ^
  184. ((UCHAR)( achBuffer[(iBufferIndex+iSeed) & 31] -
  185. Keys[iBufferIndex] )));
  186. iSeed += achBuffer[iBufferIndex];
  187. }
  188. return iSeed;
  189. }
  190. NTSTATUS
  191. ReturnNetwareForm(
  192. const char * pszSecretValue,
  193. DWORD dwUserId,
  194. const WCHAR * pchNWPassword,
  195. UCHAR * pchEncryptedNWPassword
  196. )
  197. /*++
  198. Routine Description:
  199. This routine takes the ObjectId and encrypts it with the user
  200. supplied password to develop a credential for the intermediate form.
  201. Arguments:
  202. DWORD dwUserId - Supplies the 4 byte user's object id
  203. const WCHAR * pchNWPassword - Supplies the user's password
  204. UCHAR * pchEncryptedNWPassword - 16 characters where the result goes.
  205. Return Value:
  206. none.
  207. --*/
  208. {
  209. DWORD dwStatus;
  210. DWORD chObjectId = SWAP_OBJECT_ID (dwUserId);
  211. UNICODE_STRING uniNWPassword;
  212. OEM_STRING oemNWPassword;
  213. //
  214. // shuffle actually uses 32 bytes, not just 16. It only returns 16 though.
  215. //
  216. UCHAR pszShuffledNWPassword[NT_OWF_PASSWORD_LENGTH * 2];
  217. uniNWPassword.Buffer = (WCHAR *) pchNWPassword;
  218. uniNWPassword.Length = (USHORT)(lstrlenW (pchNWPassword)*sizeof(WCHAR));
  219. uniNWPassword.MaximumLength = uniNWPassword.Length;
  220. if ((dwStatus = RtlUpcaseUnicodeStringToOemString (&oemNWPassword,
  221. &uniNWPassword,
  222. TRUE)) == STATUS_SUCCESS)
  223. {
  224. Shuffle((UCHAR *) &chObjectId, oemNWPassword.Buffer, oemNWPassword.Length, pszShuffledNWPassword);
  225. // Encrypt with LSA secret.
  226. dwStatus = RtlEncryptNtOwfPwdWithUserKey(
  227. (PNT_OWF_PASSWORD) pszShuffledNWPassword,
  228. (PUSER_SESSION_KEY) pszSecretValue,
  229. (PENCRYPTED_NT_OWF_PASSWORD) pchEncryptedNWPassword);
  230. }
  231. return (dwStatus);
  232. }