![]() |
The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
|
The cryptographic primitives of EAP-PSK (RFC 4764). More...
#include <freeradius-devel/util/misc.h>#include <openssl/evp.h>#include <openssl/cmac.h>#include <openssl/crypto.h>#include "crypto.h"
Include dependency graph for crypto.c:
This graph shows which files directly or indirectly include this file:Go to the source code of this file.
Functions | |
| static int | aes128_ctr (uint8_t *out, uint8_t const key[static 16], uint8_t const ctr[static 16], uint8_t const *in, size_t len) |
| AES-128 in counter mode. | |
| static USES_APPLE_DEPRECATED_API int | aes128_ecb_block (uint8_t out[static 16], uint8_t const key[static 16], uint8_t const in[static 16]) |
| A single AES-128 ECB block encryption: out = AES-128(key, in) | |
| static int | eap_psk_cmac (uint8_t mac[static 16], uint8_t const key[static 16], uint8_t const *seg1, size_t len1, uint8_t const *seg2, size_t len2, uint8_t const *seg3, size_t len3, uint8_t const *seg4, size_t len4) |
| AES-128 CMAC over one or more concatenated buffers. | |
| static int | eap_psk_counter_mode (uint8_t *out, uint8_t const key[static 16], uint8_t const input[static 16], size_t count) |
| The "modified counter mode" of RFC 4764 Sections 3.1 and 3.2. | |
| int | eap_psk_derive_ak_kdk (uint8_t ak[static EAP_PSK_AK_LEN], uint8_t kdk[static EAP_PSK_KDK_LEN], uint8_t const psk[static EAP_PSK_PSK_LEN]) |
| Key setup: derive AK (counter 1) and KDK (counter 2) from the PSK. | |
| int | eap_psk_derive_keys (uint8_t tek[static EAP_PSK_TEK_LEN], uint8_t msk[static EAP_PSK_MSK_LEN], uint8_t emsk[static EAP_PSK_EMSK_LEN], uint8_t const kdk[static EAP_PSK_KDK_LEN], uint8_t const rand_p[static EAP_PSK_RAND_LEN]) |
| Session-key derivation: expand RAND_P under KDK into nine output blocks. | |
| int | eap_psk_mac_p (uint8_t mac_p[static EAP_PSK_MAC_LEN], uint8_t const ak[static EAP_PSK_AK_LEN], uint8_t const *id_p, size_t id_p_len, uint8_t const *id_s, size_t id_s_len, uint8_t const rand_s[static EAP_PSK_RAND_LEN], uint8_t const rand_p[static EAP_PSK_RAND_LEN]) |
| Compute MAC_P = CMAC-AES-128(AK, ID_P || ID_S || RAND_S || RAND_P) | |
| int | eap_psk_mac_s (uint8_t mac_s[static EAP_PSK_MAC_LEN], uint8_t const ak[static EAP_PSK_AK_LEN], uint8_t const *id_s, size_t id_s_len, uint8_t const rand_p[static EAP_PSK_RAND_LEN]) |
| Compute MAC_S = CMAC-AES-128(AK, ID_S || RAND_P) | |
| static void | eap_psk_nonce_block (uint8_t block[static 16], uint32_t nonce) |
| Build the 16-byte EAX nonce block from the 4-byte EAP-PSK Nonce N. | |
| static int | eap_psk_omac (uint8_t out[static 16], uint8_t const key[static 16], uint8_t t, uint8_t const *data, size_t data_len) |
| The tweaked OMAC used by EAX: OMAC^t(M) = CMAC(K, [t]_16 || M) | |
| int | eap_psk_pchannel_decrypt (uint8_t *plain, uint8_t const tek[static EAP_PSK_TEK_LEN], uint32_t nonce, uint8_t const *header, size_t header_len, uint8_t const *cipher, size_t cipher_len, uint8_t const tag[static EAP_PSK_TAG_LEN]) |
| EAX decrypt-and-verify for the protected channel (RFC 4764 Section 3.3) | |
| int | eap_psk_pchannel_encrypt (uint8_t *cipher, uint8_t tag[static EAP_PSK_TAG_LEN], uint8_t const tek[static EAP_PSK_TEK_LEN], uint32_t nonce, uint8_t const *header, size_t header_len, uint8_t const *plain, size_t plain_len) |
| EAX encrypt for the protected channel (RFC 4764 Section 3.3) | |
The cryptographic primitives of EAP-PSK (RFC 4764).
EAP-PSK is built entirely on AES-128. This file implements, using the OpenSSL EVP and CMAC APIs:
Definition in file crypto.c.
|
static |
AES-128 in counter mode.
OpenSSL uses the 16-byte IV as the initial counter block and increments the whole 128-bit value as a big-endian integer, which is exactly what EAX (and hence EAP-PSK) requires. CTR is symmetric, so the function serves both encryption and decryption.
| [out] | out | receives len bytes. |
| [in] | key | the 16-byte AES key. |
| [in] | ctr | the initial 16-byte counter block. |
| [in] | in | the data to encrypt or decrypt. |
| [in] | len | length of in. |
Definition at line 93 of file crypto.c.
Here is the caller graph for this function:
|
static |
A single AES-128 ECB block encryption: out = AES-128(key, in)
| [out] | out | the encrypted 16-byte block. |
| [in] | key | the 16-byte AES key. |
| [in] | in | the 16-byte block to encrypt. |
Definition at line 52 of file crypto.c.
Here is the caller graph for this function:
|
static |
AES-128 CMAC over one or more concatenated buffers.
A NULL buffer is skipped, so callers can pass a fixed set of segments.
The low-level CMAC API is used because it is portable across OpenSSL 1.1 and 3.x; OpenSSL 3.0 deprecates it in favour of EVP_MAC, so the deprecation warning is suppressed the same way the rest of the tree handles deprecated OpenSSL calls.
| [out] | mac | the computed 16-byte CMAC. |
| [in] | key | the 16-byte AES key. |
| [in] | seg1 | first data segment. May be NULL. |
| [in] | len1 | length of seg1. |
| [in] | seg2 | second data segment. May be NULL. |
| [in] | len2 | length of seg2. |
| [in] | seg3 | third data segment. May be NULL. |
| [in] | len3 | length of seg3. |
| [in] | seg4 | fourth data segment. May be NULL. |
| [in] | len4 | length of seg4. |
Definition at line 235 of file crypto.c.
Here is the caller graph for this function:
|
static |
The "modified counter mode" of RFC 4764 Sections 3.1 and 3.2.
A length-increasing function that expands one 16-byte input block into 'count' output blocks:
hash = AES-128(key, input) out_i = AES-128(key, hash XOR c_i) for i = 1 .. count
where c_i is the integer i encoded as a 16-byte block. Since i is always small (<= 9) only the low-order byte is ever non-zero.
| [out] | out | receives count * 16 bytes. |
| [in] | key | the 16-byte AES key. |
| [in] | input | the 16-byte block to expand. |
| [in] | count | how many output blocks to produce. |
Definition at line 133 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:| int eap_psk_derive_ak_kdk | ( | uint8_t | ak[static EAP_PSK_AK_LEN], |
| uint8_t | kdk[static EAP_PSK_KDK_LEN], | ||
| uint8_t const | psk[static EAP_PSK_PSK_LEN] | ||
| ) |
Key setup: derive AK (counter 1) and KDK (counter 2) from the PSK.
Expands a constant all-zero input block under the PSK using the modified counter mode. See RFC 4764 Section 3.1, Figure 3.
| [out] | ak | the derived authentication key. |
| [out] | kdk | the derived key-derivation key. |
| [in] | psk | the 16-byte pre-shared key. |
Definition at line 164 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:| int eap_psk_derive_keys | ( | uint8_t | tek[static EAP_PSK_TEK_LEN], |
| uint8_t | msk[static EAP_PSK_MSK_LEN], | ||
| uint8_t | emsk[static EAP_PSK_EMSK_LEN], | ||
| uint8_t const | kdk[static EAP_PSK_KDK_LEN], | ||
| uint8_t const | rand_p[static EAP_PSK_RAND_LEN] | ||
| ) |
Session-key derivation: expand RAND_P under KDK into nine output blocks.
Block 1 is the TEK, blocks 2..5 are the MSK, and blocks 6..9 are the EMSK. See RFC 4764 Section 3.2, Figure 7.
| [out] | tek | the transient EAP key, used for the protected channel. |
| [out] | msk | the 64-byte master session key. |
| [out] | emsk | the 64-byte extended master session key. |
| [in] | kdk | the key-derivation key from eap_psk_derive_ak_kdk(). |
| [in] | rand_p | the peer's 16-byte nonce. |
Definition at line 194 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:| int eap_psk_mac_p | ( | uint8_t | mac_p[static EAP_PSK_MAC_LEN], |
| uint8_t const | ak[static EAP_PSK_AK_LEN], | ||
| uint8_t const * | id_p, | ||
| size_t | id_p_len, | ||
| uint8_t const * | id_s, | ||
| size_t | id_s_len, | ||
| uint8_t const | rand_s[static EAP_PSK_RAND_LEN], | ||
| uint8_t const | rand_p[static EAP_PSK_RAND_LEN] | ||
| ) |
Compute MAC_P = CMAC-AES-128(AK, ID_P || ID_S || RAND_S || RAND_P)
The peer proves possession of the PSK with MAC_P in the second message. See RFC 4764 Section 5.2.
| [out] | mac_p | the computed 16-byte MAC. |
| [in] | ak | the authentication key. |
| [in] | id_p | the peer's NAI. May not be NULL terminated. |
| [in] | id_p_len | length of id_p. |
| [in] | id_s | the server's NAI. |
| [in] | id_s_len | length of id_s. |
| [in] | rand_s | the server's nonce. |
| [in] | rand_p | the peer's nonce. |
Definition at line 283 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:| int eap_psk_mac_s | ( | uint8_t | mac_s[static EAP_PSK_MAC_LEN], |
| uint8_t const | ak[static EAP_PSK_AK_LEN], | ||
| uint8_t const * | id_s, | ||
| size_t | id_s_len, | ||
| uint8_t const | rand_p[static EAP_PSK_RAND_LEN] | ||
| ) |
Compute MAC_S = CMAC-AES-128(AK, ID_S || RAND_P)
The server proves possession of the PSK with MAC_S in the third message. See RFC 4764 Section 5.3.
| [out] | mac_s | the computed 16-byte MAC. |
| [in] | ak | the authentication key. |
| [in] | id_s | the server's NAI. |
| [in] | id_s_len | length of id_s. |
| [in] | rand_p | the peer's nonce. |
Definition at line 311 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:Build the 16-byte EAX nonce block from the 4-byte EAP-PSK Nonce N.
N is padded with 96 zero high-order bits, i.e. 12 zero bytes followed by the 4-byte big-endian counter (RFC 4764 Section 3.3).
| [out] | block | the 16-byte nonce block. |
| [in] | nonce | the PCHANNEL counter. |
Definition at line 361 of file crypto.c.
Here is the caller graph for this function:
|
static |
The tweaked OMAC used by EAX: OMAC^t(M) = CMAC(K, [t]_16 || M)
[t]_16 is the integer t encoded as a 16-byte block. t is only ever 0, 1 or 2 here, so only the low-order byte is non-zero.
| [out] | out | the computed 16-byte OMAC. |
| [in] | key | the 16-byte AES key. |
| [in] | t | the OMAC tweak. |
| [in] | data | the data to authenticate. |
| [in] | data_len | length of data. |
Definition at line 337 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:| int eap_psk_pchannel_decrypt | ( | uint8_t * | plain, |
| uint8_t const | tek[static EAP_PSK_TEK_LEN], | ||
| uint32_t | nonce, | ||
| uint8_t const * | header, | ||
| size_t | header_len, | ||
| uint8_t const * | cipher, | ||
| size_t | cipher_len, | ||
| uint8_t const | tag[static EAP_PSK_TAG_LEN] | ||
| ) |
EAX decrypt-and-verify for the protected channel (RFC 4764 Section 3.3)
Recomputes the tag over the received ciphertext and header, and compares the result (in constant time) against the received tag. Only if the tags match is the ciphertext decrypted.
| [out] | plain | receives cipher_len bytes of plaintext. |
| [in] | tek | the transient EAP key. |
| [in] | nonce | the 4-byte PCHANNEL counter (1 for the fourth message). |
| [in] | header | the EAX header H to authenticate. |
| [in] | header_len | length of header. |
| [in] | cipher | the ciphertext to verify and decrypt. |
| [in] | cipher_len | length of cipher. |
| [in] | tag | the received 16-byte authentication tag. |
Definition at line 439 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:| int eap_psk_pchannel_encrypt | ( | uint8_t * | cipher, |
| uint8_t | tag[static EAP_PSK_TAG_LEN], | ||
| uint8_t const | tek[static EAP_PSK_TEK_LEN], | ||
| uint32_t | nonce, | ||
| uint8_t const * | header, | ||
| size_t | header_len, | ||
| uint8_t const * | plain, | ||
| size_t | plain_len | ||
| ) |
EAX encrypt for the protected channel (RFC 4764 Section 3.3)
Computes:
N' = OMAC^0(nonce_block)
H' = OMAC^1(header)
C = CTR_{N'}(plain)
C' = OMAC^2(C)
tag = N' XOR H' XOR C'
Either the plaintext or its length may be zero (EAP-PSK only ever protects a single byte, but the code does not rely on that).
| [out] | cipher | receives plain_len bytes of ciphertext. |
| [out] | tag | receives the 16-byte authentication tag. |
| [in] | tek | the transient EAP key. |
| [in] | nonce | the 4-byte PCHANNEL counter (0 for the third message). |
| [in] | header | the EAX header H to authenticate. |
| [in] | header_len | length of header. |
| [in] | plain | the plaintext to encrypt. |
| [in] | plain_len | length of plain. |
Definition at line 395 of file crypto.c.
Here is the call graph for this function:
Here is the caller graph for this function:
1.9.8