void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk) { u8 hash[aes_block_size]; u8 counter = 1; int i; aes_128_encrypt_block(kdk, rand_p, hash); hash[aes_block_size - 1] ^= counter; aes_128_encrypt_block(kdk, hash, tek); hash[aes_block_size - 1] ^= counter; counter++; for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) { hash[aes_block_size - 1] ^= counter; aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]); hash[aes_block_size - 1] ^= counter; counter++; } }
/** * milenage_f1 - Milenage f1 and f1* algorithms * @opc: OPc = 128-bit value derived from OP and K * @k: K = 128-bit subscriber key * @_rand: RAND = 128-bit random challenge * @sqn: SQN = 48-bit sequence number * @amf: AMF = 16-bit authentication management field * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL * Returns: 0 on success, -1 on failure */ int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) { u8 tmp1[16], tmp2[16], tmp3[16]; int i; /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ for (i = 0; i < 16; i++) tmp1[i] = _rand[i] ^ opc[i]; if (aes_128_encrypt_block(k, tmp1, tmp1)) return -1; /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ os_memcpy(tmp2, sqn, 6); os_memcpy(tmp2 + 6, amf, 2); os_memcpy(tmp2 + 8, tmp2, 8); /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ for (i = 0; i < 16; i++) tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; /* XOR with TEMP = E_K(RAND XOR OP_C) */ for (i = 0; i < 16; i++) tmp3[i] ^= tmp1[i]; /* XOR with c1 (= ..00, i.e., NOP) */ /* f1 || f1* = E_K(tmp3) XOR OP_c */ if (aes_128_encrypt_block(k, tmp3, tmp1)) return -1; for (i = 0; i < 16; i++) tmp1[i] ^= opc[i]; if (mac_a) os_memcpy(mac_a, tmp1, 8); /* f1 */ if (mac_s) os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ return 0; }
/** Derive OPc from OP and Ki * * @param[out] opc The derived Operator Code used as an input to other Milenage * functions. * @param[in] op Operator Code. * @param[in] ki Subscriber key. * @return * - 0 on success. * - -1 on failure. */ int milenage_opc_generate(uint8_t opc[MILENAGE_OPC_SIZE], uint8_t const op[MILENAGE_OP_SIZE], uint8_t const ki[MILENAGE_KI_SIZE]) { int ret; uint8_t tmp[MILENAGE_OPC_SIZE]; EVP_CIPHER_CTX *evp_ctx; size_t i; evp_ctx = EVP_CIPHER_CTX_new(); if (!evp_ctx) { tls_strerror_printf("Failed allocating EVP context"); return -1; } ret = aes_128_encrypt_block(evp_ctx, ki, op, tmp); EVP_CIPHER_CTX_free(evp_ctx); if (ret < 0) return ret; for (i = 0; i < sizeof(tmp); i++) opc[i] = op[i] ^ tmp[i]; return 0; }
/** * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms * @opc: OPc = 128-bit value derived from OP and K * @k: K = 128-bit subscriber key * @_rand: RAND = 128-bit random challenge * @res: Buffer for RES = 64-bit signed response (f2), or %NULL * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL * Returns: 0 on success, -1 on failure */ int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) { u8 tmp1[16], tmp2[16], tmp3[16]; int i; /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ for (i = 0; i < 16; i++) tmp1[i] = _rand[i] ^ opc[i]; if (aes_128_encrypt_block(k, tmp1, tmp2)) return -1; /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ /* f2 and f5 */ /* rotate by r2 (= 0, i.e., NOP) */ for (i = 0; i < 16; i++) tmp1[i] = tmp2[i] ^ opc[i]; tmp1[15] ^= 1; /* XOR c2 (= ..01) */ /* f5 || f2 = E_K(tmp1) XOR OP_c */ if (aes_128_encrypt_block(k, tmp1, tmp3)) return -1; for (i = 0; i < 16; i++) tmp3[i] ^= opc[i]; if (res) os_memcpy(res, tmp3 + 8, 8); /* f2 */ if (ak) os_memcpy(ak, tmp3, 6); /* f5 */ /* f3 */ if (ck) { /* rotate by r3 = 0x20 = 4 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 2; /* XOR c3 (= ..02) */ if (aes_128_encrypt_block(k, tmp1, ck)) return -1; for (i = 0; i < 16; i++) ck[i] ^= opc[i]; } /* f4 */ if (ik) { /* rotate by r4 = 0x40 = 8 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 4; /* XOR c4 (= ..04) */ if (aes_128_encrypt_block(k, tmp1, ik)) return -1; for (i = 0; i < 16; i++) ik[i] ^= opc[i]; } /* f5* */ if (akstar) { /* rotate by r5 = 0x60 = 12 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 8; /* XOR c5 (= ..08) */ if (aes_128_encrypt_block(k, tmp1, tmp1)) return -1; for (i = 0; i < 6; i++) akstar[i] = tmp1[i] ^ opc[i]; } return 0; }
/** milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms * * @param[out] res Buffer for RES = 64-bit signed response (f2), or NULL * @param[out] ck Buffer for CK = 128-bit confidentiality key (f3), or NULL * @param[out] ik Buffer for IK = 128-bit integrity key (f4), or NULL * @param[out] ak Buffer for AK = 48-bit anonymity key (f5), or NULL * @param[out] ak_resync Buffer for AK = 48-bit anonymity key (f5*), or NULL * @param[in] opc 128-bit value derived from OP and K. * @param[in] k 128-bit subscriber key * @param[in] rand 128-bit random challenge * @return * - 0 on success. * - -1 on failure. */ static int milenage_f2345(uint8_t res[MILENAGE_RES_SIZE], uint8_t ik[MILENAGE_IK_SIZE], uint8_t ck[MILENAGE_CK_SIZE], uint8_t ak[MILENAGE_AK_SIZE], uint8_t ak_resync[MILENAGE_AK_SIZE], uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const k[MILENAGE_KI_SIZE], uint8_t const rand[MILENAGE_RAND_SIZE]) { uint8_t tmp1[16], tmp2[16], tmp3[16]; int i; EVP_CIPHER_CTX *evp_ctx; /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ for (i = 0; i < 16; i++) tmp1[i] = rand[i] ^ opc[i]; evp_ctx = EVP_CIPHER_CTX_new(); if (!evp_ctx) { tls_strerror_printf("Failed allocating EVP context"); return -1; } if (aes_128_encrypt_block(evp_ctx, k, tmp1, tmp2) < 0) { error: EVP_CIPHER_CTX_free(evp_ctx); return -1; } /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ /* f2 and f5 */ /* rotate by r2 (= 0, i.e., NOP) */ for (i = 0; i < 16; i++) tmp1[i] = tmp2[i] ^ opc[i]; tmp1[15] ^= 1; /* XOR c2 (= ..01) */ /* f5 || f2 = E_K(tmp1) XOR OP_c */ if (aes_128_encrypt_block(evp_ctx, k, tmp1, tmp3) < 0) goto error; for (i = 0; i < 16; i++) tmp3[i] ^= opc[i]; if (res) memcpy(res, tmp3 + 8, 8); /* f2 */ if (ak) memcpy(ak, tmp3, 6); /* f5 */ /* f3 */ if (ck) { /* rotate by r3 = 0x20 = 4 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 2; /* XOR c3 (= ..02) */ if (aes_128_encrypt_block(evp_ctx, k, tmp1, ck) < 0) goto error; for (i = 0; i < 16; i++) ck[i] ^= opc[i]; } /* f4 */ if (ik) { /* rotate by r4 = 0x40 = 8 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 4; /* XOR c4 (= ..04) */ if (aes_128_encrypt_block(evp_ctx, k, tmp1, ik) < 0) goto error; for (i = 0; i < 16; i++) ik[i] ^= opc[i]; } /* f5* */ if (ak_resync) { /* rotate by r5 = 0x60 = 12 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 8; /* XOR c5 (= ..08) */ if (aes_128_encrypt_block(evp_ctx, k, tmp1, tmp1) < 0) goto error; for (i = 0; i < 6; i++) ak_resync[i] = tmp1[i] ^ opc[i]; } EVP_CIPHER_CTX_free(evp_ctx); return 0; }