crypto.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. crypto.c
  5. Abstract:
  6. This module implements cryptographic functionality for the 802.11 core
  7. wireless networking library.
  8. Author:
  9. Chris Stevens 5-Nov-2015
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include "net80211.h"
  17. #include "eapol.h"
  18. #include <minoca/lib/crypto.h>
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // Define the default key ID to use for transmitting data.
  24. //
  25. #define NET80211_DEFAULT_ENCRYPTION_KEY 0
  26. //
  27. // ------------------------------------------------------ Data Type Definitions
  28. //
  29. //
  30. // ----------------------------------------------- Internal Function Prototypes
  31. //
  32. KSTATUS
  33. Net80211pCcmEncrypt (
  34. PNET80211_KEY Key,
  35. PUCHAR Message,
  36. ULONG MessageLength,
  37. PUCHAR Aad,
  38. ULONG AadLength,
  39. PUCHAR Nonce,
  40. ULONG NonceLength,
  41. PUCHAR AuthenticationField,
  42. ULONG AuthenticationFieldSize,
  43. ULONG LengthFieldSize
  44. );
  45. KSTATUS
  46. Net80211pCcmDecrypt (
  47. PNET80211_KEY Key,
  48. PUCHAR Message,
  49. ULONG MessageLength,
  50. PUCHAR Aad,
  51. ULONG AadLength,
  52. PUCHAR Nonce,
  53. ULONG NonceLength,
  54. PUCHAR AuthenticationField,
  55. ULONG AuthenticationFieldSize,
  56. ULONG LengthFieldSize
  57. );
  58. VOID
  59. Net80211pCcmComputeAuthenticationField (
  60. PNET80211_KEY Key,
  61. PUCHAR Message,
  62. ULONG MessageLength,
  63. PUCHAR Aad,
  64. ULONG AadLength,
  65. PUCHAR Nonce,
  66. ULONG NonceLength,
  67. PUCHAR AuthenticationField,
  68. ULONG AuthenticationFieldSize,
  69. ULONG LengthFieldSize
  70. );
  71. VOID
  72. Net80211pEapolCompletionRoutine (
  73. PVOID Context,
  74. KSTATUS Status
  75. );
  76. //
  77. // -------------------------------------------------------------------- Globals
  78. //
  79. //
  80. // ------------------------------------------------------------------ Functions
  81. //
  82. NET80211_API
  83. KSTATUS
  84. Net80211SetKey (
  85. PNET80211_LINK Link,
  86. PUCHAR KeyValue,
  87. ULONG KeyLength,
  88. ULONG KeyFlags,
  89. ULONG KeyId
  90. )
  91. /*++
  92. Routine Description:
  93. This routine sets the given key into the given network link. The 802.11
  94. networking library makes a local copy of all parameters.
  95. Arguments:
  96. Link - Supplies a pointer to the networking link to which the keys should
  97. be added.
  98. KeyValue - Supplies a pointer to the key value.
  99. KeyLength - Supplies the length of the key value, in bytes.
  100. KeyFlags - Supplies a bitmask of flags to describe the key. See
  101. NET80211_KEY_FLAG_* for definitions.
  102. KeyId - Supplies the ID of the key negotiated between this station and its
  103. peers and/or access point.
  104. Return Value:
  105. Status code.
  106. --*/
  107. {
  108. ULONG AllocationSize;
  109. PNET80211_ENCRYPTION Encryption;
  110. PNET80211_KEY Key;
  111. PNET80211_KEY OldKey;
  112. KSTATUS Status;
  113. OldKey = NULL;
  114. //
  115. // Make sure the key ID is valid and supported. The CCMP header only has
  116. // two bits for the key ID.
  117. //
  118. if (KeyId >= NET80211_MAX_KEY_COUNT) {
  119. return STATUS_INVALID_PARAMETER;
  120. }
  121. AllocationSize = sizeof(NET80211_KEY) + KeyLength - ANYSIZE_ARRAY;
  122. Key = MmAllocatePagedPool(AllocationSize, NET80211_ALLOCATION_TAG);
  123. if (Key == NULL) {
  124. Status = STATUS_INSUFFICIENT_RESOURCES;
  125. goto SetKeyEnd;
  126. }
  127. RtlZeroMemory(Key, AllocationSize);
  128. Key->Flags = KeyFlags;
  129. Key->Id = KeyId;
  130. Key->Length = KeyLength;
  131. RtlCopyMemory(Key->Value, KeyValue, KeyLength);
  132. //
  133. // Update the pointer in the array of keys for the active BSS.
  134. //
  135. KeAcquireQueuedLock(Link->Lock);
  136. if ((Link->ActiveBss == NULL) ||
  137. (Link->State != Net80211StateAssociated)) {
  138. Status = STATUS_NOT_READY;
  139. } else {
  140. Encryption = &(Link->ActiveBss->Encryption);
  141. OldKey = Encryption->Keys[KeyId];
  142. Encryption->Keys[KeyId] = Key;
  143. //
  144. // Update the key indices if this is a group key.
  145. //
  146. if ((KeyFlags & NET80211_KEY_FLAG_GLOBAL) != 0) {
  147. Encryption->GroupKeyIndex = KeyId;
  148. if ((Encryption->Flags &
  149. NET80211_ENCRYPTION_FLAG_USE_GROUP_CIPHER) != 0) {
  150. Encryption->PairwiseKeyIndex = KeyId;
  151. }
  152. }
  153. Status = STATUS_SUCCESS;
  154. }
  155. KeReleaseQueuedLock(Link->Lock);
  156. SetKeyEnd:
  157. if (!KSUCCESS(Status)) {
  158. if (Key != NULL) {
  159. Net80211pDestroyKey(Key);
  160. }
  161. }
  162. if (OldKey != NULL) {
  163. Net80211pDestroyKey(OldKey);
  164. }
  165. return Status;
  166. }
  167. VOID
  168. Net80211pDestroyKey (
  169. PNET80211_KEY Key
  170. )
  171. /*++
  172. Routine Description:
  173. This routine destroys the given 802.11 encryption key.
  174. Arguments:
  175. Key - Supplies a pointer to the key to be destroyed.
  176. Return Value:
  177. None.
  178. --*/
  179. {
  180. RtlZeroMemory(Key->Value, Key->Length);
  181. MmFreePagedPool(Key);
  182. return;
  183. }
  184. KSTATUS
  185. Net80211pInitializeEncryption (
  186. PNET80211_LINK Link,
  187. PNET80211_BSS_ENTRY Bss
  188. )
  189. /*++
  190. Routine Description:
  191. This routine initializes the 802.11 core to handle the completion of an
  192. advanced encryption handshake.
  193. Arguments:
  194. Link - Supplies a pointer to the 802.11 link establishing an ecrypted
  195. connection.
  196. Bss - Supplies a pointer to the BSS on which the encryption handshake will
  197. take place.
  198. Return Value:
  199. Status code.
  200. --*/
  201. {
  202. ULONG ApRsnSize;
  203. NETWORK_ADDRESS AuthenticatorAddress;
  204. EAPOL_CREATION_PARAMETERS Parameters;
  205. ULONG StationRsnSize;
  206. KSTATUS Status;
  207. ASSERT(Bss != NULL);
  208. //
  209. // The BSS is good to go if there is alreayd an EAPOL instance associated
  210. // with it.
  211. //
  212. if (Bss->EapolHandle != INVALID_HANDLE) {
  213. return STATUS_SUCCESS;
  214. }
  215. //
  216. // If there is no encryption required by the BSS or it is using the basic
  217. // authentication built into 802.11, there is no work to be done.
  218. //
  219. if ((Bss->Encryption.Pairwise == NetworkEncryptionNone) ||
  220. (Bss->Encryption.Pairwise == NetworkEncryptionWep)) {
  221. return STATUS_SUCCESS;
  222. }
  223. //
  224. // Set both the pairwise and group key indices to the default.
  225. //
  226. Bss->Encryption.PairwiseKeyIndex = NET80211_DEFAULT_ENCRYPTION_KEY;
  227. Bss->Encryption.GroupKeyIndex = NET80211_DEFAULT_ENCRYPTION_KEY;
  228. //
  229. // Otherwise, EAPOL must be invoked in order to derive the PTK.
  230. //
  231. ASSERT(Bss->Encryption.Pairwise == NetworkEncryptionWpa2Psk);
  232. RtlZeroMemory(&AuthenticatorAddress, sizeof(NETWORK_ADDRESS));
  233. AuthenticatorAddress.Domain = NetDomain80211;
  234. RtlCopyMemory(AuthenticatorAddress.Address,
  235. Bss->State.Bssid,
  236. NET80211_ADDRESS_SIZE);
  237. RtlZeroMemory(&Parameters, sizeof(EAPOL_CREATION_PARAMETERS));
  238. Parameters.Mode = EapolModeSupplicant;
  239. Parameters.NetworkLink = Link->NetworkLink;
  240. Parameters.Net80211Link = Link;
  241. Parameters.SupplicantAddress = &(Link->Properties.PhysicalAddress);
  242. Parameters.AuthenticatorAddress = &AuthenticatorAddress;
  243. Parameters.Ssid = NET80211_GET_ELEMENT_DATA(Bss->Ssid);
  244. Parameters.SsidLength = NET80211_GET_ELEMENT_LENGTH(Bss->Ssid);
  245. Parameters.Passphrase = Bss->Passphrase;
  246. Parameters.PassphraseLength = Bss->PassphraseLength;
  247. Parameters.SupplicantRsn = Bss->Encryption.StationRsn;
  248. StationRsnSize = NET80211_GET_ELEMENT_LENGTH(Bss->Encryption.StationRsn) +
  249. NET80211_ELEMENT_HEADER_SIZE;
  250. Parameters.SupplicantRsnSize = StationRsnSize;
  251. Parameters.AuthenticatorRsn = Bss->Encryption.ApRsn;
  252. ApRsnSize = NET80211_GET_ELEMENT_LENGTH(Bss->Encryption.ApRsn) +
  253. NET80211_ELEMENT_HEADER_SIZE;
  254. Parameters.AuthenticatorRsnSize = ApRsnSize;
  255. Parameters.CompletionRoutine = Net80211pEapolCompletionRoutine;
  256. Parameters.CompletionContext = Link;
  257. Status = Net80211pEapolCreateInstance(&Parameters, &(Bss->EapolHandle));
  258. if (!KSUCCESS(Status)) {
  259. return Status;
  260. }
  261. return STATUS_SUCCESS;
  262. }
  263. VOID
  264. Net80211pDestroyEncryption (
  265. PNET80211_BSS_ENTRY Bss
  266. )
  267. /*++
  268. Routine Description:
  269. This routine destroys the context used to handle encryption initialization.
  270. It is not necessary to keep this context once the encrypted state is
  271. reached.
  272. Arguments:
  273. Bss - Supplies a pointer to the BSS on which encryption initialization took
  274. place.
  275. Return Value:
  276. None.
  277. --*/
  278. {
  279. ASSERT(Bss != NULL);
  280. if (Bss->EapolHandle == INVALID_HANDLE) {
  281. return;
  282. }
  283. Net80211pEapolDestroyInstance(Bss->EapolHandle);
  284. Bss->EapolHandle = INVALID_HANDLE;
  285. return;
  286. }
  287. KSTATUS
  288. Net80211pEncryptPacket (
  289. PNET80211_LINK Link,
  290. PNET80211_BSS_ENTRY Bss,
  291. PNET_PACKET_BUFFER Packet
  292. )
  293. /*++
  294. Routine Description:
  295. This routine encrypts the given network packet's plaintext data. The
  296. supplied packet buffer is modified directly and should already include the
  297. full MPDU (i.e. the 802.11 headers should be present).
  298. Arguments:
  299. Link - Supplies a pointer to the 802.11 network link that owns the packet.
  300. Bss - Supplies a pointer to the BSS over which this packet should be sent.
  301. Packet - Supplies a pointer to the packet to encrypt.
  302. Return Value:
  303. Status code.
  304. --*/
  305. {
  306. NET80211_AAD Aad;
  307. PUCHAR AuthField;
  308. NET80211_CCM_NONCE CcmNonce;
  309. PNET80211_CCMP_HEADER CcmpHeader;
  310. PNET80211_DATA_FRAME_HEADER DataHeader;
  311. ULONG Index;
  312. PNET80211_KEY Key;
  313. ULONG KeyId;
  314. PUCHAR Message;
  315. ULONG MessageLength;
  316. PNET80211_DATA_FRAME_HEADER MovedDataHeader;
  317. ULONGLONG PacketNumber;
  318. PUCHAR PacketNumberArray;
  319. KSTATUS Status;
  320. //
  321. // Use the pairwise key by default.
  322. //
  323. KeyId = Bss->Encryption.PairwiseKeyIndex;
  324. Key = Bss->Encryption.Keys[KeyId];
  325. if ((Key == NULL) || ((Key->Flags & NET80211_KEY_FLAG_TRANSMIT) == 0)) {
  326. RtlDebugPrint("802.11: Failed to find valid key for transmit.\n");
  327. Status = STATUS_INVALID_CONFIGURATION;
  328. goto EncryptPacketEnd;
  329. }
  330. //
  331. // The start of the packet's valid data should point to the 802.11 header.
  332. //
  333. DataHeader = Packet->Buffer + Packet->DataOffset;
  334. AuthField = Packet->Buffer + Packet->FooterOffset;
  335. Message = (PUCHAR)(DataHeader + 1);
  336. MessageLength = AuthField - Message;
  337. Packet->FooterOffset += NET80211_CCMP_MIC_SIZE;
  338. //
  339. // Get a new packet number for the temporal key. The first 48-bits cannot
  340. // wrap. It's time to get a new temporal key if they do.
  341. //
  342. PacketNumber = RtlAtomicAdd64(&(Key->PacketNumber), 1);
  343. ASSERT(PacketNumber < 0x1000000000000);
  344. //
  345. // Construct the AAD based on the 802.11 header.
  346. //
  347. Aad.FrameControl = DataHeader->FrameControl &
  348. NET80211_AAD_FRAME_CONTROL_DEFAULT_MASK;
  349. RtlCopyMemory(Aad.Address1,
  350. DataHeader->ReceiverAddress,
  351. NET80211_ADDRESS_SIZE * 3);
  352. Aad.SequenceControl = DataHeader->SequenceControl &
  353. NET80211_AAD_SEQUENCE_CONTROL_MASK;
  354. //
  355. // Construct the CCM nonce. This is based on the packet number, which must
  356. // be stored in big-endian byte order.
  357. //
  358. CcmNonce.Flags = 0;
  359. RtlCopyMemory(CcmNonce.Address2, Aad.Address2, NET80211_ADDRESS_SIZE);
  360. PacketNumberArray = (PUCHAR)&PacketNumber;
  361. for (Index = 0; Index < NET80211_CCMP_PACKET_NUMBER_SIZE; Index += 1) {
  362. CcmNonce.PacketNumber[Index] =
  363. PacketNumberArray[NET80211_CCMP_PACKET_NUMBER_SIZE - 1 - Index];
  364. }
  365. //
  366. // Perform the CCM originator processing to produce the cipher text.
  367. //
  368. Status = Net80211pCcmEncrypt(Key,
  369. Message,
  370. MessageLength,
  371. (PUCHAR)&Aad,
  372. sizeof(NET80211_AAD),
  373. (PUCHAR)&CcmNonce,
  374. sizeof(NET80211_CCM_NONCE),
  375. AuthField,
  376. NET80211_CCMP_MIC_SIZE,
  377. NET80211_CCMP_LENGTH_FIELD_SIZE);
  378. if (!KSUCCESS(Status)) {
  379. goto EncryptPacketEnd;
  380. }
  381. //
  382. // Build the finalized encrypted packet. First move the 802.11 header
  383. // forward to make space for the CCMP header.
  384. //
  385. Packet->DataOffset -= sizeof(NET80211_CCMP_HEADER);
  386. MovedDataHeader = Packet->Buffer + Packet->DataOffset;
  387. RtlCopyMemory(MovedDataHeader,
  388. DataHeader,
  389. sizeof(NET80211_DATA_FRAME_HEADER));
  390. //
  391. // Construct the CCMP header using key ID 0.
  392. //
  393. CcmpHeader = (PNET80211_CCMP_HEADER)(MovedDataHeader + 1);
  394. CcmpHeader->Reserved = 0;
  395. CcmpHeader->Flags = NET80211_CCMP_FLAG_EXT_IV |
  396. ((KeyId << NET80211_CCMP_FLAG_KEY_ID_SHIFT) &
  397. NET80211_CCMP_FLAG_KEY_ID_MASK);
  398. NET80211_SET_CCMP_HEADER_PACKET_NUMBER(CcmpHeader, PacketNumber);
  399. //
  400. // The plaintext was encrypted in place and is right where it should be and
  401. // the MIC was placed where it should be in the footer. This packet is good
  402. // to go!
  403. //
  404. EncryptPacketEnd:
  405. return Status;
  406. }
  407. KSTATUS
  408. Net80211pDecryptPacket (
  409. PNET80211_LINK Link,
  410. PNET80211_BSS_ENTRY Bss,
  411. PNET_PACKET_BUFFER Packet
  412. )
  413. /*++
  414. Routine Description:
  415. This routine decrypts the given network packet's ciphertext. The supplied
  416. packet buffer is modified directly and should contain the full encrypted
  417. MPDU, including the 802.11 headers.
  418. Arguments:
  419. Link - Supplies a pointer to the 802.11 network link that owns the packet.
  420. Bss - Supplies a pointer to the BSS over which this packet was received.
  421. Packet - Supplies a pointer to the packet to decrypt.
  422. Return Value:
  423. Status code.
  424. --*/
  425. {
  426. NET80211_AAD Aad;
  427. PUCHAR AuthField;
  428. NET80211_CCM_NONCE CcmNonce;
  429. PNET80211_CCMP_HEADER CcmpHeader;
  430. PNET80211_DATA_FRAME_HEADER DataHeader;
  431. ULONG Index;
  432. PNET80211_KEY Key;
  433. ULONG KeyId;
  434. PUCHAR Message;
  435. ULONG MessageLength;
  436. ULONGLONG PacketNumber;
  437. PUCHAR PacketNumberArray;
  438. KSTATUS Status;
  439. //
  440. // The start of the packet's valid data should point to the 802.11 header.
  441. //
  442. DataHeader = Packet->Buffer + Packet->DataOffset;
  443. CcmpHeader = (PNET80211_CCMP_HEADER)(DataHeader + 1);
  444. Message = (PUCHAR)(CcmpHeader + 1);
  445. AuthField = Packet->Buffer + Packet->FooterOffset - NET80211_CCMP_MIC_SIZE;
  446. MessageLength = AuthField - Message;
  447. //
  448. // Get the correct key to use for the decryption.
  449. //
  450. KeyId = (CcmpHeader->Flags & NET80211_CCMP_FLAG_KEY_ID_MASK) >>
  451. NET80211_CCMP_FLAG_KEY_ID_SHIFT;
  452. Key = Bss->Encryption.Keys[KeyId];
  453. if (Key == NULL) {
  454. Status = STATUS_UNSUCCESSFUL;
  455. goto DecryptPacketEnd;
  456. }
  457. //
  458. // Construct the AAD based on the 802.11 header.
  459. //
  460. Aad.FrameControl = DataHeader->FrameControl &
  461. NET80211_AAD_FRAME_CONTROL_DEFAULT_MASK;
  462. RtlCopyMemory(Aad.Address1,
  463. DataHeader->ReceiverAddress,
  464. NET80211_ADDRESS_SIZE * 3);
  465. Aad.SequenceControl = DataHeader->SequenceControl &
  466. NET80211_AAD_SEQUENCE_CONTROL_MASK;
  467. //
  468. // Construct the CCM nonce. This is based on the packet number retrieved
  469. // from the CCMP header.
  470. //
  471. CcmNonce.Flags = 0;
  472. RtlCopyMemory(CcmNonce.Address2, Aad.Address2, NET80211_ADDRESS_SIZE);
  473. NET80211_GET_CCMP_HEADER_PACKET_NUMBER(CcmpHeader, PacketNumber);
  474. PacketNumberArray = (PUCHAR)&PacketNumber;
  475. for (Index = 0; Index < NET80211_CCMP_PACKET_NUMBER_SIZE; Index += 1) {
  476. CcmNonce.PacketNumber[Index] =
  477. PacketNumberArray[NET80211_CCMP_PACKET_NUMBER_SIZE - 1 - Index];
  478. }
  479. //
  480. // Perform the CCM originator processing to produce the cipher text.
  481. //
  482. Status = Net80211pCcmDecrypt(Key,
  483. Message,
  484. MessageLength,
  485. (PUCHAR)&Aad,
  486. sizeof(NET80211_AAD),
  487. (PUCHAR)&CcmNonce,
  488. sizeof(NET80211_CCM_NONCE),
  489. AuthField,
  490. NET80211_CCMP_MIC_SIZE,
  491. NET80211_CCMP_LENGTH_FIELD_SIZE);
  492. if (!KSUCCESS(Status)) {
  493. RtlDebugPrint("802.11: Failed to decrypt packet 0x%08x for link "
  494. "0x%08x.\n",
  495. Packet,
  496. Link);
  497. goto DecryptPacketEnd;
  498. }
  499. //
  500. // Compare the packet number to the replay counter and toss the packet if
  501. // if it's number is too low.
  502. //
  503. if (PacketNumber <= Key->ReplayCounter) {
  504. Status = STATUS_TOO_LATE;
  505. goto DecryptPacketEnd;
  506. }
  507. Key->ReplayCounter = PacketNumber;
  508. //
  509. // Move past both the encryption header and the data header. Fully
  510. // recreating a decrypted packet is not useful unless tooling requires it.
  511. //
  512. Packet->DataOffset += sizeof(NET80211_DATA_FRAME_HEADER) +
  513. sizeof(NET80211_CCMP_HEADER);
  514. Packet->FooterOffset -= NET80211_CCMP_MIC_SIZE;
  515. DecryptPacketEnd:
  516. return Status;
  517. }
  518. //
  519. // --------------------------------------------------------- Internal Functions
  520. //
  521. KSTATUS
  522. Net80211pCcmEncrypt (
  523. PNET80211_KEY Key,
  524. PUCHAR Message,
  525. ULONG MessageLength,
  526. PUCHAR Aad,
  527. ULONG AadLength,
  528. PUCHAR Nonce,
  529. ULONG NonceLength,
  530. PUCHAR AuthenticationField,
  531. ULONG AuthenticationFieldSize,
  532. ULONG LengthFieldSize
  533. )
  534. /*++
  535. Routine Description:
  536. This routine performs CCM originator processing on the given plaintext
  537. message, updating it in place with the corresponding encrypted text.
  538. Arguments:
  539. Key - Supplies a pointer to the temporal key to use for CCM encryption.
  540. Message - Supplies a pointer to the plaintext message that is to be
  541. encrypted in place.
  542. MessageLength - Supplies the length of the plaintext message, in bytes.
  543. Aad - Supplies a pointer to the additional authentication data (AAD).
  544. AadLength - Supplies the length of the AAD, in bytes.
  545. Nonce - Supplies a pointer to the nonce value to use for CCM encryption.
  546. NonceLength - Supplies the length of the nonce value, in bytes.
  547. AuthenticationField - Supplies a pointer to a buffer that is to receive
  548. the authentication bytes for the CCM encryption (i.e. the MIC).
  549. AuthenticationFieldSize - Supplies the length of the authentication field
  550. in bytes.
  551. LengthFieldSize - Supplies the size, in bytes, of the CCM length field.
  552. Return Value:
  553. Status code.
  554. --*/
  555. {
  556. AES_CONTEXT AesContext;
  557. UCHAR AesInitializationVector[AES_INITIALIZATION_VECTOR_SIZE];
  558. ULONG BlockCount;
  559. UCHAR BlockIn[AES_BLOCK_SIZE];
  560. ULONG BytesRemaining;
  561. ULONG Index;
  562. ASSERT(NonceLength >= (AES_BLOCK_SIZE - 1 - LengthFieldSize));
  563. //
  564. // Compute the authentication field and store it in the input block, as it
  565. // used as the first input for the encryption process.
  566. //
  567. Net80211pCcmComputeAuthenticationField(Key,
  568. Message,
  569. MessageLength,
  570. Aad,
  571. AadLength,
  572. Nonce,
  573. NonceLength,
  574. BlockIn,
  575. AuthenticationFieldSize,
  576. LengthFieldSize);
  577. //
  578. // Initialize the AES context in counter mode.
  579. //
  580. AesInitializationVector[0] = LengthFieldSize - 1;
  581. RtlCopyMemory(AesInitializationVector + 1,
  582. Nonce,
  583. (AES_BLOCK_SIZE - 1 - LengthFieldSize));
  584. for (Index = AES_INITIALIZATION_VECTOR_SIZE - LengthFieldSize;
  585. Index < AES_INITIALIZATION_VECTOR_SIZE;
  586. Index += 1) {
  587. AesInitializationVector[Index] = 0;
  588. }
  589. CyAesInitialize(&AesContext,
  590. AesModeCtr128,
  591. Key->Value,
  592. AesInitializationVector);
  593. //
  594. // The first block encrypts the authentication field to get the
  595. // authentication value.
  596. //
  597. CyAesCtrEncrypt(&AesContext, BlockIn, BlockIn, AES_BLOCK_SIZE);
  598. RtlCopyMemory(AuthenticationField, BlockIn, AuthenticationFieldSize);
  599. //
  600. // The message is now encrypted with the rest of the counter sequence.
  601. // Because of how the counter algorithm works, this can actually be done
  602. // in-place.
  603. //
  604. BlockCount = MessageLength / AES_BLOCK_SIZE;
  605. BytesRemaining = MessageLength % AES_BLOCK_SIZE;
  606. CyAesCtrEncrypt(&AesContext, Message, Message, BlockCount * AES_BLOCK_SIZE);
  607. //
  608. // If there are leftover bytes, then copy them to a local block, perform
  609. // the encryption and then copy back the ciphertext.
  610. //
  611. if (BytesRemaining != 0) {
  612. RtlCopyMemory(BlockIn,
  613. Message + (BlockCount * AES_BLOCK_SIZE),
  614. BytesRemaining);
  615. CyAesCtrEncrypt(&AesContext, BlockIn, BlockIn, AES_BLOCK_SIZE);
  616. RtlCopyMemory(Message + (BlockCount * AES_BLOCK_SIZE),
  617. BlockIn,
  618. BytesRemaining);
  619. }
  620. return STATUS_SUCCESS;
  621. }
  622. KSTATUS
  623. Net80211pCcmDecrypt (
  624. PNET80211_KEY Key,
  625. PUCHAR Message,
  626. ULONG MessageLength,
  627. PUCHAR Aad,
  628. ULONG AadLength,
  629. PUCHAR Nonce,
  630. ULONG NonceLength,
  631. PUCHAR AuthenticationField,
  632. ULONG AuthenticationFieldSize,
  633. ULONG LengthFieldSize
  634. )
  635. /*++
  636. Routine Description:
  637. This routine performs CCM recipient processing on the given ciphertext
  638. message, updating it in place with the corresponding decrypted text.
  639. Arguments:
  640. Key - Supplies a pointer to the temporal key to use for CCM decryption.
  641. Message - Supplies a pointer to the encrypted message that is to be
  642. decrypted in place.
  643. MessageLength - Supplies the length of the ciphertext message, in bytes.
  644. Aad - Supplies a pointer to the additional authentication data (AAD).
  645. AadLength - Supplies the length of the AAD, in bytes.
  646. Nonce - Supplies a pointer to the nonce value to use for CCM encryption.
  647. NonceLength - Supplies the length of the nonce value, in bytes.
  648. AuthenticationField - Supplies a pointer to the authentication bytes for
  649. the CCM decryption (i.e. the MIC).
  650. AuthenticationFieldSize - Supplies the length of the authentication field
  651. in bytes.
  652. LengthFieldSize - Supplies the size, in bytes, of the CCM length field.
  653. Return Value:
  654. Status code.
  655. --*/
  656. {
  657. AES_CONTEXT AesContext;
  658. UCHAR AesInitializationVector[AES_INITIALIZATION_VECTOR_SIZE];
  659. ULONG BlockCount;
  660. UCHAR BlockIn[AES_BLOCK_SIZE];
  661. ULONG BytesRemaining;
  662. ULONG Index;
  663. UCHAR LocalAuthenticationField[NET80211_CCM_MAX_AUTHENTICATION_FIELD_SIZE];
  664. BOOL Match;
  665. ASSERT(NonceLength >= (AES_BLOCK_SIZE - 1 - LengthFieldSize));
  666. ASSERT(MessageLength < MAX_USHORT);
  667. //
  668. // Initialize the AES context in CTR mode.
  669. //
  670. AesInitializationVector[0] = LengthFieldSize - 1;
  671. RtlCopyMemory(AesInitializationVector + 1,
  672. Nonce,
  673. (AES_BLOCK_SIZE - 1 - LengthFieldSize));
  674. for (Index = AES_INITIALIZATION_VECTOR_SIZE - LengthFieldSize;
  675. Index < AES_INITIALIZATION_VECTOR_SIZE;
  676. Index += 1) {
  677. AesInitializationVector[Index] = 0;
  678. }
  679. CyAesInitialize(&AesContext,
  680. AesModeCtr128,
  681. Key->Value,
  682. AesInitializationVector);
  683. //
  684. // The authentication value passes through the counter decryption first
  685. // to recompute the authentification field. The uninitialized portions of
  686. // the supplied block do not need to be zeroed.
  687. //
  688. RtlCopyMemory(BlockIn, AuthenticationField, AuthenticationFieldSize);
  689. CyAesCtrDecrypt(&AesContext, BlockIn, BlockIn, AES_BLOCK_SIZE);
  690. RtlCopyMemory(AuthenticationField, BlockIn, AuthenticationFieldSize);
  691. //
  692. // The message is now decrypted with the rest of the counter sequence.
  693. // Because of how the counter algorithm works, this can actually be done
  694. // in-place.
  695. //
  696. BlockCount = MessageLength / AES_BLOCK_SIZE;
  697. BytesRemaining = MessageLength % AES_BLOCK_SIZE;
  698. CyAesCtrDecrypt(&AesContext, Message, Message, BlockCount * AES_BLOCK_SIZE);
  699. //
  700. // If there are leftover bytes, then copy them to a local block, perform
  701. // the decryption and then copy back the ciphertext.
  702. //
  703. if (BytesRemaining != 0) {
  704. RtlCopyMemory(BlockIn,
  705. Message + (BlockCount * AES_BLOCK_SIZE),
  706. BytesRemaining);
  707. CyAesCtrDecrypt(&AesContext, BlockIn, BlockIn, AES_BLOCK_SIZE);
  708. RtlCopyMemory(Message + (BlockCount * AES_BLOCK_SIZE),
  709. BlockIn,
  710. BytesRemaining);
  711. }
  712. //
  713. // Compute the authentication field for the now decrypted message and
  714. // compare it to the recomputed authentication field.
  715. //
  716. Net80211pCcmComputeAuthenticationField(Key,
  717. Message,
  718. MessageLength,
  719. Aad,
  720. AadLength,
  721. Nonce,
  722. NonceLength,
  723. LocalAuthenticationField,
  724. AuthenticationFieldSize,
  725. LengthFieldSize);
  726. Match = RtlCompareMemory(AuthenticationField,
  727. LocalAuthenticationField,
  728. AuthenticationFieldSize);
  729. if (Match != FALSE) {
  730. return STATUS_SUCCESS;
  731. }
  732. RtlDebugPrint("802.11: CCM decryption found a bad authentication value!\n");
  733. return STATUS_UNSUCCESSFUL;
  734. }
  735. VOID
  736. Net80211pCcmComputeAuthenticationField (
  737. PNET80211_KEY Key,
  738. PUCHAR Message,
  739. ULONG MessageLength,
  740. PUCHAR Aad,
  741. ULONG AadLength,
  742. PUCHAR Nonce,
  743. ULONG NonceLength,
  744. PUCHAR AuthenticationField,
  745. ULONG AuthenticationFieldSize,
  746. ULONG LengthFieldSize
  747. )
  748. /*++
  749. Routine Description:
  750. This routine computes the authentication field for the given plaintext
  751. message, additional information, and key. This is used for both encryption
  752. and decryption as a MIC at the end of the packet.
  753. Arguments:
  754. Key - Supplies a pointer to the temporal key to use for CBC encryption.
  755. Message - Supplies a pointer to the plaintext message that is to be
  756. used as input to compute the authentication field.
  757. MessageLength - Supplies the length of the plaintext message, in bytes.
  758. Aad - Supplies a pointer to the additional authentication data (AAD).
  759. AadLength - Supplies the length of the AAD, in bytes.
  760. Nonce - Supplies a pointer to the nonce value to use.
  761. NonceLength - Supplies the length of the nonce value, in bytes.
  762. AuthenticationField - Supplies a pointer to a buffer that is to receive
  763. the authentication field for the CCM encryption (i.e. the MIC).
  764. AuthenticationFieldSize - Supplies the length of the authentication field
  765. in bytes.
  766. LengthFieldSize - Supplies the size, in bytes, of the CCM length field.
  767. Return Value:
  768. None.
  769. --*/
  770. {
  771. ULONG AadIndex;
  772. AES_CONTEXT AesContext;
  773. UCHAR BlockIn[AES_BLOCK_SIZE];
  774. ULONG BlockIndex;
  775. UCHAR BlockOut[AES_BLOCK_SIZE];
  776. ULONG BytesRemaining;
  777. ULONG BytesThisRound;
  778. UCHAR Flags;
  779. ULONG Index;
  780. ULONG MessageIndex;
  781. ASSERT(AuthenticationFieldSize <=
  782. NET80211_CCM_MAX_AUTHENTICATION_FIELD_SIZE);
  783. ASSERT((LengthFieldSize >= NET80211_CCM_MIN_LENGTH_FIELD_SIZE) &&
  784. (LengthFieldSize <= NET80211_CCM_MAX_LENGTH_FIELD_SIZE));
  785. //
  786. // Initialize the AES context for CBC mode.
  787. //
  788. CyAesInitialize(&AesContext, AesModeCbc128, Key->Value, NULL);
  789. //
  790. // Initialize the first block based on the length field size,
  791. // authentication field size, nonce, and message length.
  792. //
  793. Flags = ((AuthenticationFieldSize - 2) / 2) <<
  794. NET80211_CCM_FLAG_AUTHENTICATION_FIELD_SHIFT;
  795. Flags |= (LengthFieldSize - 1) << NET80211_CCM_FLAG_LENGTH_SHIFT;
  796. if (AadLength != 0) {
  797. Flags |= NET80211_CCM_FLAG_AAD;
  798. }
  799. BlockIn[0] = Flags;
  800. RtlCopyMemory(BlockIn + 1, Nonce, (AES_BLOCK_SIZE - 1 - LengthFieldSize));
  801. for (Index = LengthFieldSize; Index > 0; Index -= 1) {
  802. BlockIn[AES_BLOCK_SIZE - Index] = ((PUCHAR)&MessageLength)[Index - 1];
  803. }
  804. //
  805. // Encrypt the first output block. Because this is a CBC algorithm that can
  806. // be called multiple times, the AES library internally remembers the last
  807. // out block and will XOR that with the next supplied in block before
  808. // encrypting.
  809. //
  810. CyAesCbcEncrypt(&AesContext, BlockIn, BlockOut, AES_BLOCK_SIZE);
  811. //
  812. // If an AAD was supplied, then that makes up the second block.
  813. //
  814. if (AadLength != 0) {
  815. if (AadLength <= NET80211_CCM_AAD_MAX_SHORT_LENGTH) {
  816. *((PUSHORT)&(BlockIn[0])) = CPU_TO_NETWORK16(AadLength);
  817. BlockIndex = 2;
  818. } else {
  819. *((PUSHORT)&(BlockIn[0])) = NET80211_CCM_AAD_LONG_ENCODING;
  820. *((PULONG)&(BlockIn[2])) = CPU_TO_NETWORK32(AadLength);
  821. BlockIndex = 6;
  822. }
  823. AadIndex = 0;
  824. BytesRemaining = AadLength;
  825. while (BytesRemaining != 0) {
  826. BytesThisRound = BytesRemaining;
  827. if (BytesThisRound > (AES_BLOCK_SIZE - BlockIndex)) {
  828. BytesThisRound = AES_BLOCK_SIZE - BlockIndex;
  829. }
  830. RtlCopyMemory(BlockIn + BlockIndex,
  831. Aad + AadIndex,
  832. BytesThisRound);
  833. BlockIndex += BytesThisRound;
  834. AadIndex += BytesThisRound;
  835. BytesRemaining -= BytesThisRound;
  836. //
  837. // Pad the block with zeros if necessary.
  838. //
  839. if (BlockIndex != AES_BLOCK_SIZE) {
  840. ASSERT(BytesRemaining == 0);
  841. RtlZeroMemory(BlockIn + BlockIndex,
  842. AES_BLOCK_SIZE - BlockIndex);
  843. }
  844. //
  845. // Encrypt this block. It will get XOR'd with the previous block,
  846. // which is stored internally to the AES context.
  847. //
  848. CyAesCbcEncrypt(&AesContext, BlockIn, BlockOut, AES_BLOCK_SIZE);
  849. BlockIndex = 0;
  850. }
  851. }
  852. //
  853. // Fold the message into the computation. This must not modify the contents
  854. // of the message buffer. As a result, it is done block-by-block.
  855. //
  856. MessageIndex = 0;
  857. BytesRemaining = MessageLength;
  858. while (BytesRemaining != 0) {
  859. BytesThisRound = BytesRemaining;
  860. if (BytesThisRound > (AES_BLOCK_SIZE - BlockIndex)) {
  861. BytesThisRound = AES_BLOCK_SIZE - BlockIndex;
  862. }
  863. RtlCopyMemory(BlockIn, Message + MessageIndex, BytesThisRound);
  864. MessageIndex += BytesThisRound;
  865. BytesRemaining -= BytesThisRound;
  866. //
  867. // Pad the block with zeros if necessary.
  868. //
  869. if (BytesThisRound != AES_BLOCK_SIZE) {
  870. ASSERT(BytesRemaining == 0);
  871. RtlZeroMemory(BlockIn + BytesThisRound,
  872. AES_BLOCK_SIZE - BytesThisRound);
  873. }
  874. //
  875. // Encrypt this block. It will get XOR'd with the previous block, which
  876. // is stored internally to the AES context.
  877. //
  878. CyAesCbcEncrypt(&AesContext, BlockIn, BlockOut, AES_BLOCK_SIZE);
  879. }
  880. //
  881. // The out block now stores the authentication field.
  882. //
  883. RtlCopyMemory(AuthenticationField, BlockOut, AuthenticationFieldSize);
  884. return;
  885. }
  886. VOID
  887. Net80211pEapolCompletionRoutine (
  888. PVOID Context,
  889. KSTATUS Status
  890. )
  891. /*++
  892. Routine Description:
  893. This routine is called when an EAPOL exchange completes. It is supplied by
  894. the creator of the EAPOL instance.
  895. Arguments:
  896. Context - Supplies a pointer to the context supplied by the creator of the
  897. EAPOL instance.
  898. Status - Supplies the completion status of the EAPOL exchange.
  899. Return Value:
  900. None.
  901. --*/
  902. {
  903. PNET80211_LINK Link;
  904. NET80211_STATE State;
  905. Link = (PNET80211_LINK)Context;
  906. State = Net80211StateEncrypted;
  907. if (!KSUCCESS(Status)) {
  908. RtlDebugPrint("802.11: EAPOL failed with status %d\n", Status);
  909. State = Net80211StateInitialized;
  910. }
  911. Net80211pSetState(Link, State);
  912. return;
  913. }