1cf3d41adSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0-or-later 2cf3d41adSArd Biesheuvel /* 3cf3d41adSArd Biesheuvel * The AEGIS-128 Authenticated-Encryption Algorithm 4cf3d41adSArd Biesheuvel * 5cf3d41adSArd Biesheuvel * Copyright (c) 2017-2018 Ondrej Mosnacek <omosnacek@gmail.com> 6cf3d41adSArd Biesheuvel * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. 7cf3d41adSArd Biesheuvel */ 8cf3d41adSArd Biesheuvel 9cf3d41adSArd Biesheuvel #include <crypto/algapi.h> 10cf3d41adSArd Biesheuvel #include <crypto/internal/aead.h> 11cf3d41adSArd Biesheuvel #include <crypto/internal/simd.h> 12cf3d41adSArd Biesheuvel #include <crypto/internal/skcipher.h> 13cf3d41adSArd Biesheuvel #include <crypto/scatterwalk.h> 14cf3d41adSArd Biesheuvel #include <linux/err.h> 15cf3d41adSArd Biesheuvel #include <linux/init.h> 162698bce1SArd Biesheuvel #include <linux/jump_label.h> 17cf3d41adSArd Biesheuvel #include <linux/kernel.h> 18cf3d41adSArd Biesheuvel #include <linux/module.h> 19cf3d41adSArd Biesheuvel #include <linux/scatterlist.h> 20cf3d41adSArd Biesheuvel 21cf3d41adSArd Biesheuvel #include <asm/simd.h> 22cf3d41adSArd Biesheuvel 23cf3d41adSArd Biesheuvel #include "aegis.h" 24cf3d41adSArd Biesheuvel 25cf3d41adSArd Biesheuvel #define AEGIS128_NONCE_SIZE 16 26cf3d41adSArd Biesheuvel #define AEGIS128_STATE_BLOCKS 5 27cf3d41adSArd Biesheuvel #define AEGIS128_KEY_SIZE 16 28cf3d41adSArd Biesheuvel #define AEGIS128_MIN_AUTH_SIZE 8 29cf3d41adSArd Biesheuvel #define AEGIS128_MAX_AUTH_SIZE 16 30cf3d41adSArd Biesheuvel 31cf3d41adSArd Biesheuvel struct aegis_state { 32cf3d41adSArd Biesheuvel union aegis_block blocks[AEGIS128_STATE_BLOCKS]; 33cf3d41adSArd Biesheuvel }; 34cf3d41adSArd Biesheuvel 35cf3d41adSArd Biesheuvel struct aegis_ctx { 36cf3d41adSArd Biesheuvel union aegis_block key; 37cf3d41adSArd Biesheuvel }; 38cf3d41adSArd Biesheuvel 392698bce1SArd Biesheuvel static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_simd); 40cf3d41adSArd Biesheuvel 41f1d087b9SYueHaibing static const union aegis_block crypto_aegis_const[2] = { 42f1d087b9SYueHaibing { .words64 = { 43f1d087b9SYueHaibing cpu_to_le64(U64_C(0x0d08050302010100)), 44f1d087b9SYueHaibing cpu_to_le64(U64_C(0x6279e99059372215)), 45f1d087b9SYueHaibing } }, 46f1d087b9SYueHaibing { .words64 = { 47f1d087b9SYueHaibing cpu_to_le64(U64_C(0xf12fc26d55183ddb)), 48f1d087b9SYueHaibing cpu_to_le64(U64_C(0xdd28b57342311120)), 49f1d087b9SYueHaibing } }, 50f1d087b9SYueHaibing }; 51f1d087b9SYueHaibing 52cf3d41adSArd Biesheuvel static bool aegis128_do_simd(void) 53cf3d41adSArd Biesheuvel { 54cf3d41adSArd Biesheuvel #ifdef CONFIG_CRYPTO_AEGIS128_SIMD 552698bce1SArd Biesheuvel if (static_branch_likely(&have_simd)) 56cf3d41adSArd Biesheuvel return crypto_simd_usable(); 57cf3d41adSArd Biesheuvel #endif 58cf3d41adSArd Biesheuvel return false; 59cf3d41adSArd Biesheuvel } 60cf3d41adSArd Biesheuvel 61cf3d41adSArd Biesheuvel bool crypto_aegis128_have_simd(void); 62cf3d41adSArd Biesheuvel void crypto_aegis128_update_simd(struct aegis_state *state, const void *msg); 6352828263SArd Biesheuvel void crypto_aegis128_init_simd(struct aegis_state *state, 6452828263SArd Biesheuvel const union aegis_block *key, 6552828263SArd Biesheuvel const u8 *iv); 66cf3d41adSArd Biesheuvel void crypto_aegis128_encrypt_chunk_simd(struct aegis_state *state, u8 *dst, 67cf3d41adSArd Biesheuvel const u8 *src, unsigned int size); 68cf3d41adSArd Biesheuvel void crypto_aegis128_decrypt_chunk_simd(struct aegis_state *state, u8 *dst, 69cf3d41adSArd Biesheuvel const u8 *src, unsigned int size); 7097b70180SArd Biesheuvel int crypto_aegis128_final_simd(struct aegis_state *state, 7152828263SArd Biesheuvel union aegis_block *tag_xor, 7297b70180SArd Biesheuvel unsigned int assoclen, 7397b70180SArd Biesheuvel unsigned int cryptlen, 7497b70180SArd Biesheuvel unsigned int authsize); 75cf3d41adSArd Biesheuvel 76cf3d41adSArd Biesheuvel static void crypto_aegis128_update(struct aegis_state *state) 77cf3d41adSArd Biesheuvel { 78cf3d41adSArd Biesheuvel union aegis_block tmp; 79cf3d41adSArd Biesheuvel unsigned int i; 80cf3d41adSArd Biesheuvel 81cf3d41adSArd Biesheuvel tmp = state->blocks[AEGIS128_STATE_BLOCKS - 1]; 82cf3d41adSArd Biesheuvel for (i = AEGIS128_STATE_BLOCKS - 1; i > 0; i--) 83cf3d41adSArd Biesheuvel crypto_aegis_aesenc(&state->blocks[i], &state->blocks[i - 1], 84cf3d41adSArd Biesheuvel &state->blocks[i]); 85cf3d41adSArd Biesheuvel crypto_aegis_aesenc(&state->blocks[0], &tmp, &state->blocks[0]); 86cf3d41adSArd Biesheuvel } 87cf3d41adSArd Biesheuvel 88cf3d41adSArd Biesheuvel static void crypto_aegis128_update_a(struct aegis_state *state, 89*ac50aec4SArd Biesheuvel const union aegis_block *msg, 90*ac50aec4SArd Biesheuvel bool do_simd) 91cf3d41adSArd Biesheuvel { 92*ac50aec4SArd Biesheuvel if (do_simd) { 93cf3d41adSArd Biesheuvel crypto_aegis128_update_simd(state, msg); 94cf3d41adSArd Biesheuvel return; 95cf3d41adSArd Biesheuvel } 96cf3d41adSArd Biesheuvel 97cf3d41adSArd Biesheuvel crypto_aegis128_update(state); 98cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[0], msg); 99cf3d41adSArd Biesheuvel } 100cf3d41adSArd Biesheuvel 101*ac50aec4SArd Biesheuvel static void crypto_aegis128_update_u(struct aegis_state *state, const void *msg, 102*ac50aec4SArd Biesheuvel bool do_simd) 103cf3d41adSArd Biesheuvel { 104*ac50aec4SArd Biesheuvel if (do_simd) { 105cf3d41adSArd Biesheuvel crypto_aegis128_update_simd(state, msg); 106cf3d41adSArd Biesheuvel return; 107cf3d41adSArd Biesheuvel } 108cf3d41adSArd Biesheuvel 109cf3d41adSArd Biesheuvel crypto_aegis128_update(state); 110cf3d41adSArd Biesheuvel crypto_xor(state->blocks[0].bytes, msg, AEGIS_BLOCK_SIZE); 111cf3d41adSArd Biesheuvel } 112cf3d41adSArd Biesheuvel 113cf3d41adSArd Biesheuvel static void crypto_aegis128_init(struct aegis_state *state, 114cf3d41adSArd Biesheuvel const union aegis_block *key, 115cf3d41adSArd Biesheuvel const u8 *iv) 116cf3d41adSArd Biesheuvel { 117cf3d41adSArd Biesheuvel union aegis_block key_iv; 118cf3d41adSArd Biesheuvel unsigned int i; 119cf3d41adSArd Biesheuvel 120cf3d41adSArd Biesheuvel key_iv = *key; 121cf3d41adSArd Biesheuvel crypto_xor(key_iv.bytes, iv, AEGIS_BLOCK_SIZE); 122cf3d41adSArd Biesheuvel 123cf3d41adSArd Biesheuvel state->blocks[0] = key_iv; 124cf3d41adSArd Biesheuvel state->blocks[1] = crypto_aegis_const[1]; 125cf3d41adSArd Biesheuvel state->blocks[2] = crypto_aegis_const[0]; 126cf3d41adSArd Biesheuvel state->blocks[3] = *key; 127cf3d41adSArd Biesheuvel state->blocks[4] = *key; 128cf3d41adSArd Biesheuvel 129cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[3], &crypto_aegis_const[0]); 130cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[4], &crypto_aegis_const[1]); 131cf3d41adSArd Biesheuvel 132cf3d41adSArd Biesheuvel for (i = 0; i < 5; i++) { 133*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, key, false); 134*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &key_iv, false); 135cf3d41adSArd Biesheuvel } 136cf3d41adSArd Biesheuvel } 137cf3d41adSArd Biesheuvel 138cf3d41adSArd Biesheuvel static void crypto_aegis128_ad(struct aegis_state *state, 139*ac50aec4SArd Biesheuvel const u8 *src, unsigned int size, 140*ac50aec4SArd Biesheuvel bool do_simd) 141cf3d41adSArd Biesheuvel { 142cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src)) { 143cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 144cf3d41adSArd Biesheuvel (const union aegis_block *)src; 145cf3d41adSArd Biesheuvel 146cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 147*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, src_blk, do_simd); 148cf3d41adSArd Biesheuvel 149cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 150cf3d41adSArd Biesheuvel src_blk++; 151cf3d41adSArd Biesheuvel } 152cf3d41adSArd Biesheuvel } else { 153cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 154*ac50aec4SArd Biesheuvel crypto_aegis128_update_u(state, src, do_simd); 155cf3d41adSArd Biesheuvel 156cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 157cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 158cf3d41adSArd Biesheuvel } 159cf3d41adSArd Biesheuvel } 160cf3d41adSArd Biesheuvel } 161cf3d41adSArd Biesheuvel 16202685906SArd Biesheuvel static void crypto_aegis128_wipe_chunk(struct aegis_state *state, u8 *dst, 16302685906SArd Biesheuvel const u8 *src, unsigned int size) 16402685906SArd Biesheuvel { 16502685906SArd Biesheuvel memzero_explicit(dst, size); 16602685906SArd Biesheuvel } 16702685906SArd Biesheuvel 168cf3d41adSArd Biesheuvel static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst, 169cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 170cf3d41adSArd Biesheuvel { 171cf3d41adSArd Biesheuvel union aegis_block tmp; 172cf3d41adSArd Biesheuvel 173cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 174cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 175cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 176cf3d41adSArd Biesheuvel (union aegis_block *)dst; 177cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 178cf3d41adSArd Biesheuvel (const union aegis_block *)src; 179cf3d41adSArd Biesheuvel 180cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 181cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 182cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 183cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 184cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 185cf3d41adSArd Biesheuvel 186*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, src_blk, false); 187cf3d41adSArd Biesheuvel 188cf3d41adSArd Biesheuvel *dst_blk = tmp; 189cf3d41adSArd Biesheuvel 190cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 191cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 192cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 193cf3d41adSArd Biesheuvel } 194cf3d41adSArd Biesheuvel } else { 195cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 196cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 197cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 198cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 199cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 200cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 201cf3d41adSArd Biesheuvel 202*ac50aec4SArd Biesheuvel crypto_aegis128_update_u(state, src, false); 203cf3d41adSArd Biesheuvel 204cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 205cf3d41adSArd Biesheuvel 206cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 207cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 208cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 209cf3d41adSArd Biesheuvel } 210cf3d41adSArd Biesheuvel } 211cf3d41adSArd Biesheuvel 212cf3d41adSArd Biesheuvel if (size > 0) { 213cf3d41adSArd Biesheuvel union aegis_block msg = {}; 214cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 215cf3d41adSArd Biesheuvel 216cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 217cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 218cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 219cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 220cf3d41adSArd Biesheuvel 221*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &msg, false); 222cf3d41adSArd Biesheuvel 223cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 224cf3d41adSArd Biesheuvel 225cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 226cf3d41adSArd Biesheuvel } 227cf3d41adSArd Biesheuvel } 228cf3d41adSArd Biesheuvel 229cf3d41adSArd Biesheuvel static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst, 230cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 231cf3d41adSArd Biesheuvel { 232cf3d41adSArd Biesheuvel union aegis_block tmp; 233cf3d41adSArd Biesheuvel 234cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 235cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 236cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 237cf3d41adSArd Biesheuvel (union aegis_block *)dst; 238cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 239cf3d41adSArd Biesheuvel (const union aegis_block *)src; 240cf3d41adSArd Biesheuvel 241cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 242cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 243cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 244cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 245cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 246cf3d41adSArd Biesheuvel 247*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &tmp, false); 248cf3d41adSArd Biesheuvel 249cf3d41adSArd Biesheuvel *dst_blk = tmp; 250cf3d41adSArd Biesheuvel 251cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 252cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 253cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 254cf3d41adSArd Biesheuvel } 255cf3d41adSArd Biesheuvel } else { 256cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 257cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 258cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 259cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 260cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 261cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 262cf3d41adSArd Biesheuvel 263*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &tmp, false); 264cf3d41adSArd Biesheuvel 265cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 266cf3d41adSArd Biesheuvel 267cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 268cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 269cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 270cf3d41adSArd Biesheuvel } 271cf3d41adSArd Biesheuvel } 272cf3d41adSArd Biesheuvel 273cf3d41adSArd Biesheuvel if (size > 0) { 274cf3d41adSArd Biesheuvel union aegis_block msg = {}; 275cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 276cf3d41adSArd Biesheuvel 277cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 278cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 279cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 280cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 281cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 282cf3d41adSArd Biesheuvel 283cf3d41adSArd Biesheuvel memset(msg.bytes + size, 0, AEGIS_BLOCK_SIZE - size); 284cf3d41adSArd Biesheuvel 285*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &msg, false); 286cf3d41adSArd Biesheuvel 287cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 288cf3d41adSArd Biesheuvel } 289cf3d41adSArd Biesheuvel } 290cf3d41adSArd Biesheuvel 291cf3d41adSArd Biesheuvel static void crypto_aegis128_process_ad(struct aegis_state *state, 292cf3d41adSArd Biesheuvel struct scatterlist *sg_src, 293*ac50aec4SArd Biesheuvel unsigned int assoclen, 294*ac50aec4SArd Biesheuvel bool do_simd) 295cf3d41adSArd Biesheuvel { 296cf3d41adSArd Biesheuvel struct scatter_walk walk; 297cf3d41adSArd Biesheuvel union aegis_block buf; 298cf3d41adSArd Biesheuvel unsigned int pos = 0; 299cf3d41adSArd Biesheuvel 300cf3d41adSArd Biesheuvel scatterwalk_start(&walk, sg_src); 301cf3d41adSArd Biesheuvel while (assoclen != 0) { 302cf3d41adSArd Biesheuvel unsigned int size = scatterwalk_clamp(&walk, assoclen); 303cf3d41adSArd Biesheuvel unsigned int left = size; 304cf3d41adSArd Biesheuvel void *mapped = scatterwalk_map(&walk); 305cf3d41adSArd Biesheuvel const u8 *src = (const u8 *)mapped; 306cf3d41adSArd Biesheuvel 307cf3d41adSArd Biesheuvel if (pos + size >= AEGIS_BLOCK_SIZE) { 308cf3d41adSArd Biesheuvel if (pos > 0) { 309cf3d41adSArd Biesheuvel unsigned int fill = AEGIS_BLOCK_SIZE - pos; 310cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, fill); 311*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &buf, do_simd); 312cf3d41adSArd Biesheuvel pos = 0; 313cf3d41adSArd Biesheuvel left -= fill; 314cf3d41adSArd Biesheuvel src += fill; 315cf3d41adSArd Biesheuvel } 316cf3d41adSArd Biesheuvel 317*ac50aec4SArd Biesheuvel crypto_aegis128_ad(state, src, left, do_simd); 318cf3d41adSArd Biesheuvel src += left & ~(AEGIS_BLOCK_SIZE - 1); 319cf3d41adSArd Biesheuvel left &= AEGIS_BLOCK_SIZE - 1; 320cf3d41adSArd Biesheuvel } 321cf3d41adSArd Biesheuvel 322cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, left); 323cf3d41adSArd Biesheuvel 324cf3d41adSArd Biesheuvel pos += left; 325cf3d41adSArd Biesheuvel assoclen -= size; 326cf3d41adSArd Biesheuvel scatterwalk_unmap(mapped); 327cf3d41adSArd Biesheuvel scatterwalk_advance(&walk, size); 328cf3d41adSArd Biesheuvel scatterwalk_done(&walk, 0, assoclen); 329cf3d41adSArd Biesheuvel } 330cf3d41adSArd Biesheuvel 331cf3d41adSArd Biesheuvel if (pos > 0) { 332cf3d41adSArd Biesheuvel memset(buf.bytes + pos, 0, AEGIS_BLOCK_SIZE - pos); 333*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &buf, do_simd); 334cf3d41adSArd Biesheuvel } 335cf3d41adSArd Biesheuvel } 336cf3d41adSArd Biesheuvel 3372698bce1SArd Biesheuvel static __always_inline 3382698bce1SArd Biesheuvel int crypto_aegis128_process_crypt(struct aegis_state *state, 3392698bce1SArd Biesheuvel struct skcipher_walk *walk, 3402698bce1SArd Biesheuvel void (*crypt)(struct aegis_state *state, 3412698bce1SArd Biesheuvel u8 *dst, const u8 *src, 3422698bce1SArd Biesheuvel unsigned int size)) 343cf3d41adSArd Biesheuvel { 3442698bce1SArd Biesheuvel int err = 0; 345cf3d41adSArd Biesheuvel 3462698bce1SArd Biesheuvel while (walk->nbytes) { 3472698bce1SArd Biesheuvel unsigned int nbytes = walk->nbytes; 348cf3d41adSArd Biesheuvel 3492698bce1SArd Biesheuvel if (nbytes < walk->total) 3502698bce1SArd Biesheuvel nbytes = round_down(nbytes, walk->stride); 351cf3d41adSArd Biesheuvel 3522698bce1SArd Biesheuvel crypt(state, walk->dst.virt.addr, walk->src.virt.addr, nbytes); 353cf3d41adSArd Biesheuvel 3542698bce1SArd Biesheuvel err = skcipher_walk_done(walk, walk->nbytes - nbytes); 355cf3d41adSArd Biesheuvel } 3562698bce1SArd Biesheuvel return err; 357cf3d41adSArd Biesheuvel } 358cf3d41adSArd Biesheuvel 359cf3d41adSArd Biesheuvel static void crypto_aegis128_final(struct aegis_state *state, 360cf3d41adSArd Biesheuvel union aegis_block *tag_xor, 361cf3d41adSArd Biesheuvel u64 assoclen, u64 cryptlen) 362cf3d41adSArd Biesheuvel { 363cf3d41adSArd Biesheuvel u64 assocbits = assoclen * 8; 364cf3d41adSArd Biesheuvel u64 cryptbits = cryptlen * 8; 365cf3d41adSArd Biesheuvel 366cf3d41adSArd Biesheuvel union aegis_block tmp; 367cf3d41adSArd Biesheuvel unsigned int i; 368cf3d41adSArd Biesheuvel 369cf3d41adSArd Biesheuvel tmp.words64[0] = cpu_to_le64(assocbits); 370cf3d41adSArd Biesheuvel tmp.words64[1] = cpu_to_le64(cryptbits); 371cf3d41adSArd Biesheuvel 372cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[3]); 373cf3d41adSArd Biesheuvel 374cf3d41adSArd Biesheuvel for (i = 0; i < 7; i++) 375*ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, &tmp, false); 376cf3d41adSArd Biesheuvel 377cf3d41adSArd Biesheuvel for (i = 0; i < AEGIS128_STATE_BLOCKS; i++) 378cf3d41adSArd Biesheuvel crypto_aegis_block_xor(tag_xor, &state->blocks[i]); 379cf3d41adSArd Biesheuvel } 380cf3d41adSArd Biesheuvel 381cf3d41adSArd Biesheuvel static int crypto_aegis128_setkey(struct crypto_aead *aead, const u8 *key, 382cf3d41adSArd Biesheuvel unsigned int keylen) 383cf3d41adSArd Biesheuvel { 384cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(aead); 385cf3d41adSArd Biesheuvel 386674f368aSEric Biggers if (keylen != AEGIS128_KEY_SIZE) 387cf3d41adSArd Biesheuvel return -EINVAL; 388cf3d41adSArd Biesheuvel 389cf3d41adSArd Biesheuvel memcpy(ctx->key.bytes, key, AEGIS128_KEY_SIZE); 390cf3d41adSArd Biesheuvel return 0; 391cf3d41adSArd Biesheuvel } 392cf3d41adSArd Biesheuvel 393cf3d41adSArd Biesheuvel static int crypto_aegis128_setauthsize(struct crypto_aead *tfm, 394cf3d41adSArd Biesheuvel unsigned int authsize) 395cf3d41adSArd Biesheuvel { 396cf3d41adSArd Biesheuvel if (authsize > AEGIS128_MAX_AUTH_SIZE) 397cf3d41adSArd Biesheuvel return -EINVAL; 398cf3d41adSArd Biesheuvel if (authsize < AEGIS128_MIN_AUTH_SIZE) 399cf3d41adSArd Biesheuvel return -EINVAL; 400cf3d41adSArd Biesheuvel return 0; 401cf3d41adSArd Biesheuvel } 402cf3d41adSArd Biesheuvel 403*ac50aec4SArd Biesheuvel static int crypto_aegis128_encrypt_generic(struct aead_request *req) 404cf3d41adSArd Biesheuvel { 405cf3d41adSArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 4062698bce1SArd Biesheuvel union aegis_block tag = {}; 4072698bce1SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 408cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 4092698bce1SArd Biesheuvel unsigned int cryptlen = req->cryptlen; 4102698bce1SArd Biesheuvel struct skcipher_walk walk; 411cf3d41adSArd Biesheuvel struct aegis_state state; 412cf3d41adSArd Biesheuvel 4132698bce1SArd Biesheuvel skcipher_walk_aead_encrypt(&walk, req, false); 41452828263SArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 415*ac50aec4SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen, false); 41602685906SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 4172698bce1SArd Biesheuvel crypto_aegis128_encrypt_chunk); 4182698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 419cf3d41adSArd Biesheuvel 420cf3d41adSArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, 421cf3d41adSArd Biesheuvel authsize, 1); 422cf3d41adSArd Biesheuvel return 0; 423cf3d41adSArd Biesheuvel } 424cf3d41adSArd Biesheuvel 425*ac50aec4SArd Biesheuvel static int crypto_aegis128_decrypt_generic(struct aead_request *req) 426cf3d41adSArd Biesheuvel { 427cf3d41adSArd Biesheuvel static const u8 zeros[AEGIS128_MAX_AUTH_SIZE] = {}; 428cf3d41adSArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 429cf3d41adSArd Biesheuvel union aegis_block tag; 430cf3d41adSArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 431cf3d41adSArd Biesheuvel unsigned int cryptlen = req->cryptlen - authsize; 4322698bce1SArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 4332698bce1SArd Biesheuvel struct skcipher_walk walk; 4342698bce1SArd Biesheuvel struct aegis_state state; 435cf3d41adSArd Biesheuvel 436cf3d41adSArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, 437cf3d41adSArd Biesheuvel authsize, 0); 438cf3d41adSArd Biesheuvel 4392698bce1SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 44052828263SArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 441*ac50aec4SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen, false); 44202685906SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 4432698bce1SArd Biesheuvel crypto_aegis128_decrypt_chunk); 4442698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 445cf3d41adSArd Biesheuvel 44602685906SArd Biesheuvel if (unlikely(crypto_memneq(tag.bytes, zeros, authsize))) { 44702685906SArd Biesheuvel /* 44802685906SArd Biesheuvel * From Chapter 4. 'Security Analysis' of the AEGIS spec [0] 44902685906SArd Biesheuvel * 45002685906SArd Biesheuvel * "3. If verification fails, the decrypted plaintext and the 45102685906SArd Biesheuvel * wrong authentication tag should not be given as output." 45202685906SArd Biesheuvel * 45302685906SArd Biesheuvel * [0] https://competitions.cr.yp.to/round3/aegisv11.pdf 45402685906SArd Biesheuvel */ 45502685906SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 45602685906SArd Biesheuvel crypto_aegis128_process_crypt(NULL, &walk, 45702685906SArd Biesheuvel crypto_aegis128_wipe_chunk); 45802685906SArd Biesheuvel memzero_explicit(&tag, sizeof(tag)); 45902685906SArd Biesheuvel return -EBADMSG; 46002685906SArd Biesheuvel } 46102685906SArd Biesheuvel return 0; 462cf3d41adSArd Biesheuvel } 463cf3d41adSArd Biesheuvel 464*ac50aec4SArd Biesheuvel static int crypto_aegis128_encrypt_simd(struct aead_request *req) 465*ac50aec4SArd Biesheuvel { 466*ac50aec4SArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 467*ac50aec4SArd Biesheuvel union aegis_block tag = {}; 468*ac50aec4SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 469*ac50aec4SArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 470*ac50aec4SArd Biesheuvel unsigned int cryptlen = req->cryptlen; 471*ac50aec4SArd Biesheuvel struct skcipher_walk walk; 472*ac50aec4SArd Biesheuvel struct aegis_state state; 473*ac50aec4SArd Biesheuvel 474*ac50aec4SArd Biesheuvel if (!aegis128_do_simd()) 475*ac50aec4SArd Biesheuvel return crypto_aegis128_encrypt_generic(req); 476*ac50aec4SArd Biesheuvel 477*ac50aec4SArd Biesheuvel skcipher_walk_aead_encrypt(&walk, req, false); 478*ac50aec4SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 479*ac50aec4SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen, true); 480*ac50aec4SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 481*ac50aec4SArd Biesheuvel crypto_aegis128_encrypt_chunk_simd); 482*ac50aec4SArd Biesheuvel crypto_aegis128_final_simd(&state, &tag, req->assoclen, cryptlen, 0); 483*ac50aec4SArd Biesheuvel 484*ac50aec4SArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, 485*ac50aec4SArd Biesheuvel authsize, 1); 486*ac50aec4SArd Biesheuvel return 0; 487*ac50aec4SArd Biesheuvel } 488*ac50aec4SArd Biesheuvel 489*ac50aec4SArd Biesheuvel static int crypto_aegis128_decrypt_simd(struct aead_request *req) 490*ac50aec4SArd Biesheuvel { 491*ac50aec4SArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 492*ac50aec4SArd Biesheuvel union aegis_block tag; 493*ac50aec4SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 494*ac50aec4SArd Biesheuvel unsigned int cryptlen = req->cryptlen - authsize; 495*ac50aec4SArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 496*ac50aec4SArd Biesheuvel struct skcipher_walk walk; 497*ac50aec4SArd Biesheuvel struct aegis_state state; 498*ac50aec4SArd Biesheuvel 499*ac50aec4SArd Biesheuvel if (!aegis128_do_simd()) 500*ac50aec4SArd Biesheuvel return crypto_aegis128_decrypt_generic(req); 501*ac50aec4SArd Biesheuvel 502*ac50aec4SArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, 503*ac50aec4SArd Biesheuvel authsize, 0); 504*ac50aec4SArd Biesheuvel 505*ac50aec4SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 506*ac50aec4SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 507*ac50aec4SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen, true); 508*ac50aec4SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 509*ac50aec4SArd Biesheuvel crypto_aegis128_decrypt_chunk_simd); 510*ac50aec4SArd Biesheuvel 511*ac50aec4SArd Biesheuvel if (unlikely(crypto_aegis128_final_simd(&state, &tag, req->assoclen, 512*ac50aec4SArd Biesheuvel cryptlen, authsize))) { 513*ac50aec4SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 514*ac50aec4SArd Biesheuvel crypto_aegis128_process_crypt(NULL, &walk, 515*ac50aec4SArd Biesheuvel crypto_aegis128_wipe_chunk); 516*ac50aec4SArd Biesheuvel return -EBADMSG; 517*ac50aec4SArd Biesheuvel } 518*ac50aec4SArd Biesheuvel return 0; 519*ac50aec4SArd Biesheuvel } 520*ac50aec4SArd Biesheuvel 521*ac50aec4SArd Biesheuvel static struct aead_alg crypto_aegis128_alg_generic = { 522cf3d41adSArd Biesheuvel .setkey = crypto_aegis128_setkey, 523cf3d41adSArd Biesheuvel .setauthsize = crypto_aegis128_setauthsize, 524*ac50aec4SArd Biesheuvel .encrypt = crypto_aegis128_encrypt_generic, 525*ac50aec4SArd Biesheuvel .decrypt = crypto_aegis128_decrypt_generic, 526cf3d41adSArd Biesheuvel 527cf3d41adSArd Biesheuvel .ivsize = AEGIS128_NONCE_SIZE, 528cf3d41adSArd Biesheuvel .maxauthsize = AEGIS128_MAX_AUTH_SIZE, 529cf3d41adSArd Biesheuvel .chunksize = AEGIS_BLOCK_SIZE, 530cf3d41adSArd Biesheuvel 531*ac50aec4SArd Biesheuvel .base.cra_blocksize = 1, 532*ac50aec4SArd Biesheuvel .base.cra_ctxsize = sizeof(struct aegis_ctx), 533*ac50aec4SArd Biesheuvel .base.cra_alignmask = 0, 534*ac50aec4SArd Biesheuvel .base.cra_priority = 100, 535*ac50aec4SArd Biesheuvel .base.cra_name = "aegis128", 536*ac50aec4SArd Biesheuvel .base.cra_driver_name = "aegis128-generic", 537*ac50aec4SArd Biesheuvel .base.cra_module = THIS_MODULE, 538*ac50aec4SArd Biesheuvel }; 539cf3d41adSArd Biesheuvel 540*ac50aec4SArd Biesheuvel static struct aead_alg crypto_aegis128_alg_simd = { 541*ac50aec4SArd Biesheuvel .setkey = crypto_aegis128_setkey, 542*ac50aec4SArd Biesheuvel .setauthsize = crypto_aegis128_setauthsize, 543*ac50aec4SArd Biesheuvel .encrypt = crypto_aegis128_encrypt_simd, 544*ac50aec4SArd Biesheuvel .decrypt = crypto_aegis128_decrypt_simd, 545cf3d41adSArd Biesheuvel 546*ac50aec4SArd Biesheuvel .ivsize = AEGIS128_NONCE_SIZE, 547*ac50aec4SArd Biesheuvel .maxauthsize = AEGIS128_MAX_AUTH_SIZE, 548*ac50aec4SArd Biesheuvel .chunksize = AEGIS_BLOCK_SIZE, 549cf3d41adSArd Biesheuvel 550*ac50aec4SArd Biesheuvel .base.cra_blocksize = 1, 551*ac50aec4SArd Biesheuvel .base.cra_ctxsize = sizeof(struct aegis_ctx), 552*ac50aec4SArd Biesheuvel .base.cra_alignmask = 0, 553*ac50aec4SArd Biesheuvel .base.cra_priority = 200, 554*ac50aec4SArd Biesheuvel .base.cra_name = "aegis128", 555*ac50aec4SArd Biesheuvel .base.cra_driver_name = "aegis128-simd", 556*ac50aec4SArd Biesheuvel .base.cra_module = THIS_MODULE, 557cf3d41adSArd Biesheuvel }; 558cf3d41adSArd Biesheuvel 559cf3d41adSArd Biesheuvel static int __init crypto_aegis128_module_init(void) 560cf3d41adSArd Biesheuvel { 561*ac50aec4SArd Biesheuvel int ret; 562cf3d41adSArd Biesheuvel 563*ac50aec4SArd Biesheuvel ret = crypto_register_aead(&crypto_aegis128_alg_generic); 564*ac50aec4SArd Biesheuvel if (ret) 565*ac50aec4SArd Biesheuvel return ret; 566*ac50aec4SArd Biesheuvel 567*ac50aec4SArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 568*ac50aec4SArd Biesheuvel crypto_aegis128_have_simd()) { 569*ac50aec4SArd Biesheuvel ret = crypto_register_aead(&crypto_aegis128_alg_simd); 570*ac50aec4SArd Biesheuvel if (ret) { 571*ac50aec4SArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg_generic); 572*ac50aec4SArd Biesheuvel return ret; 573*ac50aec4SArd Biesheuvel } 574*ac50aec4SArd Biesheuvel static_branch_enable(&have_simd); 575*ac50aec4SArd Biesheuvel } 576*ac50aec4SArd Biesheuvel return 0; 577cf3d41adSArd Biesheuvel } 578cf3d41adSArd Biesheuvel 579cf3d41adSArd Biesheuvel static void __exit crypto_aegis128_module_exit(void) 580cf3d41adSArd Biesheuvel { 581*ac50aec4SArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 582*ac50aec4SArd Biesheuvel crypto_aegis128_have_simd()) 583*ac50aec4SArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg_simd); 584*ac50aec4SArd Biesheuvel 585*ac50aec4SArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg_generic); 586cf3d41adSArd Biesheuvel } 587cf3d41adSArd Biesheuvel 588cf3d41adSArd Biesheuvel subsys_initcall(crypto_aegis128_module_init); 589cf3d41adSArd Biesheuvel module_exit(crypto_aegis128_module_exit); 590cf3d41adSArd Biesheuvel 591cf3d41adSArd Biesheuvel MODULE_LICENSE("GPL"); 592cf3d41adSArd Biesheuvel MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>"); 593cf3d41adSArd Biesheuvel MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm"); 594cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128"); 595cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128-generic"); 596*ac50aec4SArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128-simd"); 597