/* Add User-Password attribute to a RADIUS message and encrypt it as specified * in RFC 2865, Chap. 5.2 */ struct radius_attr_hdr * radius_msg_add_attr_user_password(struct radius_msg *msg, u8 *data, size_t data_len, u8 *secret, size_t secret_len) { u8 buf[128]; int padlen, i; size_t buf_len, pos; const u8 *addr[2]; size_t len[2]; u8 hash[16]; if (data_len > 128) return NULL; os_memcpy(buf, data, data_len); buf_len = data_len; padlen = data_len % 16; if (padlen) { padlen = 16 - padlen; os_memset(buf + data_len, 0, padlen); buf_len += padlen; } addr[0] = secret; len[0] = secret_len; addr[1] = msg->hdr->authenticator; len[1] = 16; md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[i] ^= hash[i]; pos = 16; while (pos < buf_len) { addr[0] = secret; len[0] = secret_len; addr[1] = &buf[pos - 16]; len[1] = 16; md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[pos + i] ^= hash[i]; pos += 16; } return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, buf, buf_len); }
int radius_user_password_hide(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len, u8 *buf, size_t buf_len) { size_t padlen, i, pos; const u8 *addr[2]; size_t len[2]; u8 hash[16]; if (data_len + 16 > buf_len) return -1; os_memcpy(buf, data, data_len); padlen = data_len % 16; if (padlen && data_len < buf_len) { padlen = 16 - padlen; os_memset(buf + data_len, 0, padlen); buf_len = data_len + padlen; } else { buf_len = data_len; } addr[0] = secret; len[0] = secret_len; addr[1] = msg->hdr->authenticator; len[1] = 16; md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[i] ^= hash[i]; pos = 16; while (pos < buf_len) { addr[0] = secret; len[0] = secret_len; addr[1] = &buf[pos - 16]; len[1] = 16; md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[pos + i] ^= hash[i]; pos += 16; } return buf_len; }
int radius_msg_verify(struct radius_msg *msg, const u8 *secret, size_t secret_len, struct radius_msg *sent_msg, int auth) { const u8 *addr[4]; size_t len[4]; u8 hash[MD5_MAC_LEN]; if (sent_msg == NULL) { printf("No matching Access-Request message found\n"); return 1; } if (auth && radius_msg_verify_msg_auth(msg, secret, secret_len, sent_msg->hdr->authenticator)) { return 1; } /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; len[0] = 1 + 1 + 2; addr[1] = sent_msg->hdr->authenticator; len[1] = MD5_MAC_LEN; addr[2] = (u8 *) (msg->hdr + 1); len[2] = msg->buf_used - sizeof(*msg->hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, hash); if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { printf("Response Authenticator invalid!\n"); return 1; } return 0; }
int radius_msg_verify(struct radius_msg *msg, const u8 *secret, size_t secret_len, struct radius_msg *sent_msg, int auth) { const u8 *addr[4]; size_t len[4]; u8 hash[MD5_MAC_LEN]; if (sent_msg == NULL) { wpa_printf(MSG_INFO, "No matching Access-Request message found"); return 1; } if (auth && radius_msg_verify_msg_auth(msg, secret, secret_len, sent_msg->hdr->authenticator)) { return 1; } /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; len[0] = 1 + 1 + 2; addr[1] = sent_msg->hdr->authenticator; len[1] = MD5_MAC_LEN; addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); addr[3] = secret; len[3] = secret_len; if (md5_vector(4, addr, len, hash) < 0 || os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "Response Authenticator invalid!"); return 1; } return 0; }
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, size_t secret_len) { const u8 *addr[4]; size_t len[4]; u8 zero[MD5_MAC_LEN]; u8 hash[MD5_MAC_LEN]; u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; u8 orig_authenticator[16]; struct radius_attr_hdr *attr = NULL, *tmp; size_t i; os_memset(zero, 0, sizeof(zero)); addr[0] = (u8 *) msg->hdr; len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; addr[1] = zero; len[1] = MD5_MAC_LEN; addr[2] = (u8 *) (msg->hdr + 1); len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, hash); if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) return 1; for (i = 0; i < msg->attr_used; i++) { tmp = radius_get_attr_hdr(msg, i); if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { if (attr != NULL) { wpa_printf(MSG_WARNING, "Multiple " "Message-Authenticator attributes " "in RADIUS message"); return 1; } attr = tmp; } } if (attr == NULL) { /* Message-Authenticator is MAY; not required */ return 0; } os_memcpy(orig, attr + 1, MD5_MAC_LEN); os_memset(attr + 1, 0, MD5_MAC_LEN); os_memcpy(orig_authenticator, msg->hdr->authenticator, sizeof(orig_authenticator)); os_memset(msg->hdr->authenticator, 0, sizeof(msg->hdr->authenticator)); hmac_md5(secret, secret_len, wpabuf_head(msg->buf), wpabuf_len(msg->buf), auth); os_memcpy(attr + 1, orig, MD5_MAC_LEN); os_memcpy(msg->hdr->authenticator, orig_authenticator, sizeof(orig_authenticator)); return os_memcmp(orig, auth, MD5_MAC_LEN) != 0; }
static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_leap_data *data = priv; u8 *key, pw_hash_hash[16], pw_hash[16]; const u8 *addr[5], *password; size_t elen[5], password_len; int pwhash; if (data->state != LEAP_DONE) return NULL; password = eap_get_config_password2(sm, &password_len, &pwhash); if (password == NULL) return NULL; key = os_malloc(LEAP_KEY_LEN); if (key == NULL) return NULL; if (pwhash) { if (hash_nt_password_hash(password, pw_hash_hash)) { os_free(key); return NULL; } } else { if (nt_password_hash(password, password_len, pw_hash) || hash_nt_password_hash(pw_hash, pw_hash_hash)) { os_free(key); return NULL; } } wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", pw_hash_hash, 16); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", data->peer_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", data->peer_response, LEAP_RESPONSE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", data->ap_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", data->ap_response, LEAP_RESPONSE_LEN); addr[0] = pw_hash_hash; elen[0] = 16; addr[1] = data->ap_challenge; elen[1] = LEAP_CHALLENGE_LEN; addr[2] = data->ap_response; elen[2] = LEAP_RESPONSE_LEN; addr[3] = data->peer_challenge; elen[3] = LEAP_CHALLENGE_LEN; addr[4] = data->peer_response; elen[4] = LEAP_RESPONSE_LEN; md5_vector(5, addr, elen, key); wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); *len = LEAP_KEY_LEN; return key; }
int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, size_t challenge_len, u8 *response) { const u8 *addr[3]; size_t len[3]; addr[0] = &id; len[0] = 1; addr[1] = secret; len[1] = secret_len; addr[2] = challenge; len[2] = challenge_len; return md5_vector(3, addr, len, response); }
static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, const u8 *req_authenticator, const u8 *secret, size_t secret_len, u8 *ebuf, size_t *elen) { int i, len, first = 1; u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; const u8 *addr[3]; size_t _len[3]; saltbuf[0] = salt >> 8; saltbuf[1] = salt; len = 1 + key_len; if (len & 0x0f) { len = (len & 0xf0) + 16; } os_memset(ebuf, 0, len); ebuf[0] = key_len; os_memcpy(ebuf + 1, key, key_len); *elen = len; pos = ebuf; while (len > 0) { /* b(1) = MD5(Secret + Request-Authenticator + Salt) * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ addr[0] = secret; _len[0] = secret_len; if (first) { addr[1] = req_authenticator; _len[1] = MD5_MAC_LEN; addr[2] = saltbuf; _len[2] = sizeof(saltbuf); } else { addr[1] = pos - MD5_MAC_LEN; _len[1] = MD5_MAC_LEN; } md5_vector(first ? 3 : 2, addr, _len, hash); first = 0; for (i = 0; i < MD5_MAC_LEN; i++) *pos++ ^= hash[i]; len -= MD5_MAC_LEN; } }
/* Create Request Authenticator. The value should be unique over the lifetime * of the shared secret between authenticator and authentication server. * Use one-way MD5 hash calculated from current timestamp and some data given * by the caller. */ void radius_msg_make_authenticator(struct radius_msg *msg, u8 *data, size_t len) { struct timeval tv; long int l; const u8 *addr[3]; size_t elen[3]; gettimeofday(&tv, NULL); l = random(); addr[0] = (u8 *) &tv; elen[0] = sizeof(tv); addr[1] = data; elen[1] = len; addr[2] = (u8 *) &l; elen[2] = sizeof(l); md5_vector(3, addr, elen, msg->hdr->authenticator); }
/* Create Request Authenticator. The value should be unique over the lifetime * of the shared secret between authenticator and authentication server. * Use one-way MD5 hash calculated from current timestamp and some data given * by the caller. */ void radius_msg_make_authenticator(struct radius_msg *msg, const u8 *data, size_t len) { struct os_time tv; long int l; const u8 *addr[3]; size_t elen[3]; os_get_time(&tv); l = os_random(); addr[0] = (u8 *) &tv; elen[0] = sizeof(tv); addr[1] = data; elen[1] = len; addr[2] = (u8 *) &l; elen[2] = sizeof(l); md5_vector(3, addr, elen, msg->hdr->authenticator); }
static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_leap_data *data = priv; struct wpa_ssid *config = eap_get_config(sm); u8 *key, pw_hash_hash[16], pw_hash[16]; const u8 *addr[5]; size_t elen[5]; if (data->state != LEAP_DONE) return NULL; key = malloc(LEAP_KEY_LEN); if (key == NULL) return NULL; nt_password_hash(config->password, config->password_len, pw_hash); hash_nt_password_hash(pw_hash, pw_hash_hash); wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", pw_hash_hash, 16); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", data->peer_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", data->peer_response, LEAP_RESPONSE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", data->ap_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", data->ap_response, LEAP_RESPONSE_LEN); addr[0] = pw_hash_hash; elen[0] = 16; addr[1] = data->ap_challenge; elen[1] = LEAP_CHALLENGE_LEN; addr[2] = data->ap_response; elen[2] = LEAP_RESPONSE_LEN; addr[3] = data->peer_challenge; elen[3] = LEAP_CHALLENGE_LEN; addr[4] = data->peer_response; elen[4] = LEAP_RESPONSE_LEN; md5_vector(5, addr, elen, key); wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); *len = LEAP_KEY_LEN; return key; }
static void eap_md5_process(struct eap_sm *sm, void *priv, u8 *respData, size_t respDataLen) { struct eap_md5_data *data = priv; struct eap_hdr *resp; const u8 *pos; const u8 *addr[3]; size_t len[3], plen; u8 hash[MD5_MAC_LEN]; if (sm->user == NULL || sm->user->password == NULL || sm->user->password_hash) { wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " "configured"); data->state = FAILURE; return; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, respDataLen, &plen); if (pos == NULL || *pos != MD5_MAC_LEN || plen < 1 + MD5_MAC_LEN) return; /* Should not happen - frame already validated */ pos++; /* Skip response len */ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN); resp = (struct eap_hdr *) respData; addr[0] = &resp->identifier; len[0] = 1; addr[1] = sm->user->password; len[1] = sm->user->password_len; addr[2] = data->challenge; len[2] = CHALLENGE_LEN; md5_vector(3, addr, len, hash); if (memcmp(hash, pos, MD5_MAC_LEN) == 0) { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); data->state = SUCCESS; } else { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure"); data->state = FAILURE; } }
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, size_t secret_len, const u8 *req_authenticator) { u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; const u8 *addr[4]; size_t len[4]; if (msg->hdr->code != RADIUS_CODE_ACCOUNTING_RESPONSE) { os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { fd_log_debug("WARNING: Could not add Message-Authenticator"); return -1; } msg->hdr->length = htons(msg->buf_used); os_memcpy(msg->hdr->authenticator, req_authenticator, sizeof(msg->hdr->authenticator)); hmac_md5(secret, secret_len, msg->buf, msg->buf_used, (u8 *) (attr + 1)); } else { msg->hdr->length = htons(msg->buf_used); } /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; len[0] = 1 + 1 + 2; addr[1] = req_authenticator; len[1] = MD5_MAC_LEN; addr[2] = (u8 *) (msg->hdr + 1); len[2] = msg->buf_used - sizeof(*msg->hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, msg->hdr->authenticator); if (msg->buf_used > 0xffff) { fd_log_debug("WARNING: too long RADIUS message (%lu)", (unsigned long) msg->buf_used); return -1; } return 0; }
void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret, size_t secret_len) { const u8 *addr[2]; size_t len[2]; msg->hdr->length = htons(msg->buf_used); os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); addr[0] = msg->buf; len[0] = msg->buf_used; addr[1] = secret; len[1] = secret_len; md5_vector(2, addr, len, msg->hdr->authenticator); if (msg->buf_used > 0xffff) { printf("WARNING: too long RADIUS messages (%lu)\n", (unsigned long) msg->buf_used); } }
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, size_t secret_len) { const u8 *addr[2]; size_t len[2]; msg->hdr->length = htons(wpabuf_len(msg->buf)); os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); addr[0] = wpabuf_head(msg->buf); len[0] = wpabuf_len(msg->buf); addr[1] = secret; len[1] = secret_len; md5_vector(2, addr, len, msg->hdr->authenticator); if (wpabuf_len(msg->buf) > 0xffff) { wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", (unsigned long) wpabuf_len(msg->buf)); } }
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, size_t secret_len) { const u8 *addr[4]; size_t len[4]; u8 zero[MD5_MAC_LEN]; u8 hash[MD5_MAC_LEN]; os_memset(zero, 0, sizeof(zero)); addr[0] = (u8 *) msg->hdr; len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; addr[1] = zero; len[1] = MD5_MAC_LEN; addr[2] = (u8 *) (msg->hdr + 1); len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, hash); return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; }
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, size_t secret_len, const u8 *req_authenticator) { u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; const u8 *addr[4]; size_t len[4]; os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { printf("WARNING: Could not add Message-Authenticator\n"); return -1; } msg->hdr->length = htons(wpabuf_len(msg->buf)); os_memcpy(msg->hdr->authenticator, req_authenticator, sizeof(msg->hdr->authenticator)); hmac_md5(secret, secret_len, wpabuf_head(msg->buf), wpabuf_len(msg->buf), (u8 *) (attr + 1)); /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; len[0] = 1 + 1 + 2; addr[1] = req_authenticator; len[1] = MD5_MAC_LEN; addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, msg->hdr->authenticator); if (wpabuf_len(msg->buf) > 0xffff) { wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", (unsigned long) wpabuf_len(msg->buf)); return -1; } return 0; }
int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, size_t secret_len, const struct radius_hdr *req_hdr) { const u8 *addr[2]; size_t len[2]; u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); return -1; } msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); hmac_md5(secret, secret_len, wpabuf_head(msg->buf), wpabuf_len(msg->buf), (u8 *) (attr + 1)); /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = wpabuf_head_u8(msg->buf); len[0] = wpabuf_len(msg->buf); addr[1] = secret; len[1] = secret_len; if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) return -1; if (wpabuf_len(msg->buf) > 0xffff) { wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", (unsigned long) wpabuf_len(msg->buf)); return -1; } return 0; }
static u8 * decrypt_ms_key(const u8 *key, size_t len, const u8 *req_authenticator, const u8 *secret, size_t secret_len, size_t *reslen) { u8 *plain, *ppos, *res; const u8 *pos; size_t left, plen; u8 hash[MD5_MAC_LEN]; int i, first = 1; const u8 *addr[3]; size_t elen[3]; /* key: 16-bit salt followed by encrypted key info */ if (len < 2 + 16) return NULL; pos = key + 2; left = len - 2; if (left % 16) { printf("Invalid ms key len %lu\n", (unsigned long) left); return NULL; } plen = left; ppos = plain = os_malloc(plen); if (plain == NULL) return NULL; while (left > 0) { /* b(1) = MD5(Secret + Request-Authenticator + Salt) * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ addr[0] = secret; elen[0] = secret_len; if (first) { addr[1] = req_authenticator; elen[1] = MD5_MAC_LEN; addr[2] = key; elen[2] = 2; /* Salt */ } else { addr[1] = pos - MD5_MAC_LEN; elen[1] = MD5_MAC_LEN; } md5_vector(first ? 3 : 2, addr, elen, hash); first = 0; for (i = 0; i < MD5_MAC_LEN; i++) *ppos++ = *pos++ ^ hash[i]; left -= MD5_MAC_LEN; } if (plain[0] > plen - 1) { printf("Failed to decrypt MPPE key\n"); os_free(plain); return NULL; } res = os_malloc(plain[0]); if (res == NULL) { os_free(plain); return NULL; } os_memcpy(res, plain + 1, plain[0]); if (reslen) *reslen = plain[0]; os_free(plain); return res; }
int main(int argc, char *argv[]) { struct { char *data; char *hash; } tests[] = { { "", "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04" "\xe9\x80\x09\x98\xec\xf8\x42\x7e" }, { "a", "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8" "\x31\xc3\x99\xe2\x69\x77\x26\x61" }, { "abc", "\x90\x01\x50\x98\x3c\xd2\x4f\xb0" "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72" }, { "message digest", "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d" "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0" }, { "abcdefghijklmnopqrstuvwxyz", "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00" "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b" }, { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789", "\xd1\x74\xab\x98\xd2\x77\xd9\xf5" "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f" }, { "12345678901234567890123456789012345678901234567890" "123456789012345678901234567890", "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55" "\xac\x49\xda\x2e\x21\x07\xb6\x7a" } }; unsigned int i; u8 hash[16]; const u8 *addr[2]; size_t len[2]; int errors = 0; for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { printf("MD5 test case %d:", i); addr[0] = (u8 *) tests[i].data; len[0] = strlen(tests[i].data); md5_vector(1, addr, len, hash); if (memcmp(hash, tests[i].hash, 16) != 0) { printf(" FAIL"); errors++; } else printf(" OK"); if (len[0]) { addr[0] = (u8 *) tests[i].data; len[0] = strlen(tests[i].data); addr[1] = (u8 *) tests[i].data + 1; len[1] = strlen(tests[i].data) - 1; md5_vector(1, addr, len, hash); if (memcmp(hash, tests[i].hash, 16) != 0) { printf(" FAIL"); errors++; } else printf(" OK"); } printf("\n"); } return errors; }
/** * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password * @msg: Received RADIUS message * @keylen: Length of returned password * @secret: RADIUS shared secret * @secret_len: Length of secret * @sent_msg: Sent RADIUS message * @n: Number of password attribute to return (starting with 0) * Returns: Pointer to n-th password (free with os_free) or %NULL */ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, const u8 *secret, size_t secret_len, struct radius_msg *sent_msg, size_t n) { u8 *buf = NULL; size_t buflen; const u8 *salt; u8 *str; const u8 *addr[3]; size_t len[3]; u8 hash[16]; u8 *pos; size_t i, j = 0; struct radius_attr_hdr *attr; const u8 *data; size_t dlen; const u8 *fdata = NULL; /* points to found item */ size_t fdlen = -1; char *ret = NULL; /* find n-th valid Tunnel-Password attribute */ for (i = 0; i < msg->attr_used; i++) { attr = radius_get_attr_hdr(msg, i); if (attr == NULL || attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { continue; } if (attr->length <= 5) continue; data = (const u8 *) (attr + 1); dlen = attr->length - sizeof(*attr); if (dlen <= 3 || dlen % 16 != 3) continue; j++; if (j <= n) continue; fdata = data; fdlen = dlen; break; } if (fdata == NULL) goto out; /* alloc writable memory for decryption */ buf = os_malloc(fdlen); if (buf == NULL) goto out; os_memcpy(buf, fdata, fdlen); buflen = fdlen; /* init pointers */ salt = buf + 1; str = buf + 3; /* decrypt blocks */ pos = buf + buflen - 16; /* last block */ while (pos >= str + 16) { /* all but the first block */ addr[0] = secret; len[0] = secret_len; addr[1] = pos - 16; len[1] = 16; md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) pos[i] ^= hash[i]; pos -= 16; } /* decrypt first block */ if (str != pos) goto out; addr[0] = secret; len[0] = secret_len; addr[1] = sent_msg->hdr->authenticator; len[1] = 16; addr[2] = salt; len[2] = 2; md5_vector(3, addr, len, hash); for (i = 0; i < 16; i++) pos[i] ^= hash[i]; /* derive plaintext length from first subfield */ *keylen = (unsigned char) str[0]; if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { /* decryption error - invalid key length */ goto out; } if (*keylen == 0) { /* empty password */ goto out; } /* copy passphrase into new buffer */ ret = os_malloc(*keylen); if (ret) os_memcpy(ret, str + 1, *keylen); out: /* return new buffer */ os_free(buf); return ret; }
void kr_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], const size_t *msg_lens, uint8_t *digest) { (void) md5_vector(num_msgs, msgs, msg_lens, digest); }
static u8 * eap_md5_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { const struct eap_hdr *req; struct eap_hdr *resp; const u8 *pos, *challenge, *password; u8 *rpos; size_t len, challenge_len, password_len; const u8 *addr[3]; size_t elen[3]; password = eap_get_config_password(sm, &password_len); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-MD5: Password not configured"); eap_sm_request_password(sm); ret->ignore = TRUE; return NULL; } pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, reqDataLen, &len); if (pos == NULL || len == 0) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)", pos, (unsigned long) len); ret->ignore = TRUE; return NULL; } /* * CHAP Challenge: * Value-Size (1 octet) | Value(Challenge) | Name(optional) */ req = (const struct eap_hdr *) reqData; challenge_len = *pos++; if (challenge_len == 0 || challenge_len > len - 1) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge " "(challenge_len=%lu len=%lu)", (unsigned long) challenge_len, (unsigned long) len); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; challenge = pos; wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", challenge, challenge_len); wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response"); ret->methodState = METHOD_DONE; ret->decision = DECISION_UNCOND_SUCC; ret->allowNotifications = TRUE; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, respDataLen, 1 + MD5_MAC_LEN, EAP_CODE_RESPONSE, req->identifier, &rpos); if (resp == NULL) return NULL; /* * CHAP Response: * Value-Size (1 octet) | Value(Response) | Name(optional) */ *rpos++ = MD5_MAC_LEN; addr[0] = &resp->identifier; elen[0] = 1; addr[1] = password; elen[1] = password_len; addr[2] = challenge; elen[2] = challenge_len; md5_vector(3, addr, elen, rpos); wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, MD5_MAC_LEN); return (u8 *) resp; }
/** * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (16 bytes) * Returns: 0 on success, -1 on failure */ int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { u8 k_pad[64]; /* padding - key XORd with ipad/opad */ u8 tk[16]; const u8 *_addr[6]; size_t i, _len[6]; if (num_elem > 5) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ return -1; } /* if key is longer than 64 bytes reset it to key = MD5(key) */ if (key_len > 64) { if (md5_vector(1, &key, &key_len, tk)) return -1; key = tk; key_len = 16; } /* the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in ipad */ os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with ipad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x36; /* perform inner MD5 */ _addr[0] = k_pad; _len[0] = 64; for (i = 0; i < num_elem; i++) { _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } if (md5_vector(1 + num_elem, _addr, _len, mac)) return -1; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with opad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x5c; /* perform outer MD5 */ _addr[0] = k_pad; _len[0] = 64; _addr[1] = mac; _len[1] = MD5_MAC_LEN; return md5_vector(2, _addr, _len, mac); }
static u8 * eap_md5_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { struct wpa_ssid *config = eap_get_config(sm); const struct eap_hdr *req; struct eap_hdr *resp; const u8 *pos, *challenge; u8 *rpos; size_t len, challenge_len; const u8 *addr[3]; size_t elen[3]; if (config == NULL || config->password == NULL) { wpa_printf(MSG_INFO, "EAP-MD5: Password not configured"); eap_sm_request_password(sm, config); ret->ignore = TRUE; return NULL; } pos = eap_hdr_validate(EAP_TYPE_MD5, reqData, reqDataLen, &len); if (pos == NULL) { ret->ignore = TRUE; return NULL; } req = (const struct eap_hdr *) reqData; challenge_len = *pos++; if (challenge_len == 0 || challenge_len > len - 1) { wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge " "(challenge_len=%lu len=%lu", (unsigned long) challenge_len, (unsigned long) len); ret->ignore = TRUE; return NULL; } ret->ignore = FALSE; challenge = pos; wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", challenge, challenge_len); wpa_printf(MSG_DEBUG, "EAP-MD5: generating Challenge Response"); ret->methodState = METHOD_DONE; ret->decision = DECISION_UNCOND_SUCC; ret->allowNotifications = TRUE; *respDataLen = sizeof(struct eap_hdr) + 1 + 1 + MD5_MAC_LEN; resp = malloc(*respDataLen); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = req->identifier; resp->length = host_to_be16(*respDataLen); rpos = (u8 *) (resp + 1); *rpos++ = EAP_TYPE_MD5; *rpos++ = MD5_MAC_LEN; /* Value-Size */ addr[0] = &resp->identifier; elen[0] = 1; addr[1] = config->password; elen[1] = config->password_len; addr[2] = challenge; elen[2] = challenge_len; md5_vector(3, addr, elen, rpos); wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, MD5_MAC_LEN); return (u8 *) resp; }
static int eap_ttls_phase2_request_chap(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, u8 **resp, size_t *resp_len) { struct wpa_ssid *config = eap_get_config(sm); u8 *buf, *pos, *challenge; const u8 *addr[3]; size_t len[3]; wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); pos = buf = os_malloc(config->identity_len + 1000); if (buf == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to allocate memory"); return -1; } /* User-Name */ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, config->identity, config->identity_len); /* CHAP-Challenge */ challenge = eap_ttls_implicit_challenge( sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); if (challenge == NULL) { os_free(buf); wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " "implicit challenge"); return -1; } pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); /* CHAP-Password */ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, 1 + EAP_TTLS_CHAP_PASSWORD_LEN); data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; *pos++ = data->ident; /* MD5(Ident + Password + Challenge) */ addr[0] = &data->ident; len[0] = 1; addr[1] = config->password; len[1] = config->password_len; addr[2] = challenge; len[2] = EAP_TTLS_CHAP_CHALLENGE_LEN; md5_vector(3, addr, len, pos); wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", config->identity, config->identity_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", config->password, config->password_len); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", pos, EAP_TTLS_CHAP_PASSWORD_LEN); pos += EAP_TTLS_CHAP_PASSWORD_LEN; os_free(challenge); AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; if (data->ttls_version > 0) { /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, * so do not allow connection to be terminated yet. */ ret->methodState = METHOD_CONT; ret->decision = DECISION_COND_SUCC; } else { /* EAP-TTLS/CHAP does not provide tunneled success * notification, so assume that Phase2 succeeds. */ ret->methodState = METHOD_DONE; ret->decision = DECISION_COND_SUCC; } return 0; }