Path: blob/main/sys/crypto/openssl/ossl_aes_gcm.c
106751 views
/*1* Copyright 2010-2022 The OpenSSL Project Authors. All Rights Reserved.2* Copyright (c) 2021, Intel Corporation. All Rights Reserved.3* Copyright (c) 2023, Raptor Engineering, LLC. All Rights Reserved.4*5* Licensed under the Apache License 2.0 (the "License"). You may not use6* this file except in compliance with the License. You can obtain a copy7* in the file LICENSE in the source distribution or at8* https://www.openssl.org/source/license.html9*/1011/*12* This file contains an AES-GCM wrapper implementation from OpenSSL, using13* AES-NI (x86) or POWER8 Crypto Extensions (ppc). It was ported from14* cipher_aes_gcm_hw_aesni.inc and it makes use of a generic C implementation15* for partial blocks, ported from gcm128.c with OPENSSL_SMALL_FOOTPRINT defined.16*/1718#include <sys/endian.h>19#include <sys/systm.h>2021#include <crypto/openssl/ossl.h>22#include <crypto/openssl/ossl_aes_gcm.h>23#include <crypto/openssl/ossl_cipher.h>2425#include <opencrypto/cryptodev.h>2627_Static_assert(28sizeof(struct ossl_gcm_context) <= sizeof(struct ossl_cipher_context),29"ossl_gcm_context too large");3031#if defined(__amd64__) || defined(__i386__)32#define AES_set_encrypt_key aesni_set_encrypt_key33#define AES_gcm_encrypt aesni_gcm_encrypt34#define AES_gcm_decrypt aesni_gcm_decrypt35#define AES_encrypt aesni_encrypt36#define AES_ctr32_encrypt_blocks aesni_ctr32_encrypt_blocks37#define GCM_init gcm_init_avx38#define GCM_gmult gcm_gmult_avx39#define GCM_ghash gcm_ghash_avx4041void AES_set_encrypt_key(const void *key, int bits, void *ctx);42size_t AES_gcm_encrypt(const unsigned char *in, unsigned char *out, size_t len,43const void *key, unsigned char ivec[16], uint64_t *Xi);44size_t AES_gcm_decrypt(const unsigned char *in, unsigned char *out, size_t len,45const void *key, unsigned char ivec[16], uint64_t *Xi);46void AES_encrypt(const unsigned char *in, unsigned char *out, void *ks);47void AES_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out,48size_t blocks, void *ks, const unsigned char *iv);4950void GCM_init(__uint128_t Htable[16], uint64_t Xi[2]);51void GCM_gmult(uint64_t Xi[2], const __uint128_t Htable[16]);52void GCM_ghash(uint64_t Xi[2], const __uint128_t Htable[16], const void *in,53size_t len);5455#elif defined(__powerpc64__)56#define AES_set_encrypt_key aes_p8_set_encrypt_key57#define AES_gcm_encrypt(i,o,l,k,v,x) ppc_aes_gcm_crypt(i,o,l,k,v,x,1)58#define AES_gcm_decrypt(i,o,l,k,v,x) ppc_aes_gcm_crypt(i,o,l,k,v,x,0)59#define AES_encrypt aes_p8_encrypt60#define AES_ctr32_encrypt_blocks aes_p8_ctr32_encrypt_blocks61#define GCM_init gcm_init_p862#define GCM_gmult gcm_gmult_p863#define GCM_ghash gcm_ghash_p86465size_t ppc_aes_gcm_encrypt(const unsigned char *in, unsigned char *out, size_t len,66const void *key, unsigned char ivec[16], uint64_t *Xi);67size_t ppc_aes_gcm_decrypt(const unsigned char *in, unsigned char *out, size_t len,68const void *key, unsigned char ivec[16], uint64_t *Xi);6970void AES_set_encrypt_key(const void *key, int bits, void *ctx);71void AES_encrypt(const unsigned char *in, unsigned char *out, void *ks);72void AES_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out,73size_t blocks, void *ks, const unsigned char *iv);7475void GCM_init(__uint128_t Htable[16], uint64_t Xi[2]);76void GCM_gmult(uint64_t Xi[2], const __uint128_t Htable[16]);77void GCM_ghash(uint64_t Xi[2], const __uint128_t Htable[16], const void *in,78size_t len);7980static size_t81ppc_aes_gcm_crypt(const unsigned char *in, unsigned char *out,82size_t len, const void *key, unsigned char ivec_[16], uint64_t *Xi,83int encrypt)84{85union {86uint32_t d[4];87uint8_t c[16];88} *ivec = (void *)ivec_;89int s = 0;90int ndone = 0;91int ctr_reset = 0;92uint32_t ivec_val;93uint64_t blocks_unused;94uint64_t nb = len / 16;95uint64_t next_ctr = 0;96unsigned char ctr_saved[12];9798memcpy(ctr_saved, ivec, 12);99100while (nb) {101ivec_val = ivec->d[3];102#if BYTE_ORDER == LITTLE_ENDIAN103ivec_val = bswap32(ivec_val);104#endif105106blocks_unused = (uint64_t)0xffffffffU + 1 - (uint64_t)ivec_val;107if (nb > blocks_unused) {108len = blocks_unused * 16;109nb -= blocks_unused;110next_ctr = blocks_unused;111ctr_reset = 1;112} else {113len = nb * 16;114next_ctr = nb;115nb = 0;116}117118s = encrypt ? ppc_aes_gcm_encrypt(in, out, len, key, ivec->c, Xi) :119ppc_aes_gcm_decrypt(in, out, len, key, ivec->c, Xi);120121/* add counter to ivec */122#if BYTE_ORDER == LITTLE_ENDIAN123ivec->d[3] = bswap32(ivec_val + next_ctr);124#else125ivec->d[3] += next_ctr;126#endif127if (ctr_reset) {128ctr_reset = 0;129in += len;130out += len;131}132memcpy(ivec, ctr_saved, 12);133ndone += s;134}135136return ndone;137}138139#else140#error "Unsupported architecture!"141#endif142143static void144gcm_init(struct ossl_gcm_context *ctx, const void *key, size_t keylen)145{146KASSERT(keylen == 128 || keylen == 192 || keylen == 256,147("%s: invalid key length %zu", __func__, keylen));148149memset(&ctx->gcm, 0, sizeof(ctx->gcm));150memset(&ctx->aes_ks, 0, sizeof(ctx->aes_ks));151AES_set_encrypt_key(key, keylen, &ctx->aes_ks);152ctx->ops->init(ctx, key, keylen);153}154155static void156gcm_tag_op(struct ossl_gcm_context *ctx, unsigned char *tag, size_t len)157{158(void)ctx->ops->finish(ctx, NULL, 0);159memcpy(tag, ctx->gcm.Xi.c, len);160}161162static void163gcm_init_op(struct ossl_gcm_context *ctx, const void *key, size_t keylen)164{165AES_encrypt(ctx->gcm.H.c, ctx->gcm.H.c, &ctx->aes_ks);166167#if BYTE_ORDER == LITTLE_ENDIAN168ctx->gcm.H.u[0] = bswap64(ctx->gcm.H.u[0]);169ctx->gcm.H.u[1] = bswap64(ctx->gcm.H.u[1]);170#endif171172GCM_init(ctx->gcm.Htable, ctx->gcm.H.u);173}174175static void176gcm_setiv_op(struct ossl_gcm_context *ctx, const unsigned char *iv,177size_t len)178{179uint32_t ctr;180181KASSERT(len == AES_GCM_IV_LEN,182("%s: invalid IV length %zu", __func__, len));183184ctx->gcm.len.u[0] = 0;185ctx->gcm.len.u[1] = 0;186ctx->gcm.ares = ctx->gcm.mres = 0;187188memcpy(ctx->gcm.Yi.c, iv, len);189ctx->gcm.Yi.c[12] = 0;190ctx->gcm.Yi.c[13] = 0;191ctx->gcm.Yi.c[14] = 0;192ctx->gcm.Yi.c[15] = 1;193ctr = 1;194195ctx->gcm.Xi.u[0] = 0;196ctx->gcm.Xi.u[1] = 0;197198AES_encrypt(ctx->gcm.Yi.c, ctx->gcm.EK0.c, &ctx->aes_ks);199ctr++;200201#if BYTE_ORDER == LITTLE_ENDIAN202ctx->gcm.Yi.d[3] = bswap32(ctr);203#else204ctx->gcm.Yi.d[3] = ctr;205#endif206}207208static int209gcm_aad_op(struct ossl_gcm_context *ctx, const unsigned char *aad,210size_t len)211{212size_t i;213unsigned int n;214uint64_t alen = ctx->gcm.len.u[0];215216if (ctx->gcm.len.u[1])217return -2;218219alen += len;220if (alen > (1ull << 61) || (sizeof(len) == 8 && alen < len))221return -1;222ctx->gcm.len.u[0] = alen;223224n = ctx->gcm.ares;225if (n) {226while (n && len) {227ctx->gcm.Xi.c[n] ^= *(aad++);228--len;229n = (n + 1) % 16;230}231if (n == 0)232GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);233else {234ctx->gcm.ares = n;235return 0;236}237}238if ((i = (len & (size_t)-AES_BLOCK_LEN))) {239GCM_ghash(ctx->gcm.Xi.u, ctx->gcm.Htable, aad, i);240aad += i;241len -= i;242}243if (len) {244n = (unsigned int)len;245for (i = 0; i < len; ++i)246ctx->gcm.Xi.c[i] ^= aad[i];247}248249ctx->gcm.ares = n;250return 0;251}252253static int254gcm_encrypt(struct ossl_gcm_context *ctx, const unsigned char *in,255unsigned char *out, size_t len)256{257unsigned int n, ctr, mres;258size_t i;259uint64_t mlen = ctx->gcm.len.u[1];260261mlen += len;262if (mlen > ((1ull << 36) - 32) || (sizeof(len) == 8 && mlen < len))263return -1;264ctx->gcm.len.u[1] = mlen;265266mres = ctx->gcm.mres;267268if (ctx->gcm.ares) {269/* First call to encrypt finalizes GHASH(AAD) */270GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);271ctx->gcm.ares = 0;272}273274#if BYTE_ORDER == LITTLE_ENDIAN275ctr = bswap32(ctx->gcm.Yi.d[3]);276#else277ctr = ctx->gcm.Yi.d[3];278#endif279280n = mres % 16;281for (i = 0; i < len; ++i) {282if (n == 0) {283AES_encrypt(ctx->gcm.Yi.c, ctx->gcm.EKi.c,284&ctx->aes_ks);285++ctr;286#if BYTE_ORDER == LITTLE_ENDIAN287ctx->gcm.Yi.d[3] = bswap32(ctr);288#else289ctx->gcm.Yi.d[3] = ctr;290#endif291}292ctx->gcm.Xi.c[n] ^= out[i] = in[i] ^ ctx->gcm.EKi.c[n];293mres = n = (n + 1) % 16;294if (n == 0)295GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);296}297298ctx->gcm.mres = mres;299return 0;300}301302static int303gcm_encrypt_ctr32(struct ossl_gcm_context *ctx, const unsigned char *in,304unsigned char *out, size_t len)305{306unsigned int n, ctr, mres;307size_t i;308uint64_t mlen = ctx->gcm.len.u[1];309310mlen += len;311if (mlen > ((1ull << 36) - 32) || (sizeof(len) == 8 && mlen < len))312return -1;313ctx->gcm.len.u[1] = mlen;314315mres = ctx->gcm.mres;316317if (ctx->gcm.ares) {318/* First call to encrypt finalizes GHASH(AAD) */319GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);320ctx->gcm.ares = 0;321}322323#if BYTE_ORDER == LITTLE_ENDIAN324ctr = bswap32(ctx->gcm.Yi.d[3]);325#else326ctr = ctx->gcm.Yi.d[3];327#endif328329n = mres % 16;330if (n) {331while (n && len) {332ctx->gcm.Xi.c[n] ^= *(out++) = *(in++) ^ ctx->gcm.EKi.c[n];333--len;334n = (n + 1) % 16;335}336if (n == 0) {337GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);338mres = 0;339} else {340ctx->gcm.mres = n;341return 0;342}343}344if ((i = (len & (size_t)-16))) {345size_t j = i / 16;346347AES_ctr32_encrypt_blocks(in, out, j, &ctx->aes_ks, ctx->gcm.Yi.c);348ctr += (unsigned int)j;349#if BYTE_ORDER == LITTLE_ENDIAN350ctx->gcm.Yi.d[3] = bswap32(ctr);351#else352ctx->gcm.Yi.d[3] = ctr;353#endif354in += i;355len -= i;356while (j--) {357for (i = 0; i < 16; ++i)358ctx->gcm.Xi.c[i] ^= out[i];359GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);360out += 16;361}362}363if (len) {364AES_encrypt(ctx->gcm.Yi.c, ctx->gcm.EKi.c, &ctx->aes_ks);365++ctr;366#if BYTE_ORDER == LITTLE_ENDIAN367ctx->gcm.Yi.d[3] = bswap32(ctr);368#else369ctx->gcm.Yi.d[3] = ctr;370#endif371while (len--) {372ctx->gcm.Xi.c[mres++] ^= out[n] = in[n] ^ ctx->gcm.EKi.c[n];373++n;374}375}376377ctx->gcm.mres = mres;378return 0;379}380381static int382gcm_encrypt_op(struct ossl_gcm_context *ctx, const unsigned char *in,383unsigned char *out, size_t len)384{385size_t bulk = 0, res;386int error;387388res = MIN(len, (AES_BLOCK_LEN - ctx->gcm.mres) % AES_BLOCK_LEN);389if ((error = gcm_encrypt(ctx, in, out, res)) != 0)390return error;391392bulk = AES_gcm_encrypt(in + res, out + res, len - res,393&ctx->aes_ks, ctx->gcm.Yi.c, ctx->gcm.Xi.u);394ctx->gcm.len.u[1] += bulk;395bulk += res;396397if ((error = gcm_encrypt_ctr32(ctx, in + bulk, out + bulk,398len - bulk)) != 0)399return error;400401return 0;402}403404static int405gcm_decrypt(struct ossl_gcm_context *ctx, const unsigned char *in,406unsigned char *out, size_t len)407{408unsigned int n, ctr, mres;409size_t i;410uint64_t mlen = ctx->gcm.len.u[1];411412mlen += len;413if (mlen > ((1ull << 36) - 32) || (sizeof(len) == 8 && mlen < len))414return -1;415ctx->gcm.len.u[1] = mlen;416417mres = ctx->gcm.mres;418419if (ctx->gcm.ares) {420/* First call to encrypt finalizes GHASH(AAD) */421GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);422ctx->gcm.ares = 0;423}424425#if BYTE_ORDER == LITTLE_ENDIAN426ctr = bswap32(ctx->gcm.Yi.d[3]);427#else428ctr = ctx->gcm.Yi.d[3];429#endif430431n = mres % 16;432for (i = 0; i < len; ++i) {433uint8_t c;434if (n == 0) {435AES_encrypt(ctx->gcm.Yi.c, ctx->gcm.EKi.c,436&ctx->aes_ks);437++ctr;438#if BYTE_ORDER == LITTLE_ENDIAN439ctx->gcm.Yi.d[3] = bswap32(ctr);440#else441ctx->gcm.Yi.d[3] = ctr;442#endif443}444c = in[i];445out[i] = c ^ ctx->gcm.EKi.c[n];446ctx->gcm.Xi.c[n] ^= c;447mres = n = (n + 1) % 16;448if (n == 0)449GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);450}451452ctx->gcm.mres = mres;453return 0;454}455456static int457gcm_decrypt_ctr32(struct ossl_gcm_context *ctx, const unsigned char *in,458unsigned char *out, size_t len)459{460unsigned int n, ctr, mres;461size_t i;462uint64_t mlen = ctx->gcm.len.u[1];463464mlen += len;465if (mlen > ((1ull << 36) - 32) || (sizeof(len) == 8 && mlen < len))466return -1;467ctx->gcm.len.u[1] = mlen;468469mres = ctx->gcm.mres;470471if (ctx->gcm.ares) {472/* First call to decrypt finalizes GHASH(AAD) */473GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);474ctx->gcm.ares = 0;475}476477#if BYTE_ORDER == LITTLE_ENDIAN478ctr = bswap32(ctx->gcm.Yi.d[3]);479#else480ctr = ctx->gcm.Yi.d[3];481#endif482483n = mres % 16;484if (n) {485while (n && len) {486uint8_t c = *(in++);487*(out++) = c ^ ctx->gcm.EKi.c[n];488ctx->gcm.Xi.c[n] ^= c;489--len;490n = (n + 1) % 16;491}492if (n == 0) {493GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);494mres = 0;495} else {496ctx->gcm.mres = n;497return 0;498}499}500if ((i = (len & (size_t)-16))) {501size_t j = i / 16;502503while (j--) {504size_t k;505for (k = 0; k < 16; ++k)506ctx->gcm.Xi.c[k] ^= in[k];507GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);508in += 16;509}510j = i / 16;511in -= i;512AES_ctr32_encrypt_blocks(in, out, j, &ctx->aes_ks, ctx->gcm.Yi.c);513ctr += (unsigned int)j;514#if BYTE_ORDER == LITTLE_ENDIAN515ctx->gcm.Yi.d[3] = bswap32(ctr);516#else517ctx->gcm.Yi.d[3] = ctr;518#endif519out += i;520in += i;521len -= i;522}523if (len) {524AES_encrypt(ctx->gcm.Yi.c, ctx->gcm.EKi.c, &ctx->aes_ks);525++ctr;526#if BYTE_ORDER == LITTLE_ENDIAN527ctx->gcm.Yi.d[3] = bswap32(ctr);528#else529ctx->gcm.Yi.d[3] = ctr;530#endif531while (len--) {532uint8_t c = in[n];533ctx->gcm.Xi.c[mres++] ^= c;534out[n] = c ^ ctx->gcm.EKi.c[n];535++n;536}537}538539ctx->gcm.mres = mres;540return 0;541}542543static int544gcm_decrypt_op(struct ossl_gcm_context *ctx, const unsigned char *in,545unsigned char *out, size_t len)546{547size_t bulk = 0, res;548int error;549550res = MIN(len, (AES_BLOCK_LEN - ctx->gcm.mres) % AES_BLOCK_LEN);551if ((error = gcm_decrypt(ctx, in, out, res)) != 0)552return error;553554bulk = AES_gcm_decrypt(in + res, out + res, len - res, &ctx->aes_ks,555ctx->gcm.Yi.c, ctx->gcm.Xi.u);556ctx->gcm.len.u[1] += bulk;557bulk += res;558559if ((error = gcm_decrypt_ctr32(ctx, in + bulk, out + bulk, len - bulk)) != 0)560return error;561562return 0;563}564565static int566gcm_finish_op(struct ossl_gcm_context *ctx, const unsigned char *tag,567size_t len)568{569uint64_t alen = ctx->gcm.len.u[0] << 3;570uint64_t clen = ctx->gcm.len.u[1] << 3;571572if (ctx->gcm.mres || ctx->gcm.ares)573GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);574575#if BYTE_ORDER == LITTLE_ENDIAN576alen = bswap64(alen);577clen = bswap64(clen);578#endif579580ctx->gcm.Xi.u[0] ^= alen;581ctx->gcm.Xi.u[1] ^= clen;582GCM_gmult(ctx->gcm.Xi.u, ctx->gcm.Htable);583584ctx->gcm.Xi.u[0] ^= ctx->gcm.EK0.u[0];585ctx->gcm.Xi.u[1] ^= ctx->gcm.EK0.u[1];586587if (tag != NULL)588return timingsafe_bcmp(ctx->gcm.Xi.c, tag, len);589return 0;590}591592static const struct ossl_aes_gcm_ops gcm_ops = {593.init = gcm_init_op,594.setiv = gcm_setiv_op,595.aad = gcm_aad_op,596.encrypt = gcm_encrypt_op,597.decrypt = gcm_decrypt_op,598.finish = gcm_finish_op,599.tag = gcm_tag_op,600};601602int ossl_aes_gcm_setkey(const unsigned char *key, int klen, void *_ctx);603604int605ossl_aes_gcm_setkey(const unsigned char *key, int klen,606void *_ctx)607{608struct ossl_gcm_context *ctx;609610ctx = _ctx;611ctx->ops = &gcm_ops;612gcm_init(ctx, key, klen);613return (0);614}615616617