Path: blob/main/sys/net80211/ieee80211_crypto_gcm.c
39475 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2012, Jouni Malinen <[email protected]>4* All rights reserved.5*6* Galois/Counter Mode (GCM) and GMAC with AES7*8* Originally sourced from hostapd 2.11 (src/crypto/aes-gcm.c).9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR20* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES21* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.22* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,23* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT24* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,25* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY26* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT27* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF28* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031#include "opt_wlan.h"3233#include <sys/param.h>34#include <sys/systm.h>35#include <sys/kernel.h>3637#include <crypto/rijndael/rijndael.h>38#include <net80211/ieee80211_crypto_gcm.h>3940#define AES_BLOCK_LEN 164142#define BIT(x) (1U << (x))4344static __inline void45xor_block(uint8_t *b, const uint8_t *a, size_t len)46{47int i;48for (i = 0; i < len; i++)49b[i] ^= a[i];50}5152static inline53void WPA_PUT_BE64(uint8_t *a, uint64_t val)54{55a[0] = val >> 56;56a[1] = val >> 48;57a[2] = val >> 40;58a[3] = val >> 32;59a[4] = val >> 24;60a[5] = val >> 16;61a[6] = val >> 8;62a[7] = val & 0xff;63}6465static inline void66WPA_PUT_BE32(uint8_t *a, uint32_t val)67{68a[0] = (val >> 24) & 0xff;69a[1] = (val >> 16) & 0xff;70a[2] = (val >> 8) & 0xff;71a[3] = val & 0xff;72}7374static inline uint32_t75WPA_GET_BE32(const uint8_t *a)76{77return (((uint32_t) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);78}7980static void81inc32(uint8_t *block)82{83uint32_t val;8485val = WPA_GET_BE32(block + AES_BLOCK_LEN - 4);86val++;87WPA_PUT_BE32(block + AES_BLOCK_LEN - 4, val);88}8990static void91shift_right_block(uint8_t *v)92{93uint32_t val;9495val = WPA_GET_BE32(v + 12);96val >>= 1;97if (v[11] & 0x01)98val |= 0x80000000;99WPA_PUT_BE32(v + 12, val);100101val = WPA_GET_BE32(v + 8);102val >>= 1;103if (v[7] & 0x01)104val |= 0x80000000;105WPA_PUT_BE32(v + 8, val);106107val = WPA_GET_BE32(v + 4);108val >>= 1;109if (v[3] & 0x01)110val |= 0x80000000;111WPA_PUT_BE32(v + 4, val);112113val = WPA_GET_BE32(v);114val >>= 1;115WPA_PUT_BE32(v, val);116}117118119/* Multiplication in GF(2^128) */120static void121gf_mult(const uint8_t *x, const uint8_t *y, uint8_t *z)122{123uint8_t v[16];124int i, j;125126memset(z, 0, 16); /* Z_0 = 0^128 */127memcpy(v, y, 16); /* V_0 = Y */128129for (i = 0; i < 16; i++) {130for (j = 0; j < 8; j++) {131if (x[i] & BIT(7 - j)) {132/* Z_(i + 1) = Z_i XOR V_i */133xor_block(z, v, AES_BLOCK_LEN);134} else {135/* Z_(i + 1) = Z_i */136}137138if (v[15] & 0x01) {139/* V_(i + 1) = (V_i >> 1) XOR R */140shift_right_block(v);141/* R = 11100001 || 0^120 */142v[0] ^= 0xe1;143} else {144/* V_(i + 1) = V_i >> 1 */145shift_right_block(v);146}147}148}149}150151static void152ghash_start(uint8_t *y)153{154/* Y_0 = 0^128 */155memset(y, 0, 16);156}157158static void159ghash(const uint8_t *h, const uint8_t *x, size_t xlen, uint8_t *y)160{161size_t m, i;162const uint8_t *xpos = x;163uint8_t tmp[16];164165m = xlen / 16;166167for (i = 0; i < m; i++) {168/* Y_i = (Y^(i-1) XOR X_i) dot H */169xor_block(y, xpos, AES_BLOCK_LEN);170xpos += 16;171172/* dot operation:173* multiplication operation for binary Galois (finite) field of174* 2^128 elements */175gf_mult(y, h, tmp);176memcpy(y, tmp, 16);177}178179if (x + xlen > xpos) {180/* Add zero padded last block */181size_t last = x + xlen - xpos;182memcpy(tmp, xpos, last);183memset(tmp + last, 0, sizeof(tmp) - last);184185/* Y_i = (Y^(i-1) XOR X_i) dot H */186xor_block(y, tmp, AES_BLOCK_LEN);187188/* dot operation:189* multiplication operation for binary Galois (finite) field of190* 2^128 elements */191gf_mult(y, h, tmp);192memcpy(y, tmp, 16);193}194195/* Return Y_m */196}197198/*199* Execute the GCTR call with the counter block icb200* on payload x (size len), output into y.201*/202static void203aes_gctr(rijndael_ctx *aes, const uint8_t *icb,204const uint8_t *x, size_t xlen, uint8_t *y)205{206size_t i, n, last;207uint8_t cb[AES_BLOCK_LEN], tmp[AES_BLOCK_LEN];208const uint8_t *xpos = x;209uint8_t *ypos = y;210211if (xlen == 0)212return;213214n = xlen / 16;215216memcpy(cb, icb, AES_BLOCK_LEN);217218/* Full blocks */219for (i = 0; i < n; i++) {220rijndael_encrypt(aes, cb, ypos);221xor_block(ypos, xpos, AES_BLOCK_LEN);222xpos += AES_BLOCK_LEN;223ypos += AES_BLOCK_LEN;224inc32(cb);225}226227last = x + xlen - xpos;228if (last) {229/* Last, partial block */230rijndael_encrypt(aes, cb, tmp);231for (i = 0; i < last; i++)232*ypos++ = *xpos++ ^ tmp[i];233}234}235236static void237aes_gcm_init_hash_subkey(rijndael_ctx *aes, uint8_t *H)238{239/* Generate hash subkey H = AES_K(0^128) */240memset(H, 0, AES_BLOCK_LEN);241242rijndael_encrypt(aes, H, H);243}244245static void246aes_gcm_prepare_j0(const uint8_t *iv, size_t iv_len, const uint8_t *H,247uint8_t *J0)248{249uint8_t len_buf[16];250251if (iv_len == 12) {252/* Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */253memcpy(J0, iv, iv_len);254memset(J0 + iv_len, 0, AES_BLOCK_LEN - iv_len);255J0[AES_BLOCK_LEN - 1] = 0x01;256} else {257/*258* s = 128 * ceil(len(IV)/128) - len(IV)259* J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)260*/261ghash_start(J0);262ghash(H, iv, iv_len, J0);263WPA_PUT_BE64(len_buf, 0);264WPA_PUT_BE64(len_buf + 8, iv_len * 8);265ghash(H, len_buf, sizeof(len_buf), J0);266}267}268269static void270aes_gcm_gctr(rijndael_ctx *aes, const uint8_t *J0, const uint8_t *in,271size_t len, uint8_t *out)272{273uint8_t J0inc[AES_BLOCK_LEN];274275if (len == 0)276return;277278memcpy(J0inc, J0, AES_BLOCK_LEN);279inc32(J0inc);280281aes_gctr(aes, J0inc, in, len, out);282}283284static void285aes_gcm_ghash(const uint8_t *H, const uint8_t *aad, size_t aad_len,286const uint8_t *crypt, size_t crypt_len, uint8_t *S)287{288uint8_t len_buf[16];289290/*291* u = 128 * ceil[len(C)/128] - len(C)292* v = 128 * ceil[len(A)/128] - len(A)293* S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)294* (i.e., zero padded to block size A || C and lengths of each in bits)295*/296ghash_start(S);297ghash(H, aad, aad_len, S);298ghash(H, crypt, crypt_len, S);299WPA_PUT_BE64(len_buf, aad_len * 8);300WPA_PUT_BE64(len_buf + 8, crypt_len * 8);301ghash(H, len_buf, sizeof(len_buf), S);302}303304/**305* aes_gcm_ae - GCM-AE_K(IV, P, A)306*/307void308ieee80211_crypto_aes_gcm_ae(rijndael_ctx *aes, const uint8_t *iv, size_t iv_len,309const uint8_t *plain, size_t plain_len,310const uint8_t *aad, size_t aad_len, uint8_t *crypt, uint8_t *tag)311{312uint8_t H[AES_BLOCK_LEN];313uint8_t J0[AES_BLOCK_LEN];314uint8_t S[GCMP_MIC_LEN];315316aes_gcm_init_hash_subkey(aes, H);317318aes_gcm_prepare_j0(iv, iv_len, H, J0);319320/* C = GCTR_K(inc_32(J_0), P) */321aes_gcm_gctr(aes, J0, plain, plain_len, crypt);322323aes_gcm_ghash(H, aad, aad_len, crypt, plain_len, S);324325/* T = MSB_t(GCTR_K(J_0, S)) */326aes_gctr(aes, J0, S, sizeof(S), tag);327328/* Return (C, T) */329}330331/**332* aes_gcm_ad - GCM-AD_K(IV, C, A, T)333*334* Return 0 if OK, -1 if decrypt failure.335*/336int337ieee80211_crypto_aes_gcm_ad(rijndael_ctx *aes, const uint8_t *iv, size_t iv_len,338const uint8_t *crypt, size_t crypt_len,339const uint8_t *aad, size_t aad_len, const uint8_t *tag, uint8_t *plain)340{341uint8_t H[AES_BLOCK_LEN];342uint8_t J0[AES_BLOCK_LEN];343uint8_t S[16], T[GCMP_MIC_LEN];344345aes_gcm_init_hash_subkey(aes, H);346347aes_gcm_prepare_j0(iv, iv_len, H, J0);348349/* P = GCTR_K(inc_32(J_0), C) */350aes_gcm_gctr(aes, J0, crypt, crypt_len, plain);351352aes_gcm_ghash(H, aad, aad_len, crypt, crypt_len, S);353354/* T' = MSB_t(GCTR_K(J_0, S)) */355aes_gctr(aes, J0, S, sizeof(S), T);356357if (memcmp(tag, T, 16) != 0) {358return (-1);359}360361return (0);362}363364365