📄 ikev2_common.c
字号:
/* * IKEv2 common routines for initiator and responder * Copyright (c) 2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#include "sha1.h"#include "md5.h"#include "crypto.h"#include "ikev2_common.h"static struct ikev2_integ_alg ikev2_integ_algs[] = { { AUTH_HMAC_SHA1_96, 20, 12 }, { AUTH_HMAC_MD5_96, 16, 12 }};#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))static struct ikev2_prf_alg ikev2_prf_algs[] = { { PRF_HMAC_SHA1, 20, 20 }, { PRF_HMAC_MD5, 16, 16 }};#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))static struct ikev2_encr_alg ikev2_encr_algs[] = { { ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */ { ENCR_3DES, 24, 8 }};#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))const struct ikev2_integ_alg * ikev2_get_integ(int id){ size_t i; for (i = 0; i < NUM_INTEG_ALGS; i++) { if (ikev2_integ_algs[i].id == id) return &ikev2_integ_algs[i]; } return NULL;}int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *hash){ u8 tmphash[IKEV2_MAX_HASH_LEN]; switch (alg) { case AUTH_HMAC_SHA1_96: if (key_len != 20) return -1; hmac_sha1(key, key_len, data, data_len, tmphash); os_memcpy(hash, tmphash, 12); break; case AUTH_HMAC_MD5_96: if (key_len != 16) return -1; hmac_md5(key, key_len, data, data_len, tmphash); os_memcpy(hash, tmphash, 12); break; default: return -1; } return 0;}const struct ikev2_prf_alg * ikev2_get_prf(int id){ size_t i; for (i = 0; i < NUM_PRF_ALGS; i++) { if (ikev2_prf_algs[i].id == id) return &ikev2_prf_algs[i]; } return NULL;}int ikev2_prf_hash(int alg, const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *hash){ switch (alg) { case PRF_HMAC_SHA1: hmac_sha1_vector(key, key_len, num_elem, addr, len, hash); break; case PRF_HMAC_MD5: hmac_md5_vector(key, key_len, num_elem, addr, len, hash); break; default: return -1; } return 0;}int ikev2_prf_plus(int alg, const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *out, size_t out_len){ u8 hash[IKEV2_MAX_HASH_LEN]; size_t hash_len; u8 iter, *pos, *end; const u8 *addr[3]; size_t len[3]; const struct ikev2_prf_alg *prf; int res; prf = ikev2_get_prf(alg); if (prf == NULL) return -1; hash_len = prf->hash_len; addr[0] = hash; len[0] = hash_len; addr[1] = data; len[1] = data_len; addr[2] = &iter; len[2] = 1; pos = out; end = out + out_len; iter = 1; while (pos < end) { size_t clen; if (iter == 1) res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1], &len[1], hash); else res = ikev2_prf_hash(alg, key, key_len, 3, addr, len, hash); if (res < 0) return -1; clen = hash_len; if ((int) clen > end - pos) clen = end - pos; os_memcpy(pos, hash, clen); pos += clen; iter++; } return 0;}const struct ikev2_encr_alg * ikev2_get_encr(int id){ size_t i; for (i = 0; i < NUM_ENCR_ALGS; i++) { if (ikev2_encr_algs[i].id == id) return &ikev2_encr_algs[i]; } return NULL;}#ifdef CCNS_PL/* from des.c */struct des3_key_s { u32 ek[3][32]; u32 dk[3][32];};void des3_key_setup(const u8 *key, struct des3_key_s *dkey);void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);#endif /* CCNS_PL */int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, const u8 *plain, u8 *crypt, size_t len){ struct crypto_cipher *cipher; int encr_alg;#ifdef CCNS_PL if (alg == ENCR_3DES) { struct des3_key_s des3key; size_t i, blocks; u8 *pos; /* ECB mode is used incorrectly for 3DES!? */ if (key_len != 24) { wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); return -1; } des3_key_setup(key, &des3key); blocks = len / 8; pos = crypt; for (i = 0; i < blocks; i++) { des3_encrypt(pos, &des3key, pos); pos += 8; } } else {#endif /* CCNS_PL */ switch (alg) { case ENCR_3DES: encr_alg = CRYPTO_CIPHER_ALG_3DES; break; case ENCR_AES_CBC: encr_alg = CRYPTO_CIPHER_ALG_AES; break; default: wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); return -1; } cipher = crypto_cipher_init(encr_alg, iv, key, key_len); if (cipher == NULL) { wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); return -1; } if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) { wpa_printf(MSG_INFO, "IKEV2: Encryption failed"); crypto_cipher_deinit(cipher); return -1; } crypto_cipher_deinit(cipher);#ifdef CCNS_PL }#endif /* CCNS_PL */ return 0;}int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, const u8 *crypt, u8 *plain, size_t len){ struct crypto_cipher *cipher; int encr_alg;#ifdef CCNS_PL if (alg == ENCR_3DES) { struct des3_key_s des3key; size_t i, blocks; /* ECB mode is used incorrectly for 3DES!? */ if (key_len != 24) { wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); return -1; } des3_key_setup(key, &des3key); if (len % 8) { wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted " "length"); return -1; } blocks = len / 8; for (i = 0; i < blocks; i++) { des3_decrypt(crypt, &des3key, plain); plain += 8; crypt += 8; } } else {#endif /* CCNS_PL */ switch (alg) { case ENCR_3DES: encr_alg = CRYPTO_CIPHER_ALG_3DES; break; case ENCR_AES_CBC: encr_alg = CRYPTO_CIPHER_ALG_AES; break; default: wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); return -1; } cipher = crypto_cipher_init(encr_alg, iv, key, key_len); if (cipher == NULL) { wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); return -1; } if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); crypto_cipher_deinit(cipher); return -1; } crypto_cipher_deinit(cipher);#ifdef CCNS_PL }#endif /* CCNS_PL */ return 0;}int ikev2_parse_payloads(struct ikev2_payloads *payloads, u8 next_payload, const u8 *pos, const u8 *end){ const struct ikev2_payload_hdr *phdr; os_memset(payloads, 0, sizeof(*payloads)); while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) { int plen, pdatalen; const u8 *pdata; wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u", next_payload); if (end - pos < (int) sizeof(*phdr)) { wpa_printf(MSG_INFO, "IKEV2: Too short message for " "payload header (left=%ld)", (long) (end - pos)); } phdr = (const struct ikev2_payload_hdr *) pos; plen = WPA_GET_BE16(phdr->payload_length); if (plen < (int) sizeof(*phdr) || pos + plen > end) { wpa_printf(MSG_INFO, "IKEV2: Invalid payload header " "length %d", plen); return -1; } wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x" " Payload Length: %d", phdr->next_payload, phdr->flags, plen); pdata = (const u8 *) (phdr + 1); pdatalen = plen - sizeof(*phdr); switch (next_payload) { case IKEV2_PAYLOAD_SA: wpa_printf(MSG_DEBUG, "IKEV2: Payload: Security " "Association"); payloads->sa = pdata; payloads->sa_len = pdatalen; break; case IKEV2_PAYLOAD_KEY_EXCHANGE: wpa_printf(MSG_DEBUG, "IKEV2: Payload: Key " "Exchange"); payloads->ke = pdata; payloads->ke_len = pdatalen; break; case IKEV2_PAYLOAD_IDi: wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDi"); payloads->idi = pdata; payloads->idi_len = pdatalen; break; case IKEV2_PAYLOAD_IDr: wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDr"); payloads->idr = pdata; payloads->idr_len = pdatalen; break; case IKEV2_PAYLOAD_CERTIFICATE: wpa_printf(MSG_DEBUG, "IKEV2: Payload: Certificate"); payloads->cert = pdata; payloads->cert_len = pdatalen; break; case IKEV2_PAYLOAD_AUTHENTICATION: wpa_printf(MSG_DEBUG, "IKEV2: Payload: " "Authentication"); payloads->auth = pdata; payloads->auth_len = pdatalen; break; case IKEV2_PAYLOAD_NONCE: wpa_printf(MSG_DEBUG, "IKEV2: Payload: Nonce"); payloads->nonce = pdata; payloads->nonce_len = pdatalen; break; case IKEV2_PAYLOAD_ENCRYPTED: wpa_printf(MSG_DEBUG, "IKEV2: Payload: Encrypted"); payloads->encrypted = pdata; payloads->encrypted_len = pdatalen; break; case IKEV2_PAYLOAD_NOTIFICATION: wpa_printf(MSG_DEBUG, "IKEV2: Payload: " "Notification"); payloads->notification = pdata; payloads->notification_len = pdatalen; break; default: if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -