/** * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (IN) * @pw_block: 516-byte PwBlock (OUT) * Returns: 0 on success, -1 on failure */ int encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block) { size_t ucs2_len, offset; u8 *pos; os_memset(pw_block, 0, PWBLOCK_LEN); if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0) return -1; if (ucs2_len > 256) return -1; offset = (256 - ucs2_len) * 2; if (offset != 0) { os_memmove(pw_block + offset, pw_block, ucs2_len * 2); if (os_get_random(pw_block, offset) < 0) return -1; } /* * PasswordLength is 4 octets, but since the maximum password length is * 256, only first two (in little endian byte order) can be non-zero. */ pos = &pw_block[2 * 256]; WPA_PUT_LE16(pos, password_len * 2); rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); return 0; }
/** * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (IN) * @pw_block: 516-byte PwBlock (OUT) * Returns: 0 on success, -1 on failure */ int encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block) { size_t i, offset; u8 *pos; if (password_len > 256) return -1; os_memset(pw_block, 0, PWBLOCK_LEN); offset = (256 - password_len) * 2; if (os_get_random(pw_block, offset) < 0) return -1; for (i = 0; i < password_len; i++) pw_block[offset + i * 2] = password[i]; /* * PasswordLength is 4 octets, but since the maximum password length is * 256, only first two (in little endian byte order) can be non-zero. */ pos = &pw_block[2 * 256]; WPA_PUT_LE16(pos, password_len * 2); rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); return 0; }
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, struct wpa_eapol_key *key, u16 ver) { u16 keydatalen = WPA_GET_BE16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", (u8 *) (key + 1), keydatalen); if (!sm->ptk_set) { wpa_printf(MSG_WARNING, "WPA: PTK not available, " "cannot decrypt EAPOL-Key key data."); return -1; } /* Decrypt key data here so that this operation does not need * to be implemented separately for each message type. */ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { u8 ek[32]; os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->ptk.kek, 16); if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) { wpa_printf(MSG_ERROR, "WPA: RC4 failed"); return -1; } } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { u8 *buf; if (keydatalen % 8) { wpa_printf(MSG_WARNING, "WPA: Unsupported " "AES-WRAP len %d", keydatalen); return -1; } keydatalen -= 8; /* AES-WRAP adds 8 bytes */ buf = os_malloc(keydatalen); if (buf == NULL) { wpa_printf(MSG_WARNING, "WPA: No memory for " "AES-UNWRAP buffer"); return -1; } if (aes_unwrap(sm->ptk.kek, keydatalen / 8, (u8 *) (key + 1), buf)) { os_free(buf); wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - " "could not decrypt EAPOL-Key key data"); return -1; } os_memcpy(key + 1, buf, keydatalen); os_free(buf); WPA_PUT_BE16(key->key_data_length, keydatalen); } else { wpa_printf(MSG_WARNING, "WPA: Unsupported key_info type %d", ver); return -1; } wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", (u8 *) (key + 1), keydatalen); return 0; }
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, u16 auth_transaction, const u8 *challenge, int iswep) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication (shared key, transaction %d)", auth_transaction); if (auth_transaction == 1) { if (!sta->challenge) { /* Generate a pseudo-random challenge */ u8 key[8]; time_t now; int r; sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN); if (sta->challenge == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; now = time(NULL); r = random(); os_memcpy(key, &now, 4); os_memcpy(key + 4, &r, 4); rc4_skip(key, sizeof(key), 0, sta->challenge, WLAN_AUTH_CHALLENGE_LEN); } return 0; } if (auth_transaction != 3) return WLAN_STATUS_UNSPECIFIED_FAILURE; /* Transaction 3 */ if (!iswep || !sta->challenge || !challenge || os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "shared key authentication - invalid " "challenge-response"); return WLAN_STATUS_CHALLENGE_FAIL; } hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (shared key)"); #ifdef IEEE80211_REQUIRE_AUTH_ACK /* Station will be marked authenticated if it ACKs the * authentication reply. */ #else sta->flags |= WLAN_STA_AUTH; wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); #endif os_free(sta->challenge); sta->challenge = NULL; return 0; }
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) { size_t i, j, blocks; u8 tmp[32]; switch (ctx->alg) { case CRYPTO_CIPHER_ALG_RC4: if (plain != crypt) os_memcpy(plain, crypt, len); rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, ctx->u.rc4.used_bytes, plain, len); ctx->u.rc4.used_bytes += len; break; case CRYPTO_CIPHER_ALG_AES: if (len % ctx->u.aes.block_size) return -1; blocks = len / ctx->u.aes.block_size; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, ctx->u.aes.block_size); aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); for (j = 0; j < ctx->u.aes.block_size; j++) plain[j] ^= ctx->u.aes.cbc[j]; os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size); plain += ctx->u.aes.block_size; crypt += ctx->u.aes.block_size; } break; case CRYPTO_CIPHER_ALG_3DES: if (len % 8) return -1; blocks = len / 8; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, 8); des3_decrypt(crypt, &ctx->u.des3.key, plain); for (j = 0; j < 8; j++) plain[j] ^= ctx->u.des3.cbc[j]; os_memcpy(ctx->u.des3.cbc, tmp, 8); plain += 8; crypt += 8; } break; default: return -1; } return 0; }
static void entropy_init() { FILE *urandom = fopen("/dev/urandom", "r"); if (urandom == NULL) { fprintf(stderr, "error: could not seed entropy pool\n"); exit(EXIT_FAILURE); // emergency bailout } char seed[256]; size_t count = sizeof(seed); while (count > 0) { count -= fread(&seed, 1, count, urandom); } fclose(urandom); rc4_init(&entropy_pool); rc4_schedule(&entropy_pool, seed, sizeof(seed)); rc4_skip(&entropy_pool, 4096); }
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, struct wpa_eapol_key *key, u16 ver) { u16 keydatalen = WPA_GET_BE16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",(u8 *) (key + 1), keydatalen); if (!sm->ptk_set) //wpa_supplicant_verify_eapol_key_mic ÖÐÉèÖÃ { lwip_log("WPA: PTK not available, cannot decrypt EAPOL-Key key data.\n"); return -1; } /* Decrypt key data here so that this operation does not need * to be implemented separately for each message type. */ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { u8 ek[32]; os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->ptk.kek, 16); rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { u8 buf[512]; if (keydatalen % 8) { lwip_log("WPA: Unsupported AES-WRAP len %d\n", keydatalen); return -1; } keydatalen -= 8; /* AES-WRAP adds 8 bytes */ if (buf == NULL) { lwip_log("WPA: No memory for AES-UNWRAP buffer\n"); return -1; } if (aes_unwrap(sm->ptk.kek, keydatalen / 8, (u8 *)(key + 1), buf)) { lwip_log("WPA: AES unwrap failed - could not decrypt EAPOL-Key key data\n"); return -1; } os_memcpy(key + 1, buf, keydatalen); WPA_PUT_BE16(key->key_data_length, keydatalen); } wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", (u8*)(key + 1), keydatalen); return 0; }
void rc4hash(struct rc4hash *hash, const char *password) { struct rc4 rc4; rc4_init(&rc4); rc4_schedule(&rc4, (char *) &hash->salt, sizeof(hash->salt)); /* Run scheduler 2^difficulty times. */ char buffer[256]; size_t length = strlen(password); memcpy(buffer, password, length); rc4_emit(&rc4, buffer + length, sizeof(buffer) - length); for (uint64_t i = 0; i < 1 << hash->difficulty; i++) { rc4_schedule(&rc4, buffer, sizeof(buffer)); } /* Skip (2^difficulty-1)*64 bytes of output. */ rc4_skip(&rc4, ((1 << hash->difficulty) - 1) * 64); /* Emit output. */ rc4_emit(&rc4, hash->hash, RC4HASH_SIZE - RC4HASH_HEADER_SIZE); }
static u8 * decrypt_eapol_key_data_rc4(const u8 *kek, const struct wpa_eapol_key *hdr, size_t *len) { u8 ek[32], *buf; u16 keydatalen = WPA_GET_BE16(hdr->key_data_length); buf = os_malloc(keydatalen); if (buf == NULL) return NULL; os_memcpy(ek, hdr->key_iv, 16); os_memcpy(ek + 16, kek, 16); os_memcpy(buf, hdr + 1, keydatalen); if (rc4_skip(ek, 32, 256, buf, keydatalen)) { wpa_printf(MSG_INFO, "RC4 failed"); os_free(buf); return NULL; } *len = keydatalen; return buf; }
static void eapol_sm_processKey(struct eapol_sm *sm) { struct ieee802_1x_hdr *hdr; struct ieee802_1x_eapol_key *key; struct eap_key_data keydata; u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32]; u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN]; int key_len, res, sign_key_len, encr_key_len; u16 rx_key_length; wpa_printf(MSG_DEBUG, "EAPOL: processKey"); if (sm->last_rx_key == NULL) return; if (!sm->conf.accept_802_1x_keys) { wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key" " even though this was not accepted - " "ignoring this packet"); return; } hdr = (struct ieee802_1x_hdr *) sm->last_rx_key; key = (struct ieee802_1x_eapol_key *) (hdr + 1); if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) { wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame"); return; } rx_key_length = WPA_GET_BE16(key->key_length); wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d " "EAPOL-Key: type=%d key_length=%d key_index=0x%x", hdr->version, hdr->type, be_to_host16(hdr->length), key->type, rx_key_length, key->key_index); eapol_sm_notify_lower_layer_success(sm, 1); sign_key_len = IEEE8021X_SIGN_KEY_LEN; encr_key_len = IEEE8021X_ENCR_KEY_LEN; res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata)); if (res < 0) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " "decrypting EAPOL-Key keys"); return; } if (res == 16) { /* LEAP derives only 16 bytes of keying material. */ res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); if (res) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " "master key for decrypting EAPOL-Key keys"); return; } sign_key_len = 16; encr_key_len = 16; os_memcpy(keydata.sign_key, keydata.encr_key, 16); } else if (res) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " "data for decrypting EAPOL-Key keys (res=%d)", res); return; } /* The key replay_counter must increase when same master key */ if (sm->replay_counter_valid && os_memcmp(sm->last_replay_counter, key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN) >= 0) { wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did " "not increase - ignoring key"); wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter", sm->last_replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter", key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); return; } /* Verify key signature (HMAC-MD5) */ os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN); hmac_md5(keydata.sign_key, sign_key_len, sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), key->key_signature); if (os_memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " "EAPOL-Key packet"); os_memcpy(key->key_signature, orig_key_sign, IEEE8021X_KEY_SIGN_LEN); return; } wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); key_len = be_to_host16(hdr->length) - sizeof(*key); if (key_len > 32 || rx_key_length > 32) { wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d", key_len ? key_len : rx_key_length); return; } if (key_len == rx_key_length) { os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, encr_key_len); os_memcpy(datakey, key + 1, key_len); rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0, datakey, key_len); wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key", datakey, key_len); } else if (key_len == 0) { /* * IEEE 802.1X-2004 specifies that least significant Key Length * octets from MS-MPPE-Send-Key are used as the key if the key * data is not present. This seems to be meaning the beginning * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator. * Anyway, taking the beginning of the keying material from EAP * seems to interoperate with Authenticators. */ key_len = rx_key_length; os_memcpy(datakey, keydata.encr_key, key_len); wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying " "material data encryption key", datakey, key_len); } else { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " "(key_length=%d)", key_len, rx_key_length); return; } sm->replay_counter_valid = TRUE; os_memcpy(sm->last_replay_counter, key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " "len %d", key->key_index & IEEE8021X_KEY_INDEX_FLAG ? "unicast" : "broadcast", key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); if (sm->ctx->set_wep_key && sm->ctx->set_wep_key(sm->ctx->ctx, key->key_index & IEEE8021X_KEY_INDEX_FLAG, key->key_index & IEEE8021X_KEY_INDEX_MASK, datakey, key_len) < 0) { wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " " driver."); } else { if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) sm->unicast_key_received = TRUE; else sm->broadcast_key_received = TRUE; if ((sm->unicast_key_received || !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) && (sm->broadcast_key_received || !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST))) { wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " "frames received"); sm->portValid = TRUE; if (sm->ctx->eapol_done_cb) sm->ctx->eapol_done_cb(sm->ctx->ctx); } } }
int fast_crypto_cipher_decrypt(struct crypto_cipher *ctx, const uint8_t *crypt, uint8_t *plain, size_t len) { size_t i, j, blocks; uint8_t tmp[32]; struct fast_crypto_cipher *fast_ctx; fast_ctx = (struct fast_crypto_cipher *)ctx; switch (fast_ctx->alg) { case CRYPTO_CIPHER_ALG_RC4: if (plain != crypt) { os_memcpy(plain, crypt, len); } rc4_skip(fast_ctx->u.rc4.key, fast_ctx->u.rc4.keylen, fast_ctx->u.rc4.used_bytes, plain, len); fast_ctx->u.rc4.used_bytes += len; break; case CRYPTO_CIPHER_ALG_AES: if (len % AES_BLOCK_SIZE) { return -1; } blocks = len / AES_BLOCK_SIZE; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, AES_BLOCK_SIZE); mbedtls_aes_decrypt(&(fast_ctx->u.aes.ctx_dec), crypt, plain); for (j = 0; j < AES_BLOCK_SIZE; j++) plain[j] ^= fast_ctx->u.aes.cbc[j]; os_memcpy(fast_ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE); plain += AES_BLOCK_SIZE; crypt += AES_BLOCK_SIZE; } break; #ifdef CONFIG_DES3 case CRYPTO_CIPHER_ALG_3DES: if (len % 8) { return -1; } blocks = len / 8; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, 8); des3_decrypt(crypt, &fast_ctx->u.des3.key, plain); for (j = 0; j < 8; j++) { plain[j] ^= fast_ctx->u.des3.cbc[j]; } os_memcpy(fast_ctx->u.des3.cbc, tmp, 8); plain += 8; crypt += 8; } break; #endif #ifdef CONFIG_DES case CRYPTO_CIPHER_ALG_DES: if (len % 8) { return -1; } blocks = len / 8; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, 8); des_block_decrypt(crypt, fast_ctx->u.des.dk, plain); for (j = 0; j < 8; j++) { plain[j] ^= fast_ctx->u.des.cbc[j]; } os_memcpy(fast_ctx->u.des.cbc, tmp, 8); plain += 8; crypt += 8; } break; #endif default: return -1; } return 0; }
/** * cckm_egtk_to_gtk - Calculate GTK from Encrypted GTK * @cckm_rn: Association Request Numner * @gtk: Length of BTK * @gtk_len: Length of GTK * * GTK = RC4(RN | PTK-802.1X-Encrypt-Key, EGTK) * GTK = AES-Keywrap(PTK-802.1X-Encrypt-Key, EGTK) * - where PTK-802.1X-Encrypt-Key is the key as defined in Section 0 * - Note that while the IV is not transmitted in the clear, its encrypted * value is included in the EGTK. Thus, the EGTK length shall be the GTK * key length plus 8 octets (e.g. the IV length). More explicitly, if the * broadcast cipher is TKIP, while the GTK is 32 octets, the EGTK shall * be 40 octets; similarly for AESCCMP, the GTK is 16 octets while the * EGTK shall be 24 octets. */ static int cckm_install_gtk(struct wpa_sm *sm, u32 cckm_rn, u8 *gtk, int gtk_len, int keyidx, const u8 *key_rsc, int key_rsc_len) { u8 gtk_buf[32]; enum wpa_alg alg; switch (sm->group_cipher) { case WPA_CIPHER_CCMP: alg = WPA_ALG_CCMP; break; case WPA_CIPHER_TKIP: alg = WPA_ALG_TKIP; break; case WPA_CIPHER_NONE: wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: " "NONE - do not use pairwise keys"); return 0; default: wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d", sm->pairwise_cipher); return -1; } if (sm->group_cipher == WPA_CIPHER_CCMP) { gtk_len -= 8; if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk, gtk_buf)) { wpa_printf(MSG_WARNING, "WPA: AES unwrap " "failed - could not decrypt GTK"); return -1; } gtk = gtk_buf; } else if (sm->group_cipher == WPA_CIPHER_TKIP) { u8 data[20]; WPA_PUT_LE32(data, cckm_rn); os_memcpy(data + 4, &sm->ptk.kek, sizeof(sm->ptk.kek)); wpa_hexdump_key(MSG_DEBUG, "EGTK-Data", data, sizeof(data)); rc4_skip(data, sizeof(data), 256, gtk, gtk_len); /* Swap Tx/Rx keys for Michael MIC */ os_memcpy(gtk_buf, gtk, 16); os_memcpy(gtk_buf + 16, gtk + 24, 8); os_memcpy(gtk_buf + 24, gtk + 16, 8); gtk = gtk_buf; } wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gtk, gtk_len); wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver " "(keyidx=%d tx=%d len=%d).", keyidx, 0, gtk_len); wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, key_rsc_len); if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff", keyidx, 0, key_rsc, key_rsc_len, gtk, gtk_len) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to " "the driver."); return -1; } return 0; }
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { size_t i, j, blocks; switch (ctx->alg) { case CRYPTO_CIPHER_ALG_RC4: if (plain != crypt) os_memcpy(crypt, plain, len); rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, ctx->u.rc4.used_bytes, crypt, len); ctx->u.rc4.used_bytes += len; break; case CRYPTO_CIPHER_ALG_AES: if (len % AES_BLOCK_SIZE) return -1; blocks = len / AES_BLOCK_SIZE; for (i = 0; i < blocks; i++) { for (j = 0; j < AES_BLOCK_SIZE; j++) ctx->u.aes.cbc[j] ^= plain[j]; aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, ctx->u.aes.cbc); os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE); plain += AES_BLOCK_SIZE; crypt += AES_BLOCK_SIZE; } break; case CRYPTO_CIPHER_ALG_3DES: if (len % 8) return -1; blocks = len / 8; for (i = 0; i < blocks; i++) { for (j = 0; j < 8; j++) ctx->u.des3.cbc[j] ^= plain[j]; des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, ctx->u.des3.cbc); os_memcpy(crypt, ctx->u.des3.cbc, 8); plain += 8; crypt += 8; } break; case CRYPTO_CIPHER_ALG_DES: if (len % 8) return -1; blocks = len / 8; for (i = 0; i < blocks; i++) { for (j = 0; j < 8; j++) ctx->u.des3.cbc[j] ^= plain[j]; des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek, ctx->u.des.cbc); os_memcpy(crypt, ctx->u.des.cbc, 8); plain += 8; crypt += 8; } break; default: return -1; } return 0; }
/** * rc4 - XOR RC4 stream to given data * @buf: data to be XOR'ed with RC4 stream * @len: buf length * @key: RC4 key * @key_len: RC4 key length * * Generate RC4 pseudo random stream for the given key and XOR this with the * data buffer to perform RC4 encryption/decryption. */ void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len) { rc4_skip(key, key_len, 0, buf, len); }
static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, const struct wpa_eapol_key *key, size_t keydatalen, int key_info, size_t extra_len, u16 ver, struct wpa_gtk_data *gd) { size_t maxkeylen; u8 ek[32]; gd->gtk_len = WPA_GET_BE16(key->key_length); maxkeylen = keydatalen; if (keydatalen > extra_len) { wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:" " key_data_length=%lu > extra_len=%lu", (unsigned long) keydatalen, (unsigned long) extra_len); return -1; } if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { if (maxkeylen < 8) { wpa_printf(MSG_INFO, "WPA: Too short maxkeylen (%lu)", (unsigned long) maxkeylen); return -1; } maxkeylen -= 8; } if (wpa_supplicant_check_group_cipher(sm->group_cipher, gd->gtk_len, maxkeylen, &gd->key_rsc_len, &gd->alg)) return -1; gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> WPA_KEY_INFO_KEY_INDEX_SHIFT; if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->ptk.kek, 16); if (keydatalen > sizeof(gd->gtk)) { wpa_printf(MSG_WARNING, "WPA: RC4 key data " "too long (%lu)", (unsigned long) keydatalen); return -1; } os_memcpy(gd->gtk, key + 1, keydatalen); if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { wpa_printf(MSG_ERROR, "WPA: RC4 failed"); return -1; } } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { if (keydatalen % 8) { wpa_printf(MSG_WARNING, "WPA: Unsupported AES-WRAP " "len %lu", (unsigned long) keydatalen); return -1; } if (maxkeylen > sizeof(gd->gtk)) { wpa_printf(MSG_WARNING, "WPA: AES-WRAP key data " "too long (keydatalen=%lu maxkeylen=%lu)", (unsigned long) keydatalen, (unsigned long) maxkeylen); return -1; } if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, (const u8 *) (key + 1), gd->gtk)) { wpa_printf(MSG_WARNING, "WPA: AES unwrap " "failed - could not decrypt GTK"); return -1; } } else { wpa_printf(MSG_WARNING, "WPA: Unsupported key_info type %d", ver); return -1; } gd->tx = wpa_supplicant_gtk_tx_bit_workaround( sm, !!(key_info & WPA_KEY_INFO_TXRX)); return 0; }