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.

554 lines
10 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. rc4safe.c
  5. Abstract:
  6. access rc4 key material in thread safe manner, without adversly affecting
  7. performance of multi-thread users.
  8. Author:
  9. Scott Field (sfield) 02-Jul-99
  10. --*/
  11. #ifndef KMODE_RNG
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <zwapi.h>
  17. #else
  18. #include <ntosp.h>
  19. #include <windef.h>
  20. #endif // KMODE_RNG
  21. #include <rc4.h>
  22. #include <randlib.h>
  23. #include "umkm.h"
  24. typedef struct {
  25. unsigned int BytesUsed; // bytes processed for key associated with this entry
  26. __LOCK_TYPE lock; // lock for serializing key entry
  27. RC4_KEYSTRUCT rc4key; // key material associated with this entry
  28. } RC4_SAFE, *PRC4_SAFE, *LPRC4_SAFE;
  29. typedef enum _MemoryMode {
  30. Paged = 1,
  31. NonPaged
  32. } MemoryMode;
  33. typedef struct {
  34. unsigned int Entries; // count of array entries.
  35. MemoryMode Mode; // allocation & behavior mode of SAFE_ARRAY
  36. RC4_SAFE *Array[]; // array of pointers to RC4_SAFE entries.
  37. } RC4_SAFE_ARRAY, *PRC4_SAFE_ARRAY, *LPRC4_SAFE_ARRAY;
  38. //
  39. // !!! RC4_SAFE_ENTRIES must be even multiple of 4 !!!
  40. //
  41. #ifndef KMODE_RNG
  42. #define RC4_SAFE_ENTRIES (8)
  43. #else
  44. //
  45. // we don't expect as much traffic in kernel mode, so use less resources.
  46. //
  47. #define RC4_SAFE_ENTRIES (4)
  48. #endif
  49. #ifdef KMODE_RNG
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text(PAGE, rc4_safe_select)
  52. #pragma alloc_text(PAGE, rc4_safe)
  53. #pragma alloc_text(PAGE, rc4_safe_key)
  54. #pragma alloc_text(PAGE, rc4_safe_select)
  55. #pragma alloc_text(PAGE, rc4_safe_startup)
  56. #pragma alloc_text(PAGE, rc4_safe_shutdown)
  57. #endif // ALLOC_PRAGMA
  58. #endif // KMODE_RNG
  59. void
  60. rc4_safe_select(
  61. IN void *pContext,
  62. OUT unsigned int *pEntry,
  63. OUT unsigned int *pBytesUsed
  64. )
  65. /*++
  66. Routine Description:
  67. key selector: choose a thread safe key.
  68. outputs key identifier and bytes used with key.
  69. --*/
  70. {
  71. RC4_SAFE_ARRAY *pRC4SafeArray;
  72. RC4_SAFE *pRC4Safe;
  73. static unsigned int circular;
  74. unsigned int local;
  75. #ifdef KMODE_RNG
  76. PAGED_CODE();
  77. #endif // KMODE_RNG
  78. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  79. //
  80. // there are 2 ways to increment the array selector:
  81. // 1. Just increment the pointer. On a multi-processor system,
  82. // with multiple threads calling rc4_safe_select simultaneously,
  83. // this can lead to several threads selecting the same array element.
  84. // This will lead to lock contention on the array element lock.
  85. // Currently, we've decided this scenario will be fairly rare, so the
  86. // penalty associated with option 2 is avoided.
  87. // 2. Use InterlockedIncrement to determine the array element. This would
  88. // yield no collision on an array element, hence no lock contention
  89. // on the embedded array lock. This introduces additional bus traffic
  90. // on SMP machines due to the lock primitive.
  91. //
  92. //
  93. #ifdef KMODE_RNG
  94. local = (unsigned int)InterlockedIncrement( (PLONG)&circular );
  95. #else
  96. circular++;
  97. local = circular;
  98. #endif // KMODE_RNG
  99. //
  100. // array index will not wrap.
  101. //
  102. local &= ( pRC4SafeArray->Entries-1 );
  103. pRC4Safe = pRC4SafeArray->Array[local];
  104. *pEntry = local;
  105. *pBytesUsed = pRC4Safe->BytesUsed;
  106. }
  107. #ifdef KMODE_RNG
  108. void
  109. rc4_safe_select_np(
  110. IN void *pContext,
  111. OUT unsigned int *pEntry,
  112. OUT unsigned int *pBytesUsed
  113. )
  114. /*++
  115. Routine Description:
  116. Non-paged, high-IRQL version of rc4_safe_select()
  117. --*/
  118. {
  119. RC4_SAFE_ARRAY *pRC4SafeArray;
  120. RC4_SAFE *pRC4Safe;
  121. unsigned int local;
  122. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  123. if( *pEntry == 0 ) {
  124. if( pRC4SafeArray->Entries == 1 ) {
  125. local = 0;
  126. } else {
  127. static unsigned int circular;
  128. local = (unsigned int)InterlockedIncrement( (PLONG)&circular );
  129. //
  130. // array index will not wrap.
  131. //
  132. local = (local % pRC4SafeArray->Entries);
  133. }
  134. } else {
  135. local = KeGetCurrentProcessorNumber();
  136. }
  137. pRC4Safe = pRC4SafeArray->Array[local];
  138. *pEntry = local;
  139. *pBytesUsed = pRC4Safe->BytesUsed;
  140. }
  141. #endif // KMODE_RNG
  142. void
  143. rc4_safe(
  144. IN void *pContext,
  145. IN unsigned int Entry,
  146. IN unsigned int cb,
  147. IN void *pv
  148. )
  149. /*++
  150. Routine Description:
  151. Initializes the rc4 key identified by the Entry index.
  152. Input key material is pv, of size cb.
  153. --*/
  154. {
  155. RC4_SAFE_ARRAY *pRC4SafeArray;
  156. RC4_SAFE *pRC4Safe;
  157. #ifdef KMODE_RNG
  158. KIRQL OldIrql;
  159. PAGED_CODE();
  160. #endif // KMODE_RNG
  161. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  162. Entry &= ( pRC4SafeArray->Entries - 1 );
  163. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  164. ENTER_LOCK( &(pRC4Safe->lock) );
  165. rc4( &(pRC4Safe->rc4key), cb, (unsigned char*) pv );
  166. pRC4Safe->BytesUsed += cb;
  167. LEAVE_LOCK( &(pRC4Safe->lock) );
  168. }
  169. #ifdef KMODE_RNG
  170. void
  171. rc4_safe_np(
  172. IN void *pContext,
  173. IN unsigned int Entry,
  174. IN unsigned int cb,
  175. IN void *pv
  176. )
  177. /*++
  178. Routine Description:
  179. Non-paged, high IRQL version of rc4_safe()
  180. --*/
  181. {
  182. RC4_SAFE_ARRAY *pRC4SafeArray;
  183. RC4_SAFE *pRC4Safe;
  184. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  185. // NOTE:
  186. // we ignore the Entry parameter.
  187. // future consideration may be ignore only when Entry == 0xffffffff
  188. // but, this would only be perf penalty currently.
  189. //
  190. Entry = KeGetCurrentProcessorNumber();
  191. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  192. rc4( &(pRC4Safe->rc4key), cb, (unsigned char*) pv );
  193. pRC4Safe->BytesUsed += cb;
  194. }
  195. #endif // KMODE_RNG
  196. void
  197. rc4_safe_key(
  198. IN void *pContext,
  199. IN unsigned int Entry,
  200. IN unsigned int cb,
  201. IN const void *pv
  202. )
  203. /*++
  204. Routine Description:
  205. Initializes the rc4 key identified by the Entry index.
  206. Input key material is pv, of size cb.
  207. --*/
  208. {
  209. RC4_SAFE_ARRAY *pRC4SafeArray;
  210. RC4_SAFE *pRC4Safe;
  211. #ifdef KMODE_RNG
  212. KIRQL OldIrql;
  213. PAGED_CODE();
  214. #endif // KMODE_RNG
  215. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  216. Entry &= ( pRC4SafeArray->Entries - 1 );
  217. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  218. ENTER_LOCK( &(pRC4Safe->lock) );
  219. rc4_key( &(pRC4Safe->rc4key), cb, (unsigned char*) pv );
  220. pRC4Safe->BytesUsed = 0;
  221. LEAVE_LOCK( &(pRC4Safe->lock) );
  222. }
  223. #ifdef KMODE_RNG
  224. void
  225. rc4_safe_key_np(
  226. IN void *pContext,
  227. IN unsigned int Entry,
  228. IN unsigned int cb,
  229. IN const void *pv
  230. )
  231. /*++
  232. Routine Description:
  233. Non-paged, high-IRQL version of rc4_safe_key()
  234. --*/
  235. {
  236. RC4_SAFE_ARRAY *pRC4SafeArray;
  237. RC4_SAFE *pRC4Safe;
  238. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  239. if( Entry == 0xffffffff ) {
  240. Entry = KeGetCurrentProcessorNumber();
  241. }
  242. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  243. rc4_key( &pRC4Safe->rc4key, cb, (unsigned char*) pv );
  244. pRC4Safe->BytesUsed = 0;
  245. }
  246. #endif // KMODE_RNG
  247. unsigned int
  248. rc4_safe_startup(
  249. IN OUT void **ppContext
  250. )
  251. /*++
  252. Routine Description:
  253. key selector: choose a thread safe key.
  254. outputs key identifier and bytes used with key.
  255. --*/
  256. {
  257. RC4_SAFE_ARRAY *pRC4SafeArray;
  258. RC4_SAFE *pRC4Safe;
  259. unsigned int Entries;
  260. unsigned int i;
  261. #ifdef KMODE_RNG
  262. PAGED_CODE();
  263. #endif // KMODE_RNG
  264. Entries = RC4_SAFE_ENTRIES;
  265. pRC4SafeArray = (RC4_SAFE_ARRAY *)ALLOC_NP(
  266. sizeof(RC4_SAFE_ARRAY) +
  267. (Entries * sizeof(RC4_SAFE *)) +
  268. (Entries * sizeof(RC4_SAFE))
  269. );
  270. if( pRC4SafeArray == NULL ) {
  271. return FALSE;
  272. }
  273. pRC4SafeArray->Entries = Entries;
  274. pRC4SafeArray->Mode = Paged;
  275. pRC4Safe = (RC4_SAFE*) ((unsigned char*)pRC4SafeArray +
  276. sizeof(RC4_SAFE_ARRAY) +
  277. (Entries * sizeof(RC4_SAFE*))
  278. );
  279. for ( i = 0 ; i < Entries ; i++, pRC4Safe++ ) {
  280. pRC4SafeArray->Array[i] = pRC4Safe;
  281. INIT_LOCK( &(pRC4Safe->lock) );
  282. //
  283. // cause client to re-key for each initialized array entry.
  284. //
  285. pRC4Safe->BytesUsed = 0xffffffff;
  286. }
  287. *ppContext = pRC4SafeArray;
  288. return TRUE;
  289. }
  290. #ifdef KMODE_RNG
  291. unsigned int
  292. rc4_safe_startup_np(
  293. IN OUT void **ppContext
  294. )
  295. /*++
  296. Routine Description:
  297. Non-Paged, high IRQL version of rc4_safe_startup()
  298. --*/
  299. {
  300. RC4_SAFE_ARRAY *pRC4SafeArray;
  301. RC4_SAFE *pRC4Safe;
  302. unsigned int Entries;
  303. unsigned int i;
  304. //
  305. // get installed processor count.
  306. //
  307. Entries = KeNumberProcessors;
  308. pRC4SafeArray = (RC4_SAFE_ARRAY *)ALLOC_NP(
  309. sizeof(RC4_SAFE_ARRAY) +
  310. (Entries * sizeof(RC4_SAFE *)) +
  311. (Entries * sizeof(RC4_SAFE))
  312. );
  313. if( pRC4SafeArray == NULL ) {
  314. return FALSE;
  315. }
  316. pRC4SafeArray->Entries = Entries;
  317. pRC4SafeArray->Mode = NonPaged;
  318. pRC4Safe = (RC4_SAFE*) ((unsigned char*)pRC4SafeArray +
  319. sizeof(RC4_SAFE_ARRAY) +
  320. (Entries * sizeof(RC4_SAFE*))
  321. );
  322. for ( i = 0 ; i < Entries ; i++, pRC4Safe++ ) {
  323. pRC4SafeArray->Array[i] = pRC4Safe;
  324. //
  325. // cause client to re-key for each initialized array entry.
  326. //
  327. pRC4Safe->BytesUsed = 0xffffffff;
  328. }
  329. *ppContext = pRC4SafeArray;
  330. return TRUE;
  331. }
  332. #endif
  333. void
  334. rc4_safe_shutdown(
  335. IN void *pContext
  336. )
  337. /*++
  338. Routine Description:
  339. rc4_safe_shutdown called to free resources associated with internal structures.
  340. typically called during DLL_PROCESS_DETACH type shutdown code.
  341. --*/
  342. {
  343. RC4_SAFE_ARRAY *SafeArray;
  344. unsigned int SafeEntries;
  345. unsigned int i;
  346. #ifdef KMODE_RNG
  347. PAGED_CODE();
  348. #endif // KMODE_RNG
  349. SafeArray = (RC4_SAFE_ARRAY*)pContext;
  350. SafeEntries = SafeArray->Entries;
  351. for ( i = 0 ; i < SafeEntries ; i++ ) {
  352. RC4_SAFE *pRC4Safe = SafeArray->Array[i];
  353. DELETE_LOCK( &(pRC4Safe->lock) );
  354. }
  355. FREE( pContext );
  356. }
  357. #ifdef KMODE_RNG
  358. void
  359. rc4_safe_shutdown_np(
  360. IN void *pContext
  361. )
  362. /*++
  363. Routine Description:
  364. Non-paged, high-IRQL version of rc4_safe_shutdown()
  365. --*/
  366. {
  367. FREE( pContext );
  368. }
  369. #endif