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.

781 lines
20 KiB

  1. /*++
  2. Copyright (c) 1994 Micro Computer Systems, Inc.
  3. Module Name:
  4. nwlibs\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. Shawn Walker (v-swalk) 10-10-1994
  13. Revision History:
  14. 11-9-1994 Copied from nwslib for login and minimars for
  15. change password.
  16. 09-7-1995 (AndyHe) Put in proper setpass compatible processing
  17. --*/
  18. #include "dswarn.h"
  19. #include <windef.h>
  20. #include "encrypt.h"
  21. #include <oledsdbg.h>
  22. #define STATIC
  23. #define STRLEN strlen
  24. #define STRUPR _strupr
  25. #define NUM_NYBBLES 34
  26. STATIC
  27. VOID
  28. RespondToChallengePart1(
  29. IN PUCHAR pObjectId,
  30. IN PUCHAR pPassword,
  31. OUT PUCHAR pResponse
  32. );
  33. STATIC
  34. VOID
  35. RespondToChallengePart2(
  36. IN PUCHAR pResponsePart1,
  37. IN PUCHAR pChallenge,
  38. OUT PUCHAR pResponse
  39. );
  40. STATIC
  41. VOID
  42. Shuffle(
  43. UCHAR *achObjectId,
  44. UCHAR *szUpperPassword,
  45. int iPasswordLen,
  46. UCHAR *achOutputBuffer,
  47. UCHAR ChangePassword
  48. );
  49. STATIC
  50. int
  51. Scramble(
  52. int iSeed,
  53. UCHAR achBuffer[32]
  54. );
  55. STATIC
  56. VOID
  57. ExpandBytes(
  58. IN PUCHAR InArray,
  59. OUT PUCHAR OutArray
  60. );
  61. STATIC
  62. VOID
  63. CompressBytes(
  64. IN PUCHAR InArray,
  65. OUT PUCHAR OutArray
  66. );
  67. VOID
  68. CalculateWireFromOldAndNewPasswords(
  69. UCHAR *Vold,
  70. UCHAR *Vnew,
  71. UCHAR *Vc
  72. );
  73. /*++
  74. *******************************************************************
  75. EncryptLoginPassword
  76. Routine Description:
  77. Encrypts the password for login.
  78. Arguments:
  79. pPassword = The pointer to a plain text null terminated password.
  80. ObjectId = The object id of the user to encrypt the password.
  81. pLogKey = The pointer to key to use to encrpyt the password.
  82. pEncryptedPassword = The pointer to return a 8 byte encrypted
  83. password.
  84. Return Value:
  85. None.
  86. *******************************************************************
  87. --*/
  88. void
  89. EncryptLoginPassword(
  90. unsigned char *pPassword,
  91. unsigned long ObjectId,
  92. unsigned char *pLogKey,
  93. unsigned char *pEncryptedPassword
  94. )
  95. {
  96. INT Index;
  97. UCHAR achK[32];
  98. UCHAR achBuf[32];
  99. ADsAssert(pPassword);
  100. /** The password must be upper case **/
  101. pPassword = STRUPR(pPassword);
  102. /** Encrypt the password **/
  103. Shuffle((UCHAR *) &ObjectId, pPassword, STRLEN(pPassword), achBuf, FALSE);
  104. Shuffle((UCHAR *) &pLogKey[0], achBuf, 16, &achK[0], FALSE);
  105. Shuffle((UCHAR *) &pLogKey[4], achBuf, 16, &achK[16], FALSE);
  106. for (Index = 0; Index < 16; Index++) {
  107. achK[Index] ^= achK[31 - Index];
  108. }
  109. for (Index = 0; Index < 8; Index++) {
  110. pEncryptedPassword[Index] = achK[Index] ^ achK[15 - Index];
  111. }
  112. return;
  113. }
  114. /*++
  115. *******************************************************************
  116. EncryptChangePassword
  117. Routine Description:
  118. This function encrypts for change passwords.
  119. Arguments:
  120. pOldPassword = The pointer to the old password.
  121. pNewPassword = The pointer to the new password.
  122. ObjectId = The object id to use to encrypt the password.
  123. pKey = The challenge key from the server.
  124. pValidationKey = The 8 byte validation key to return.
  125. pEncryptNewPassword = The 17 byte encrypted new password to
  126. return.
  127. Return Value:
  128. None.
  129. *******************************************************************
  130. --*/
  131. VOID
  132. EncryptChangePassword(
  133. IN PUCHAR pOldPassword,
  134. IN PUCHAR pNewPassword,
  135. IN ULONG ObjectId,
  136. IN PUCHAR pKey,
  137. OUT PUCHAR pValidationKey,
  138. OUT PUCHAR pEncryptNewPassword
  139. )
  140. {
  141. UCHAR Vc[17];
  142. UCHAR Vold[17];
  143. UCHAR Vnew[17];
  144. UCHAR ValidationKey[16];
  145. UCHAR VcTemp[NUM_NYBBLES];
  146. UCHAR VoldTemp[NUM_NYBBLES];
  147. UCHAR VnewTemp[NUM_NYBBLES];
  148. ADsAssert(pOldPassword);
  149. ADsAssert(pNewPassword);
  150. /** Uppercase the passwords **/
  151. pOldPassword = STRUPR(pOldPassword);
  152. pNewPassword = STRUPR(pNewPassword);
  153. //
  154. // The old password and object ID make up the 17-byte Vold.
  155. // This is used later to form the 17-byte Vc for changing
  156. // password on the server.
  157. //
  158. Shuffle((PUCHAR) &ObjectId, pOldPassword, STRLEN(pOldPassword), Vold, FALSE);
  159. //
  160. // Need to make an 8-byte key which includes the old password
  161. // The server validates this value before allowing the user to
  162. // set password.
  163. //
  164. RespondToChallengePart2(Vold, pKey, ValidationKey);
  165. //
  166. // Now determine Vold using the Change PW table rather than verify pw table
  167. //
  168. Shuffle((PUCHAR) &ObjectId, pOldPassword, STRLEN(pOldPassword), Vold, TRUE);
  169. //
  170. // The new password and object ID make up the 17-byte Vnew.
  171. //
  172. RespondToChallengePart1((PUCHAR) &ObjectId, pNewPassword, Vnew);
  173. //
  174. // Expand the 17-byte Vold and Vnew arrays into 34-byte arrays
  175. // for easy munging.
  176. //
  177. ExpandBytes(Vold, VoldTemp);
  178. ExpandBytes(Vnew, VnewTemp);
  179. //
  180. // leave first two bytes of VcTemp free... we slap in the value based
  181. // on new password length in below.
  182. //
  183. CalculateWireFromOldAndNewPasswords( VoldTemp, VnewTemp, &VcTemp[2] );
  184. //
  185. // Compress 34-byte array of nibbles into 17-byte array of bytes.
  186. //
  187. CompressBytes(VcTemp, Vc);
  188. //
  189. // Calculate the 1st byte of Vc as a function of the new password length
  190. // and the old password residue.
  191. //
  192. Vc[0] = ( ( ( Vold[0] ^ Vold[1] ) & 0x7F ) | 0x40 ) ^ STRLEN(pNewPassword);
  193. memcpy(pValidationKey, ValidationKey, 8);
  194. memcpy(pEncryptNewPassword, Vc, 17);
  195. return;
  196. }
  197. /*++
  198. *******************************************************************
  199. Encryption table.
  200. *******************************************************************
  201. --*/
  202. //
  203. // This is the same as LoginTable, just in a slightly different format.
  204. //
  205. UCHAR ChangeTable[] = {
  206. 0x78, 0x08, 0x64, 0xe4, 0x5c, 0x17, 0xbf, 0xa8,
  207. 0xf8, 0xcc, 0x94, 0x1e, 0x46, 0x24, 0x0a, 0xb9,
  208. 0x2f, 0xb1, 0xd2, 0x19, 0x5e, 0x70, 0x02, 0x66,
  209. 0x07, 0x38, 0x29, 0x3f, 0x7f, 0xcf, 0x64, 0xa0,
  210. 0x23, 0xab, 0xd8, 0x3a, 0x17, 0xcf, 0x18, 0x9d,
  211. 0x91, 0x94, 0xe4, 0xc5, 0x5c, 0x8b, 0x23, 0x9e,
  212. 0x77, 0x69, 0xef, 0xc8, 0xd1, 0xa6, 0xed, 0x07,
  213. 0x7a, 0x01, 0xf5, 0x4b, 0x7b, 0xec, 0x95, 0xd1,
  214. 0xbd, 0x13, 0x5d, 0xe6, 0x30, 0xbb, 0xf3, 0x64,
  215. 0x9d, 0xa3, 0x14, 0x94, 0x83, 0xbe, 0x50, 0x52,
  216. 0xcb, 0xd5, 0xd5, 0xd2, 0xd9, 0xac, 0xa0, 0xb3,
  217. 0x53, 0x69, 0x51, 0xee, 0x0e, 0x82, 0xd2, 0x20,
  218. 0x4f, 0x85, 0x96, 0x86, 0xba, 0xbf, 0x07, 0x28,
  219. 0xc7, 0x3a, 0x14, 0x25, 0xf7, 0xac, 0xe5, 0x93,
  220. 0xe7, 0x12, 0xe1, 0xf4, 0xa6, 0xc6, 0xf4, 0x30,
  221. 0xc0, 0x36, 0xf8, 0x7b, 0x2d, 0xc6, 0xaa, 0x8d
  222. };
  223. UCHAR LoginTable[] = {
  224. 0x7,0x8,0x0,0x8,0x6,0x4,0xE,0x4,0x5,0xC,0x1,0x7,0xB,0xF,0xA,0x8,
  225. 0xF,0x8,0xC,0xC,0x9,0x4,0x1,0xE,0x4,0x6,0x2,0x4,0x0,0xA,0xB,0x9,
  226. 0x2,0xF,0xB,0x1,0xD,0x2,0x1,0x9,0x5,0xE,0x7,0x0,0x0,0x2,0x6,0x6,
  227. 0x0,0x7,0x3,0x8,0x2,0x9,0x3,0xF,0x7,0xF,0xC,0xF,0x6,0x4,0xA,0x0,
  228. 0x2,0x3,0xA,0xB,0xD,0x8,0x3,0xA,0x1,0x7,0xC,0xF,0x1,0x8,0x9,0xD,
  229. 0x9,0x1,0x9,0x4,0xE,0x4,0xC,0x5,0x5,0xC,0x8,0xB,0x2,0x3,0x9,0xE,
  230. 0x7,0x7,0x6,0x9,0xE,0xF,0xC,0x8,0xD,0x1,0xA,0x6,0xE,0xD,0x0,0x7,
  231. 0x7,0xA,0x0,0x1,0xF,0x5,0x4,0xB,0x7,0xB,0xE,0xC,0x9,0x5,0xD,0x1,
  232. 0xB,0xD,0x1,0x3,0x5,0xD,0xE,0x6,0x3,0x0,0xB,0xB,0xF,0x3,0x6,0x4,
  233. 0x9,0xD,0xA,0x3,0x1,0x4,0x9,0x4,0x8,0x3,0xB,0xE,0x5,0x0,0x5,0x2,
  234. 0xC,0xB,0xD,0x5,0xD,0x5,0xD,0x2,0xD,0x9,0xA,0xC,0xA,0x0,0xB,0x3,
  235. 0x5,0x3,0x6,0x9,0x5,0x1,0xE,0xE,0x0,0xE,0x8,0x2,0xD,0x2,0x2,0x0,
  236. 0x4,0xF,0x8,0x5,0x9,0x6,0x8,0x6,0xB,0xA,0xB,0xF,0x0,0x7,0x2,0x8,
  237. 0xC,0x7,0x3,0xA,0x1,0x4,0x2,0x5,0xF,0x7,0xA,0xC,0xE,0x5,0x9,0x3,
  238. 0xE,0x7,0x1,0x2,0xE,0x1,0xF,0x4,0xA,0x6,0xC,0x6,0xF,0x4,0x3,0x0,
  239. 0xC,0x0,0x3,0x6,0xF,0x8,0x7,0xB,0x2,0xD,0xC,0x6,0xA,0xA,0x8,0xD
  240. };
  241. UCHAR Keys[32] = {
  242. 0x48,0x93,0x46,0x67,0x98,0x3D,0xE6,0x8D,
  243. 0xB7,0x10,0x7A,0x26,0x5A,0xB9,0xB1,0x35,
  244. 0x6B,0x0F,0xD5,0x70,0xAE,0xFB,0xAD,0x11,
  245. 0xF4,0x47,0xDC,0xA7,0xEC,0xCF,0x50,0xC0
  246. };
  247. #define XorArray( DEST, SRC ) { \
  248. PULONG D = (PULONG)DEST; \
  249. PULONG S = (PULONG)SRC; \
  250. int i; \
  251. for ( i = 0; i <= 7 ; i++ ) { \
  252. D[i] ^= S[i]; \
  253. } \
  254. }
  255. /*++
  256. *******************************************************************
  257. RespondToChallengePart1
  258. Routine Description:
  259. This routine takes the ObjectId and Challenge key from the server
  260. and encrypts the user supplied password to develop a credential
  261. for the server to verify.
  262. Arguments:
  263. pObjectId - Supplies the 4 byte user's bindery object id
  264. pPassword - Supplies the user's uppercased password
  265. pChallenge - Supplies the 8 byte challenge key
  266. pResponse - Returns the 16 byte response held by the server
  267. Return Value:
  268. None.
  269. *******************************************************************
  270. --*/
  271. STATIC
  272. VOID
  273. RespondToChallengePart1(
  274. IN PUCHAR pObjectId,
  275. IN PUCHAR pPassword,
  276. OUT PUCHAR pResponse
  277. )
  278. {
  279. UCHAR achBuf[32];
  280. Shuffle(pObjectId, pPassword, STRLEN(pPassword), achBuf, TRUE);
  281. memcpy(pResponse, achBuf, 17);
  282. return;
  283. }
  284. /*++
  285. *******************************************************************
  286. RespondToChallengePart2
  287. Routine Description:
  288. This routine takes the result of Shuffling the ObjectId and
  289. the Password and processes it with a challenge key.
  290. Arguments:
  291. pResponsePart1 - Supplies the 16 byte output of
  292. RespondToChallengePart1.
  293. pChallenge - Supplies the 8 byte challenge key
  294. pResponse - Returns the 8 byte response
  295. Return Value:
  296. None.
  297. *******************************************************************
  298. --*/
  299. STATIC
  300. VOID
  301. RespondToChallengePart2(
  302. IN PUCHAR pResponsePart1,
  303. IN PUCHAR pChallenge,
  304. OUT PUCHAR pResponse
  305. )
  306. {
  307. int index;
  308. UCHAR achK[32];
  309. Shuffle( &pChallenge[0], pResponsePart1, 16, &achK[0], TRUE);
  310. Shuffle( &pChallenge[4], pResponsePart1, 16, &achK[16], TRUE);
  311. for (index = 0; index < 16; index++) {
  312. achK[index] ^= achK[31-index];
  313. }
  314. for (index = 0; index < 8; index++) {
  315. pResponse[index] = achK[index] ^ achK[15-index];
  316. }
  317. return;
  318. }
  319. /*++
  320. *******************************************************************
  321. Shuffle
  322. Routine Description:
  323. This routine shuffles around the object ID with the password
  324. Arguments:
  325. achObjectId - Supplies the 4 byte user's bindery object id
  326. szUpperPassword - Supplies the user's uppercased password on the
  327. first call to process the password. On the
  328. second and third calls this parameter contains
  329. the OutputBuffer from the first call
  330. iPasswordLen - length of uppercased password
  331. achOutputBuffer - Returns the 8 byte sub-calculation
  332. Return Value:
  333. None.
  334. *******************************************************************
  335. --*/
  336. STATIC
  337. VOID
  338. Shuffle(
  339. UCHAR *achObjectId,
  340. UCHAR *szUpperPassword,
  341. int iPasswordLen,
  342. UCHAR *achOutputBuffer,
  343. UCHAR ChangePassword
  344. )
  345. {
  346. int iTempIndex;
  347. int iOutputIndex;
  348. UCHAR achTemp[32];
  349. //
  350. // Truncate all trailing zeros from the password.
  351. //
  352. while (iPasswordLen > 0 && szUpperPassword[iPasswordLen-1] == 0 ) {
  353. iPasswordLen--;
  354. }
  355. //
  356. // Initialize the achTemp buffer. Initialization consists of taking
  357. // the password and dividing it up into chunks of 32. Any bytes left
  358. // over are the remainder and do not go into the initialization.
  359. //
  360. // achTemp[0] = szUpperPassword[0] ^ szUpperPassword[32] ^ szUpper...
  361. // achTemp[1] = szUpperPassword[1] ^ szUpperPassword[33] ^ szUpper...
  362. // etc.
  363. //
  364. if ( iPasswordLen > 32) {
  365. // At least one chunk of 32. Set the buffer to the first chunk.
  366. memcpy( achTemp, szUpperPassword, 32 );
  367. szUpperPassword += 32; // Remove the first chunk
  368. iPasswordLen -= 32;
  369. while ( iPasswordLen >= 32 ) {
  370. //
  371. // Xor this chunk with the characters already loaded into
  372. // achTemp.
  373. //
  374. XorArray( achTemp, szUpperPassword);
  375. szUpperPassword += 32; // Remove this chunk
  376. iPasswordLen -= 32;
  377. }
  378. } else {
  379. // No chunks of 32 so set the buffer to zero's
  380. memset( achTemp, 0, sizeof(achTemp));
  381. }
  382. //
  383. // achTemp is now initialized. Load the remainder into achTemp.
  384. // The remainder is repeated to fill achTemp.
  385. //
  386. // The corresponding character from Keys is taken to seperate
  387. // each repitition.
  388. //
  389. // As an example, take the remainder "ABCDEFG". The remainder is expanded
  390. // to "ABCDEFGwABCDEFGxABCDEFGyABCDEFGz" where w is Keys[7],
  391. // x is Keys[15], y is Keys[23] and z is Keys[31].
  392. //
  393. //
  394. if (iPasswordLen > 0) {
  395. int iPasswordOffset = 0;
  396. for (iTempIndex = 0; iTempIndex < 32; iTempIndex++) {
  397. if (iPasswordLen == iPasswordOffset) {
  398. iPasswordOffset = 0;
  399. achTemp[iTempIndex] ^= Keys[iTempIndex];
  400. } else {
  401. achTemp[iTempIndex] ^= szUpperPassword[iPasswordOffset++];
  402. }
  403. }
  404. }
  405. //
  406. // achTemp has been loaded with the users password packed into 32
  407. // bytes. Now take the objectid that came from the server and use
  408. // that to munge every byte in achTemp.
  409. //
  410. for (iTempIndex = 0; iTempIndex < 32; iTempIndex++)
  411. achTemp[iTempIndex] ^= achObjectId[ iTempIndex & 3];
  412. Scramble( Scramble( 0, achTemp ), achTemp );
  413. //
  414. // Finally take pairs of bytes in achTemp and return the two
  415. // nibbles obtained from Table. The pairs of bytes used
  416. // are achTemp[n] and achTemp[n+16].
  417. //
  418. for (iOutputIndex = 0; iOutputIndex < 16; iOutputIndex++) {
  419. if (ChangePassword) {
  420. unsigned int offset = achTemp[iOutputIndex << 1],
  421. shift = (offset & 0x1) ? 0 : 4 ;
  422. achOutputBuffer[iOutputIndex] =
  423. (ChangeTable[offset >> 1] >> shift) & 0xF ;
  424. offset = achTemp[(iOutputIndex << 1)+1],
  425. shift = (offset & 0x1) ? 4 : 0 ;
  426. achOutputBuffer[iOutputIndex] |=
  427. (ChangeTable[offset >> 1] << shift) & 0xF0;
  428. } else {
  429. achOutputBuffer[iOutputIndex] =
  430. LoginTable[achTemp[iOutputIndex << 1]] |
  431. (LoginTable[achTemp[(iOutputIndex << 1) + 1]] << 4);
  432. }
  433. }
  434. return;
  435. }
  436. /*++
  437. *******************************************************************
  438. Scramble
  439. Routine Description:
  440. This routine scrambles around the contents of the buffer. Each
  441. buffer position is updated to include the contents of at least
  442. two character positions plus an EncryptKey value. The buffer
  443. is processed left to right and so if a character position chooses
  444. to merge with a buffer position to its left then this buffer
  445. position will include bits derived from at least 3 bytes of
  446. the original buffer contents.
  447. Arguments:
  448. iSeed =
  449. achBuffer =
  450. Return Value:
  451. None.
  452. *******************************************************************
  453. --*/
  454. STATIC
  455. int
  456. Scramble(
  457. int iSeed,
  458. UCHAR achBuffer[32]
  459. )
  460. {
  461. int iBufferIndex;
  462. for (iBufferIndex = 0; iBufferIndex < 32; iBufferIndex++) {
  463. achBuffer[iBufferIndex] =
  464. (UCHAR)(
  465. ((UCHAR)(achBuffer[iBufferIndex] + iSeed)) ^
  466. ((UCHAR)( achBuffer[(iBufferIndex+iSeed) & 31] -
  467. Keys[iBufferIndex] )));
  468. iSeed += achBuffer[iBufferIndex];
  469. }
  470. return iSeed;
  471. }
  472. //
  473. // Takes a 17-byte array and makes a 34-byte array out of it by
  474. // putting each nibble into the space of a byte.
  475. //
  476. STATIC
  477. void
  478. ExpandBytes(
  479. IN PUCHAR InArray,
  480. OUT PUCHAR OutArray
  481. )
  482. {
  483. unsigned int i;
  484. for (i = 0 ; i < (NUM_NYBBLES / 2); i++) {
  485. OutArray[i * 2] = InArray[i] & 0x0f;
  486. OutArray[(i * 2) + 1] = (InArray[i] & 0xf0) >> 4;
  487. }
  488. }
  489. //
  490. // Takes a 34-byte array and makes a 17-byte array out of it
  491. // by combining the lower nibbles of two bytes into a byte.
  492. //
  493. STATIC
  494. void
  495. CompressBytes(
  496. IN PUCHAR InArray,
  497. OUT PUCHAR OutArray
  498. )
  499. {
  500. unsigned int i;
  501. for (i = 0; i < (NUM_NYBBLES / 2); i++) {
  502. OutArray[i] = InArray[i * 2] | (InArray[i * 2 + 1] << 4);
  503. }
  504. }
  505. #define N 0x10
  506. typedef char entry_t;
  507. entry_t pinv[N][N] = {
  508. { 0xF,0x8,0x5,0x7,0xC,0x2,0xE,0x9,0x0,0x1,0x6,0xD,0x3,0x4,0xB,0xA,},
  509. { 0x2,0xC,0xE,0x6,0xF,0x0,0x1,0x8,0xD,0x3,0xA,0x4,0x9,0xB,0x5,0x7,},
  510. { 0x5,0x2,0x9,0xF,0xC,0x4,0xD,0x0,0xE,0xA,0x6,0x8,0xB,0x1,0x3,0x7,},
  511. { 0xF,0xD,0x2,0x6,0x7,0x8,0x5,0x9,0x0,0x4,0xC,0x3,0x1,0xA,0xB,0xE,},
  512. { 0x5,0xE,0x2,0xB,0xD,0xA,0x7,0x0,0x8,0x6,0x4,0x1,0xF,0xC,0x3,0x9,},
  513. { 0x8,0x2,0xF,0xA,0x5,0x9,0x6,0xC,0x0,0xB,0x1,0xD,0x7,0x3,0x4,0xE,},
  514. { 0xE,0x8,0x0,0x9,0x4,0xB,0x2,0x7,0xC,0x3,0xA,0x5,0xD,0x1,0x6,0xF,},
  515. { 0x1,0x4,0x8,0xA,0xD,0xB,0x7,0xE,0x5,0xF,0x3,0x9,0x0,0x2,0x6,0xC,},
  516. { 0x5,0x3,0xC,0x8,0xB,0x2,0xE,0xA,0x4,0x1,0xD,0x0,0x6,0x7,0xF,0x9,},
  517. { 0x6,0x0,0xB,0xE,0xD,0x4,0xC,0xF,0x7,0x2,0x8,0xA,0x1,0x5,0x3,0x9,},
  518. { 0xB,0x5,0xA,0xE,0xF,0x1,0xC,0x0,0x6,0x4,0x2,0x9,0x3,0xD,0x7,0x8,},
  519. { 0x7,0x2,0xA,0x0,0xE,0x8,0xF,0x4,0xC,0xB,0x9,0x1,0x5,0xD,0x3,0x6,},
  520. { 0x7,0x4,0xF,0x9,0x5,0x1,0xC,0xB,0x0,0x3,0x8,0xE,0x2,0xA,0x6,0xD,},
  521. { 0x9,0x4,0x8,0x0,0xA,0x3,0x1,0xC,0x5,0xF,0x7,0x2,0xB,0xE,0x6,0xD,},
  522. { 0x9,0x5,0x4,0x7,0xE,0x8,0x3,0x1,0xD,0xB,0xC,0x2,0x0,0xF,0x6,0xA,},
  523. { 0x9,0xA,0xB,0xD,0x5,0x3,0xF,0x0,0x1,0xC,0x8,0x7,0x6,0x4,0xE,0x2,},
  524. };
  525. entry_t master_perm[] = {
  526. 0, 3, 0xe, 0xf, 9, 6, 0xa, 7, 0xc, 0xb, 1, 4, 5, 8, 2, 0xd,
  527. };
  528. entry_t key_sched[N][N];
  529. entry_t perm_sched[N][N];
  530. int InverseTableInitialized = 0;
  531. void cipher_inv (
  532. const entry_t *ctxt,
  533. const entry_t *key,
  534. entry_t *ptxt
  535. )
  536. {
  537. int sc, r;
  538. entry_t v;
  539. for (sc = 0; sc < N; sc++) {
  540. v = ctxt[sc];
  541. for (r = N; --r >= 0; ) {
  542. v ^= key[key_sched[sc][r]];
  543. v = pinv[perm_sched[sc][r]][v];
  544. }
  545. ptxt[sc] = v;
  546. }
  547. }
  548. #if 0
  549. void swab_nybbles (
  550. entry_t *vec
  551. )
  552. {
  553. int i, j;
  554. //
  555. // swap all columns instead of calling this routine twice.
  556. //
  557. for (i = 0; i < (2 * N); i += 2) {
  558. j = vec[i];
  559. vec[i] = vec[i+1];
  560. vec[i+1] = j;
  561. }
  562. }
  563. #endif
  564. VOID
  565. CalculateWireFromOldAndNewPasswords(
  566. UCHAR *Vold,
  567. UCHAR *Vnew,
  568. UCHAR *Vc
  569. )
  570. {
  571. if (InverseTableInitialized == 0) {
  572. UCHAR sc,r;
  573. for (sc = 0; sc < N; sc++) {
  574. key_sched[sc][N-1] = sc; /* terminal subkey */
  575. key_sched[0][(N+ N-1 - master_perm[sc])%N] = (N+sc-master_perm[sc])%N;
  576. }
  577. for (sc = 1; sc < N; sc++) for (r = 0; r < N; r++) {
  578. key_sched[sc][(r+master_perm[sc])%N] = (key_sched[0][r] + master_perm[sc]) % N;
  579. }
  580. for (sc = 0; sc < N; sc++) {
  581. perm_sched[sc][N-1] = sc;
  582. perm_sched[0][(N + N-1 - master_perm[sc])%N] = sc;
  583. }
  584. for (sc = 1; sc < N; sc++) for (r = 0; r < N; r++) {
  585. perm_sched[sc][r] = perm_sched[0][(N+r-master_perm[sc])%N];
  586. }
  587. InverseTableInitialized = 1;
  588. }
  589. //
  590. // already swapped coming in here... don't swap them again.
  591. //
  592. // swab_nybbles(Vold);
  593. // swab_nybbles(Vnew);
  594. cipher_inv( (entry_t *)(&Vnew[0]),
  595. (entry_t *)(&Vold[0]),
  596. (entry_t *)(&Vc[0]));
  597. cipher_inv( (entry_t *)(&Vnew[16]),
  598. (entry_t *)(&Vold[16]),
  599. (entry_t *)(&Vc[16]));
  600. // swab_nybbles(Vc);
  601. return;
  602. }