#include <gpxe/net80211.h>
#include <gpxe/crypto.h>
#include <gpxe/hmac.h>
#include <gpxe/sha1.h>
#include <gpxe/aes.h>
#include <gpxe/wpa.h>
#include <byteswap.h>
#include <errno.h>
Go to the source code of this file.
Data Structures | |
| struct | ccmp_ctx |
| Context for CCMP encryption and decryption. More... | |
| struct | ccmp_head |
| Header structure at the beginning of CCMP frame data. More... | |
| struct | ccmp_nonce |
| CCMP nonce structure. More... | |
| struct | ccmp_aad |
| CCMP additional authentication data structure. More... | |
Defines | |
| #define | CCMP_HEAD_LEN 8 |
| CCMP header overhead. | |
| #define | CCMP_MIC_LEN 8 |
| CCMP MIC trailer overhead. | |
| #define | CCMP_NONCE_LEN 13 |
| CCMP nonce length. | |
| #define | CCMP_AAD_LEN 22 |
| CCMP additional authentication data length (for non-QoS, non-WDS frames). | |
| #define | CCMP_AAD_FC_MASK 0xC38F |
| Mask for Frame Control field in AAD. | |
| #define | CCMP_AAD_SEQ_MASK 0x000F |
| Mask for Sequence Control field in AAD. | |
| #define | PN_MSB 1 |
| Value for msb argument of u64_to_pn() for MSB output. | |
| #define | PN_LSB 0 |
| Value for msb argument of u64_to_pn() for LSB output. | |
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| static u64 | pn_to_u64 (const u8 *pn) |
| Convert 6-byte LSB packet number to 64-bit integer. | |
| static void | u64_to_pn (u64 v, u8 *pn, int msb) |
| Convert 64-bit integer to 6-byte packet number. | |
| static int | ccmp_init (struct net80211_crypto *crypto, const void *key, int keylen, const void *rsc) |
| Initialise CCMP state and install key. | |
| static void | ccmp_ctr_xor (struct ccmp_ctx *ctx, const void *nonce, const void *srcv, void *destv, int len, const void *msrcv, void *mdestv) |
| Encrypt or decrypt data stream using AES in Counter mode. | |
| static void | ccmp_feed_cbc_mac (void *aes_ctx, u8 *B, u8 *X) |
| Advance one block in CBC-MAC calculation. | |
| static void | ccmp_cbc_mac (struct ccmp_ctx *ctx, const void *nonce, const void *data, u16 datalen, const void *aad, void *mic) |
| Calculate MIC on plaintext data using CBC-MAC. | |
| struct io_buffer * | ccmp_encrypt (struct net80211_crypto *crypto, struct io_buffer *iob) |
| Encapsulate and encrypt a packet using CCMP. | |
| static struct io_buffer * | ccmp_decrypt (struct net80211_crypto *crypto, struct io_buffer *eiob) |
| Decrypt a packet using CCMP. | |
| static void | ccmp_kie_mic (const void *kck, const void *msg, size_t len, void *mic) |
| Calculate HMAC-SHA1 MIC for EAPOL-Key frame. | |
| static int | ccmp_kie_decrypt (const void *kek, const void *iv __unused, void *msg, u16 *len) |
| Decrypt key data in EAPOL-Key frame. | |
Variables | |
| struct net80211_crypto ccmp_crypto | __net80211_crypto |
| CCMP cryptosystem. | |
| struct wpa_kie ccmp_kie | __wpa_kie |
| CCMP-style key integrity and encryption handler. | |
Definition in file wpa_ccmp.c.
| #define CCMP_HEAD_LEN 8 |
CCMP header overhead.
Definition at line 59 of file wpa_ccmp.c.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
| #define CCMP_MIC_LEN 8 |
CCMP MIC trailer overhead.
Definition at line 62 of file wpa_ccmp.c.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
| #define CCMP_NONCE_LEN 13 |
CCMP nonce length.
Definition at line 65 of file wpa_ccmp.c.
Referenced by ccmp_cbc_mac(), and ccmp_ctr_xor().
| #define CCMP_AAD_LEN 22 |
CCMP additional authentication data length (for non-QoS, non-WDS frames).
Definition at line 76 of file wpa_ccmp.c.
Referenced by ccmp_cbc_mac().
| #define CCMP_AAD_FC_MASK 0xC38F |
Mask for Frame Control field in AAD.
Definition at line 90 of file wpa_ccmp.c.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
| #define CCMP_AAD_SEQ_MASK 0x000F |
Mask for Sequence Control field in AAD.
Definition at line 93 of file wpa_ccmp.c.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
| #define PN_MSB 1 |
Value for msb argument of u64_to_pn() for MSB output.
Definition at line 139 of file wpa_ccmp.c.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
| #define PN_LSB 0 |
Value for msb argument of u64_to_pn() for LSB output.
Definition at line 142 of file wpa_ccmp.c.
Referenced by ccmp_encrypt().
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
Convert 6-byte LSB packet number to 64-bit integer.
| pn | Pointer to 6-byte packet number |
| v | 64-bit integer value of pn |
Definition at line 102 of file wpa_ccmp.c.
Referenced by ccmp_decrypt(), and ccmp_init().
00103 { 00104 int i; 00105 u64 ret = 0; 00106 00107 for ( i = 5; i >= 0; i-- ) { 00108 ret <<= 8; 00109 ret |= pn[i]; 00110 } 00111 00112 return ret; 00113 }
Convert 64-bit integer to 6-byte packet number.
| v | 64-bit integer | |
| msb | If TRUE, reverse the output PN to be in MSB order |
| pn | 6-byte packet number |
Definition at line 125 of file wpa_ccmp.c.
References u8.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
00126 { 00127 int i; 00128 u8 *pnp = pn + ( msb ? 5 : 0 ); 00129 int delta = ( msb ? -1 : +1 ); 00130 00131 for ( i = 0; i < 6; i++ ) { 00132 *pnp = v & 0xFF; 00133 pnp += delta; 00134 v >>= 8; 00135 } 00136 }
| static int ccmp_init | ( | struct net80211_crypto * | crypto, | |
| const void * | key, | |||
| int | keylen, | |||
| const void * | rsc | |||
| ) | [static] |
Initialise CCMP state and install key.
| crypto | CCMP cryptosystem structure | |
| key | Pointer to 16-byte temporal key to install | |
| keylen | Length of key (16 bytes) | |
| rsc | Initial receive sequence counter |
Definition at line 154 of file wpa_ccmp.c.
References aes_algorithm, ccmp_ctx::aes_ctx, cipher_setkey(), EINVAL, pn_to_u64(), net80211_crypto::priv, and ccmp_ctx::rx_seq.
00156 { 00157 struct ccmp_ctx *ctx = crypto->priv; 00158 00159 if ( keylen != 16 ) 00160 return -EINVAL; 00161 00162 if ( rsc ) 00163 ctx->rx_seq = pn_to_u64 ( rsc ); 00164 00165 cipher_setkey ( &aes_algorithm, ctx->aes_ctx, key, keylen ); 00166 00167 return 0; 00168 }
| static void ccmp_ctr_xor | ( | struct ccmp_ctx * | ctx, | |
| const void * | nonce, | |||
| const void * | srcv, | |||
| void * | destv, | |||
| int | len, | |||
| const void * | msrcv, | |||
| void * | mdestv | |||
| ) | [static] |
Encrypt or decrypt data stream using AES in Counter mode.
| ctx | CCMP cryptosystem context | |
| nonce | Nonce value, 13 bytes | |
| srcv | Data to encrypt or decrypt | |
| len | Number of bytes pointed to by src | |
| msrcv | MIC value to encrypt or decrypt (may be NULL) |
| destv | Encrypted or decrypted data | |
| mdestv | Encrypted or decrypted MIC value |
Definition at line 185 of file wpa_ccmp.c.
References aes_algorithm, ccmp_ctx::aes_ctx, CCMP_NONCE_LEN, cipher_encrypt, dest, memcpy, S(), src, u16, and u8.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
00188 { 00189 u8 A[16], S[16]; 00190 u16 ctr; 00191 int i; 00192 const u8 *src = srcv, *msrc = msrcv; 00193 u8 *dest = destv, *mdest = mdestv; 00194 00195 A[0] = 0x01; /* flags, L' = L - 1 = 1, other bits rsvd */ 00196 memcpy ( A + 1, nonce, CCMP_NONCE_LEN ); 00197 00198 if ( msrcv ) { 00199 A[14] = A[15] = 0; 00200 00201 cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 ); 00202 00203 for ( i = 0; i < 8; i++ ) { 00204 *mdest++ = *msrc++ ^ S[i]; 00205 } 00206 } 00207 00208 for ( ctr = 1 ;; ctr++ ) { 00209 A[14] = ctr >> 8; 00210 A[15] = ctr & 0xFF; 00211 00212 cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 ); 00213 00214 for ( i = 0; i < len && i < 16; i++ ) 00215 *dest++ = *src++ ^ S[i]; 00216 00217 if ( len <= 16 ) 00218 break; /* we're done */ 00219 00220 len -= 16; 00221 } 00222 }
Advance one block in CBC-MAC calculation.
| aes_ctx | AES encryption context with key set | |
| B | Cleartext block to incorporate (16 bytes) | |
| X | Previous ciphertext block (16 bytes) |
| B | Clobbered | |
| X | New ciphertext block (16 bytes) |
Definition at line 236 of file wpa_ccmp.c.
References aes_algorithm, and cipher_encrypt.
Referenced by ccmp_cbc_mac().
00237 { 00238 int i; 00239 for ( i = 0; i < 16; i++ ) 00240 B[i] ^= X[i]; 00241 cipher_encrypt ( &aes_algorithm, aes_ctx, B, X, 16 ); 00242 }
| static void ccmp_cbc_mac | ( | struct ccmp_ctx * | ctx, | |
| const void * | nonce, | |||
| const void * | data, | |||
| u16 | datalen, | |||
| const void * | aad, | |||
| void * | mic | |||
| ) | [static] |
Calculate MIC on plaintext data using CBC-MAC.
| ctx | CCMP cryptosystem context | |
| nonce | Nonce value, 13 bytes | |
| data | Data to calculate MIC over | |
| datalen | Length of data | |
| aad | Additional authentication data, for MIC but not encryption |
| mic | MIC value (unencrypted), 8 bytes |
Definition at line 259 of file wpa_ccmp.c.
References aes_algorithm, ccmp_ctx::aes_ctx, CCMP_AAD_LEN, ccmp_feed_cbc_mac(), CCMP_NONCE_LEN, cipher_encrypt, memcpy, memset(), u8, and X.
Referenced by ccmp_decrypt(), and ccmp_encrypt().
00262 { 00263 u8 X[16], B[16]; 00264 00265 /* Zeroth block: flags, nonce, length */ 00266 00267 /* Rsv AAD - M'- - L'- 00268 * 0 1 0 1 1 0 0 1 for an 8-byte MAC and 2-byte message length 00269 */ 00270 B[0] = 0x59; 00271 memcpy ( B + 1, nonce, CCMP_NONCE_LEN ); 00272 B[14] = datalen >> 8; 00273 B[15] = datalen & 0xFF; 00274 00275 cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, B, X, 16 ); 00276 00277 /* First block: AAD length field and 14 bytes of AAD */ 00278 B[0] = 0; 00279 B[1] = CCMP_AAD_LEN; 00280 memcpy ( B + 2, aad, 14 ); 00281 00282 ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); 00283 00284 /* Second block: Remaining 8 bytes of AAD, 8 bytes zero pad */ 00285 memcpy ( B, aad + 14, 8 ); 00286 memset ( B + 8, 0, 8 ); 00287 00288 ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); 00289 00290 /* Message blocks */ 00291 while ( datalen ) { 00292 if ( datalen >= 16 ) { 00293 memcpy ( B, data, 16 ); 00294 datalen -= 16; 00295 } else { 00296 memcpy ( B, data, datalen ); 00297 memset ( B + datalen, 0, 16 - datalen ); 00298 datalen = 0; 00299 } 00300 00301 ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); 00302 00303 data += 16; 00304 } 00305 00306 /* Get MIC from final value of X */ 00307 memcpy ( mic, X, 8 ); 00308 }
| struct io_buffer* ccmp_encrypt | ( | struct net80211_crypto * | crypto, | |
| struct io_buffer * | iob | |||
| ) | [read] |
Encapsulate and encrypt a packet using CCMP.
| crypto | CCMP cryptosystem | |
| iob | I/O buffer containing cleartext packet |
| eiob | I/O buffer containing encrypted packet |
Definition at line 318 of file wpa_ccmp.c.
References ccmp_head::_rsvd, ccmp_aad::a1, ccmp_nonce::a2, ieee80211_frame::addr1, ieee80211_frame::addr2, alloc_iob(), CCMP_AAD_FC_MASK, CCMP_AAD_SEQ_MASK, ccmp_cbc_mac(), ccmp_ctr_xor(), CCMP_HEAD_LEN, CCMP_MIC_LEN, io_buffer::data, DBGC2, ETH_ALEN, ccmp_aad::fc, ieee80211_frame::fc, IEEE80211_FC_PROTECTED, IEEE80211_TYP_FRAME_HEADER_LEN, iob_len(), iob_put, ccmp_head::kid, memcpy, NULL, ccmp_nonce::pn, ccmp_head::pn_hi, ccmp_head::pn_lo, PN_LSB, PN_MSB, ccmp_nonce::prio, net80211_crypto::priv, ieee80211_frame::seq, ccmp_aad::seq, ccmp_ctx::tx_seq, u64_to_pn(), and u8.
00320 { 00321 struct ccmp_ctx *ctx = crypto->priv; 00322 struct ieee80211_frame *hdr = iob->data; 00323 struct io_buffer *eiob; 00324 const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; 00325 int datalen = iob_len ( iob ) - hdrlen; 00326 struct ccmp_head head; 00327 struct ccmp_nonce nonce; 00328 struct ccmp_aad aad; 00329 u8 mic[8], tx_pn[6]; 00330 void *edata, *emic; 00331 00332 ctx->tx_seq++; 00333 u64_to_pn ( ctx->tx_seq, tx_pn, PN_LSB ); 00334 00335 /* Allocate memory */ 00336 eiob = alloc_iob ( iob_len ( iob ) + CCMP_HEAD_LEN + CCMP_MIC_LEN ); 00337 if ( ! eiob ) 00338 return NULL; 00339 00340 /* Copy frame header */ 00341 memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen ); 00342 hdr = eiob->data; 00343 hdr->fc |= IEEE80211_FC_PROTECTED; 00344 00345 /* Fill in packet number and extended IV */ 00346 memcpy ( head.pn_lo, tx_pn, 2 ); 00347 memcpy ( head.pn_hi, tx_pn + 2, 4 ); 00348 head.kid = 0x20; /* have Extended IV, key ID 0 */ 00349 head._rsvd = 0; 00350 memcpy ( iob_put ( eiob, sizeof ( head ) ), &head, sizeof ( head ) ); 00351 00352 /* Form nonce */ 00353 nonce.prio = 0; 00354 memcpy ( nonce.a2, hdr->addr2, ETH_ALEN ); 00355 u64_to_pn ( ctx->tx_seq, nonce.pn, PN_MSB ); 00356 00357 /* Form additional authentication data */ 00358 aad.fc = hdr->fc & CCMP_AAD_FC_MASK; 00359 memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */ 00360 aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK; 00361 00362 /* Calculate MIC over the data */ 00363 ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, mic ); 00364 00365 /* Copy and encrypt data and MIC */ 00366 edata = iob_put ( eiob, datalen ); 00367 emic = iob_put ( eiob, CCMP_MIC_LEN ); 00368 ccmp_ctr_xor ( ctx, &nonce, 00369 iob->data + hdrlen, edata, datalen, 00370 mic, emic ); 00371 00372 /* Done! */ 00373 DBGC2 ( ctx, "WPA-CCMP %p: encrypted packet %p -> %p\n", ctx, 00374 iob, eiob ); 00375 00376 return eiob; 00377 }
| static struct io_buffer* ccmp_decrypt | ( | struct net80211_crypto * | crypto, | |
| struct io_buffer * | eiob | |||
| ) | [static, read] |
Decrypt a packet using CCMP.
| crypto | CCMP cryptosystem | |
| eiob | I/O buffer containing encrypted packet |
| iob | I/O buffer containing cleartext packet |
Definition at line 386 of file wpa_ccmp.c.
References ccmp_aad::a1, ccmp_nonce::a2, ieee80211_frame::addr1, ieee80211_frame::addr2, alloc_iob(), CCMP_AAD_FC_MASK, CCMP_AAD_SEQ_MASK, ccmp_cbc_mac(), ccmp_ctr_xor(), CCMP_HEAD_LEN, CCMP_MIC_LEN, io_buffer::data, DBGC, DBGC2, ETH_ALEN, ccmp_aad::fc, ieee80211_frame::fc, free_iob(), IEEE80211_FC_PROTECTED, IEEE80211_TYP_FRAME_HEADER_LEN, iob_len(), iob_put, memcmp(), memcpy, NULL, ccmp_nonce::pn, ccmp_head::pn_hi, ccmp_head::pn_lo, PN_MSB, pn_to_u64(), ccmp_nonce::prio, net80211_crypto::priv, ccmp_ctx::rx_seq, ieee80211_frame::seq, ccmp_aad::seq, io_buffer::tail, u64_to_pn(), and u8.
00388 { 00389 struct ccmp_ctx *ctx = crypto->priv; 00390 struct ieee80211_frame *hdr; 00391 struct io_buffer *iob; 00392 const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; 00393 int datalen = iob_len ( eiob ) - hdrlen - CCMP_HEAD_LEN - CCMP_MIC_LEN; 00394 struct ccmp_head *head; 00395 struct ccmp_nonce nonce; 00396 struct ccmp_aad aad; 00397 u8 rx_pn[6], their_mic[8], our_mic[8]; 00398 00399 iob = alloc_iob ( hdrlen + datalen ); 00400 if ( ! iob ) 00401 return NULL; 00402 00403 /* Copy frame header */ 00404 memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen ); 00405 hdr = iob->data; 00406 hdr->fc &= ~IEEE80211_FC_PROTECTED; 00407 00408 /* Check and update RX packet number */ 00409 head = eiob->data + hdrlen; 00410 memcpy ( rx_pn, head->pn_lo, 2 ); 00411 memcpy ( rx_pn + 2, head->pn_hi, 4 ); 00412 00413 if ( pn_to_u64 ( rx_pn ) <= ctx->rx_seq ) { 00414 DBGC ( ctx, "WPA-CCMP %p: packet received out of order " 00415 "(%012llx <= %012llx)\n", ctx, pn_to_u64 ( rx_pn ), 00416 ctx->rx_seq ); 00417 free_iob ( iob ); 00418 return NULL; 00419 } 00420 00421 ctx->rx_seq = pn_to_u64 ( rx_pn ); 00422 DBGC2 ( ctx, "WPA-CCMP %p: RX packet number %012llx\n", ctx, ctx->rx_seq ); 00423 00424 /* Form nonce */ 00425 nonce.prio = 0; 00426 memcpy ( nonce.a2, hdr->addr2, ETH_ALEN ); 00427 u64_to_pn ( ctx->rx_seq, nonce.pn, PN_MSB ); 00428 00429 /* Form additional authentication data */ 00430 aad.fc = ( hdr->fc & CCMP_AAD_FC_MASK ) | IEEE80211_FC_PROTECTED; 00431 memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */ 00432 aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK; 00433 00434 /* Copy-decrypt data and MIC */ 00435 ccmp_ctr_xor ( ctx, &nonce, eiob->data + hdrlen + sizeof ( *head ), 00436 iob_put ( iob, datalen ), datalen, 00437 eiob->tail - CCMP_MIC_LEN, their_mic ); 00438 00439 /* Check MIC */ 00440 ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, 00441 our_mic ); 00442 00443 if ( memcmp ( their_mic, our_mic, CCMP_MIC_LEN ) != 0 ) { 00444 DBGC2 ( ctx, "WPA-CCMP %p: MIC failure\n", ctx ); 00445 free_iob ( iob ); 00446 return NULL; 00447 } 00448 00449 DBGC2 ( ctx, "WPA-CCMP %p: decrypted packet %p -> %p\n", ctx, 00450 eiob, iob ); 00451 00452 return iob; 00453 }
| static void ccmp_kie_mic | ( | const void * | kck, | |
| const void * | msg, | |||
| size_t | len, | |||
| void * | mic | |||
| ) | [static] |
Calculate HMAC-SHA1 MIC for EAPOL-Key frame.
| kck | Key Confirmation Key, 16 bytes | |
| msg | Message to calculate MIC over | |
| len | Number of bytes to calculate MIC over |
| mic | Calculated MIC, 16 bytes long |
Definition at line 476 of file wpa_ccmp.c.
References hmac_final(), hmac_init(), hmac_update(), memcpy, sha1_algorithm, SHA1_CTX_SIZE, SHA1_SIZE, and u8.
00478 { 00479 u8 sha1_ctx[SHA1_CTX_SIZE]; 00480 u8 kckb[16]; 00481 u8 hash[SHA1_SIZE]; 00482 size_t kck_len = 16; 00483 00484 memcpy ( kckb, kck, kck_len ); 00485 00486 hmac_init ( &sha1_algorithm, sha1_ctx, kckb, &kck_len ); 00487 hmac_update ( &sha1_algorithm, sha1_ctx, msg, len ); 00488 hmac_final ( &sha1_algorithm, sha1_ctx, kckb, &kck_len, hash ); 00489 00490 memcpy ( mic, hash, 16 ); 00491 }
| static int ccmp_kie_decrypt | ( | const void * | kek, | |
| const void *iv | __unused, | |||
| void * | msg, | |||
| u16 * | len | |||
| ) | [static] |
Decrypt key data in EAPOL-Key frame.
| kek | Key Encryption Key, 16 bytes | |
| iv | Initialisation vector, 16 bytes (unused) | |
| msg | Message to decrypt | |
| len | Length of message |
| msg | Decrypted message in place of original | |
| len | Adjusted downward for 8 bytes of overhead | |
| rc | Return status code |
Definition at line 509 of file wpa_ccmp.c.
References aes_unwrap(), and EINVAL.
00511 { 00512 if ( *len % 8 != 0 ) 00513 return -EINVAL; 00514 00515 if ( aes_unwrap ( kek, msg, msg, *len / 8 - 1 ) != 0 ) 00516 return -EINVAL; 00517 00518 *len -= 8; 00519 00520 return 0; 00521 }
| struct net80211_crypto ccmp_crypto __net80211_crypto |
Initial value:
{
.algorithm = NET80211_CRYPT_CCMP,
.init = ccmp_init,
.encrypt = ccmp_encrypt,
.decrypt = ccmp_decrypt,
.priv_len = sizeof ( struct ccmp_ctx ),
}
Definition at line 457 of file wpa_ccmp.c.
Initial value:
{
.version = EAPOL_KEY_VERSION_WPA2,
.mic = ccmp_kie_mic,
.decrypt = ccmp_kie_decrypt,
}
Definition at line 524 of file wpa_ccmp.c.
1.5.7.1