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); 7052828263SArd Biesheuvel void crypto_aegis128_final_simd(struct aegis_state *state, 7152828263SArd Biesheuvel union aegis_block *tag_xor, 7252828263SArd Biesheuvel u64 assoclen, u64 cryptlen); 73cf3d41adSArd Biesheuvel 74cf3d41adSArd Biesheuvel static void crypto_aegis128_update(struct aegis_state *state) 75cf3d41adSArd Biesheuvel { 76cf3d41adSArd Biesheuvel union aegis_block tmp; 77cf3d41adSArd Biesheuvel unsigned int i; 78cf3d41adSArd Biesheuvel 79cf3d41adSArd Biesheuvel tmp = state->blocks[AEGIS128_STATE_BLOCKS - 1]; 80cf3d41adSArd Biesheuvel for (i = AEGIS128_STATE_BLOCKS - 1; i > 0; i--) 81cf3d41adSArd Biesheuvel crypto_aegis_aesenc(&state->blocks[i], &state->blocks[i - 1], 82cf3d41adSArd Biesheuvel &state->blocks[i]); 83cf3d41adSArd Biesheuvel crypto_aegis_aesenc(&state->blocks[0], &tmp, &state->blocks[0]); 84cf3d41adSArd Biesheuvel } 85cf3d41adSArd Biesheuvel 86cf3d41adSArd Biesheuvel static void crypto_aegis128_update_a(struct aegis_state *state, 87cf3d41adSArd Biesheuvel const union aegis_block *msg) 88cf3d41adSArd Biesheuvel { 89cf3d41adSArd Biesheuvel if (aegis128_do_simd()) { 90cf3d41adSArd Biesheuvel crypto_aegis128_update_simd(state, msg); 91cf3d41adSArd Biesheuvel return; 92cf3d41adSArd Biesheuvel } 93cf3d41adSArd Biesheuvel 94cf3d41adSArd Biesheuvel crypto_aegis128_update(state); 95cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[0], msg); 96cf3d41adSArd Biesheuvel } 97cf3d41adSArd Biesheuvel 98cf3d41adSArd Biesheuvel static void crypto_aegis128_update_u(struct aegis_state *state, const void *msg) 99cf3d41adSArd Biesheuvel { 100cf3d41adSArd Biesheuvel if (aegis128_do_simd()) { 101cf3d41adSArd Biesheuvel crypto_aegis128_update_simd(state, msg); 102cf3d41adSArd Biesheuvel return; 103cf3d41adSArd Biesheuvel } 104cf3d41adSArd Biesheuvel 105cf3d41adSArd Biesheuvel crypto_aegis128_update(state); 106cf3d41adSArd Biesheuvel crypto_xor(state->blocks[0].bytes, msg, AEGIS_BLOCK_SIZE); 107cf3d41adSArd Biesheuvel } 108cf3d41adSArd Biesheuvel 109cf3d41adSArd Biesheuvel static void crypto_aegis128_init(struct aegis_state *state, 110cf3d41adSArd Biesheuvel const union aegis_block *key, 111cf3d41adSArd Biesheuvel const u8 *iv) 112cf3d41adSArd Biesheuvel { 113cf3d41adSArd Biesheuvel union aegis_block key_iv; 114cf3d41adSArd Biesheuvel unsigned int i; 115cf3d41adSArd Biesheuvel 116cf3d41adSArd Biesheuvel key_iv = *key; 117cf3d41adSArd Biesheuvel crypto_xor(key_iv.bytes, iv, AEGIS_BLOCK_SIZE); 118cf3d41adSArd Biesheuvel 119cf3d41adSArd Biesheuvel state->blocks[0] = key_iv; 120cf3d41adSArd Biesheuvel state->blocks[1] = crypto_aegis_const[1]; 121cf3d41adSArd Biesheuvel state->blocks[2] = crypto_aegis_const[0]; 122cf3d41adSArd Biesheuvel state->blocks[3] = *key; 123cf3d41adSArd Biesheuvel state->blocks[4] = *key; 124cf3d41adSArd Biesheuvel 125cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[3], &crypto_aegis_const[0]); 126cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[4], &crypto_aegis_const[1]); 127cf3d41adSArd Biesheuvel 128cf3d41adSArd Biesheuvel for (i = 0; i < 5; i++) { 129cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, key); 130cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &key_iv); 131cf3d41adSArd Biesheuvel } 132cf3d41adSArd Biesheuvel } 133cf3d41adSArd Biesheuvel 134cf3d41adSArd Biesheuvel static void crypto_aegis128_ad(struct aegis_state *state, 135cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 136cf3d41adSArd Biesheuvel { 137cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src)) { 138cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 139cf3d41adSArd Biesheuvel (const union aegis_block *)src; 140cf3d41adSArd Biesheuvel 141cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 142cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, src_blk); 143cf3d41adSArd Biesheuvel 144cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 145cf3d41adSArd Biesheuvel src_blk++; 146cf3d41adSArd Biesheuvel } 147cf3d41adSArd Biesheuvel } else { 148cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 149cf3d41adSArd Biesheuvel crypto_aegis128_update_u(state, src); 150cf3d41adSArd Biesheuvel 151cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 152cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 153cf3d41adSArd Biesheuvel } 154cf3d41adSArd Biesheuvel } 155cf3d41adSArd Biesheuvel } 156cf3d41adSArd Biesheuvel 157*02685906SArd Biesheuvel static void crypto_aegis128_wipe_chunk(struct aegis_state *state, u8 *dst, 158*02685906SArd Biesheuvel const u8 *src, unsigned int size) 159*02685906SArd Biesheuvel { 160*02685906SArd Biesheuvel memzero_explicit(dst, size); 161*02685906SArd Biesheuvel } 162*02685906SArd Biesheuvel 163cf3d41adSArd Biesheuvel static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst, 164cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 165cf3d41adSArd Biesheuvel { 166cf3d41adSArd Biesheuvel union aegis_block tmp; 167cf3d41adSArd Biesheuvel 168cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 169cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 170cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 171cf3d41adSArd Biesheuvel (union aegis_block *)dst; 172cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 173cf3d41adSArd Biesheuvel (const union aegis_block *)src; 174cf3d41adSArd Biesheuvel 175cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 176cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 177cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 178cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 179cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 180cf3d41adSArd Biesheuvel 181cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, src_blk); 182cf3d41adSArd Biesheuvel 183cf3d41adSArd Biesheuvel *dst_blk = tmp; 184cf3d41adSArd Biesheuvel 185cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 186cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 187cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 188cf3d41adSArd Biesheuvel } 189cf3d41adSArd Biesheuvel } else { 190cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 191cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 192cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 193cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 194cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 195cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 196cf3d41adSArd Biesheuvel 197cf3d41adSArd Biesheuvel crypto_aegis128_update_u(state, src); 198cf3d41adSArd Biesheuvel 199cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 200cf3d41adSArd Biesheuvel 201cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 202cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 203cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 204cf3d41adSArd Biesheuvel } 205cf3d41adSArd Biesheuvel } 206cf3d41adSArd Biesheuvel 207cf3d41adSArd Biesheuvel if (size > 0) { 208cf3d41adSArd Biesheuvel union aegis_block msg = {}; 209cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 210cf3d41adSArd Biesheuvel 211cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 212cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 213cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 214cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 215cf3d41adSArd Biesheuvel 216cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &msg); 217cf3d41adSArd Biesheuvel 218cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 219cf3d41adSArd Biesheuvel 220cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 221cf3d41adSArd Biesheuvel } 222cf3d41adSArd Biesheuvel } 223cf3d41adSArd Biesheuvel 224cf3d41adSArd Biesheuvel static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst, 225cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 226cf3d41adSArd Biesheuvel { 227cf3d41adSArd Biesheuvel union aegis_block tmp; 228cf3d41adSArd Biesheuvel 229cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 230cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 231cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 232cf3d41adSArd Biesheuvel (union aegis_block *)dst; 233cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 234cf3d41adSArd Biesheuvel (const union aegis_block *)src; 235cf3d41adSArd Biesheuvel 236cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 237cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 238cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 239cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 240cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 241cf3d41adSArd Biesheuvel 242cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 243cf3d41adSArd Biesheuvel 244cf3d41adSArd Biesheuvel *dst_blk = tmp; 245cf3d41adSArd Biesheuvel 246cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 247cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 248cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 249cf3d41adSArd Biesheuvel } 250cf3d41adSArd Biesheuvel } else { 251cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 252cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 253cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 254cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 255cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 256cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 257cf3d41adSArd Biesheuvel 258cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 259cf3d41adSArd Biesheuvel 260cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 261cf3d41adSArd Biesheuvel 262cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 263cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 264cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 265cf3d41adSArd Biesheuvel } 266cf3d41adSArd Biesheuvel } 267cf3d41adSArd Biesheuvel 268cf3d41adSArd Biesheuvel if (size > 0) { 269cf3d41adSArd Biesheuvel union aegis_block msg = {}; 270cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 271cf3d41adSArd Biesheuvel 272cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 273cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 274cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 275cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 276cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 277cf3d41adSArd Biesheuvel 278cf3d41adSArd Biesheuvel memset(msg.bytes + size, 0, AEGIS_BLOCK_SIZE - size); 279cf3d41adSArd Biesheuvel 280cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &msg); 281cf3d41adSArd Biesheuvel 282cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 283cf3d41adSArd Biesheuvel } 284cf3d41adSArd Biesheuvel } 285cf3d41adSArd Biesheuvel 286cf3d41adSArd Biesheuvel static void crypto_aegis128_process_ad(struct aegis_state *state, 287cf3d41adSArd Biesheuvel struct scatterlist *sg_src, 288cf3d41adSArd Biesheuvel unsigned int assoclen) 289cf3d41adSArd Biesheuvel { 290cf3d41adSArd Biesheuvel struct scatter_walk walk; 291cf3d41adSArd Biesheuvel union aegis_block buf; 292cf3d41adSArd Biesheuvel unsigned int pos = 0; 293cf3d41adSArd Biesheuvel 294cf3d41adSArd Biesheuvel scatterwalk_start(&walk, sg_src); 295cf3d41adSArd Biesheuvel while (assoclen != 0) { 296cf3d41adSArd Biesheuvel unsigned int size = scatterwalk_clamp(&walk, assoclen); 297cf3d41adSArd Biesheuvel unsigned int left = size; 298cf3d41adSArd Biesheuvel void *mapped = scatterwalk_map(&walk); 299cf3d41adSArd Biesheuvel const u8 *src = (const u8 *)mapped; 300cf3d41adSArd Biesheuvel 301cf3d41adSArd Biesheuvel if (pos + size >= AEGIS_BLOCK_SIZE) { 302cf3d41adSArd Biesheuvel if (pos > 0) { 303cf3d41adSArd Biesheuvel unsigned int fill = AEGIS_BLOCK_SIZE - pos; 304cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, fill); 305cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &buf); 306cf3d41adSArd Biesheuvel pos = 0; 307cf3d41adSArd Biesheuvel left -= fill; 308cf3d41adSArd Biesheuvel src += fill; 309cf3d41adSArd Biesheuvel } 310cf3d41adSArd Biesheuvel 311cf3d41adSArd Biesheuvel crypto_aegis128_ad(state, src, left); 312cf3d41adSArd Biesheuvel src += left & ~(AEGIS_BLOCK_SIZE - 1); 313cf3d41adSArd Biesheuvel left &= AEGIS_BLOCK_SIZE - 1; 314cf3d41adSArd Biesheuvel } 315cf3d41adSArd Biesheuvel 316cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, left); 317cf3d41adSArd Biesheuvel 318cf3d41adSArd Biesheuvel pos += left; 319cf3d41adSArd Biesheuvel assoclen -= size; 320cf3d41adSArd Biesheuvel scatterwalk_unmap(mapped); 321cf3d41adSArd Biesheuvel scatterwalk_advance(&walk, size); 322cf3d41adSArd Biesheuvel scatterwalk_done(&walk, 0, assoclen); 323cf3d41adSArd Biesheuvel } 324cf3d41adSArd Biesheuvel 325cf3d41adSArd Biesheuvel if (pos > 0) { 326cf3d41adSArd Biesheuvel memset(buf.bytes + pos, 0, AEGIS_BLOCK_SIZE - pos); 327cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &buf); 328cf3d41adSArd Biesheuvel } 329cf3d41adSArd Biesheuvel } 330cf3d41adSArd Biesheuvel 3312698bce1SArd Biesheuvel static __always_inline 3322698bce1SArd Biesheuvel int crypto_aegis128_process_crypt(struct aegis_state *state, 3332698bce1SArd Biesheuvel struct skcipher_walk *walk, 3342698bce1SArd Biesheuvel void (*crypt)(struct aegis_state *state, 3352698bce1SArd Biesheuvel u8 *dst, const u8 *src, 3362698bce1SArd Biesheuvel unsigned int size)) 337cf3d41adSArd Biesheuvel { 3382698bce1SArd Biesheuvel int err = 0; 339cf3d41adSArd Biesheuvel 3402698bce1SArd Biesheuvel while (walk->nbytes) { 3412698bce1SArd Biesheuvel unsigned int nbytes = walk->nbytes; 342cf3d41adSArd Biesheuvel 3432698bce1SArd Biesheuvel if (nbytes < walk->total) 3442698bce1SArd Biesheuvel nbytes = round_down(nbytes, walk->stride); 345cf3d41adSArd Biesheuvel 3462698bce1SArd Biesheuvel crypt(state, walk->dst.virt.addr, walk->src.virt.addr, nbytes); 347cf3d41adSArd Biesheuvel 3482698bce1SArd Biesheuvel err = skcipher_walk_done(walk, walk->nbytes - nbytes); 349cf3d41adSArd Biesheuvel } 3502698bce1SArd Biesheuvel return err; 351cf3d41adSArd Biesheuvel } 352cf3d41adSArd Biesheuvel 353cf3d41adSArd Biesheuvel static void crypto_aegis128_final(struct aegis_state *state, 354cf3d41adSArd Biesheuvel union aegis_block *tag_xor, 355cf3d41adSArd Biesheuvel u64 assoclen, u64 cryptlen) 356cf3d41adSArd Biesheuvel { 357cf3d41adSArd Biesheuvel u64 assocbits = assoclen * 8; 358cf3d41adSArd Biesheuvel u64 cryptbits = cryptlen * 8; 359cf3d41adSArd Biesheuvel 360cf3d41adSArd Biesheuvel union aegis_block tmp; 361cf3d41adSArd Biesheuvel unsigned int i; 362cf3d41adSArd Biesheuvel 363cf3d41adSArd Biesheuvel tmp.words64[0] = cpu_to_le64(assocbits); 364cf3d41adSArd Biesheuvel tmp.words64[1] = cpu_to_le64(cryptbits); 365cf3d41adSArd Biesheuvel 366cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[3]); 367cf3d41adSArd Biesheuvel 368cf3d41adSArd Biesheuvel for (i = 0; i < 7; i++) 369cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 370cf3d41adSArd Biesheuvel 371cf3d41adSArd Biesheuvel for (i = 0; i < AEGIS128_STATE_BLOCKS; i++) 372cf3d41adSArd Biesheuvel crypto_aegis_block_xor(tag_xor, &state->blocks[i]); 373cf3d41adSArd Biesheuvel } 374cf3d41adSArd Biesheuvel 375cf3d41adSArd Biesheuvel static int crypto_aegis128_setkey(struct crypto_aead *aead, const u8 *key, 376cf3d41adSArd Biesheuvel unsigned int keylen) 377cf3d41adSArd Biesheuvel { 378cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(aead); 379cf3d41adSArd Biesheuvel 380674f368aSEric Biggers if (keylen != AEGIS128_KEY_SIZE) 381cf3d41adSArd Biesheuvel return -EINVAL; 382cf3d41adSArd Biesheuvel 383cf3d41adSArd Biesheuvel memcpy(ctx->key.bytes, key, AEGIS128_KEY_SIZE); 384cf3d41adSArd Biesheuvel return 0; 385cf3d41adSArd Biesheuvel } 386cf3d41adSArd Biesheuvel 387cf3d41adSArd Biesheuvel static int crypto_aegis128_setauthsize(struct crypto_aead *tfm, 388cf3d41adSArd Biesheuvel unsigned int authsize) 389cf3d41adSArd Biesheuvel { 390cf3d41adSArd Biesheuvel if (authsize > AEGIS128_MAX_AUTH_SIZE) 391cf3d41adSArd Biesheuvel return -EINVAL; 392cf3d41adSArd Biesheuvel if (authsize < AEGIS128_MIN_AUTH_SIZE) 393cf3d41adSArd Biesheuvel return -EINVAL; 394cf3d41adSArd Biesheuvel return 0; 395cf3d41adSArd Biesheuvel } 396cf3d41adSArd Biesheuvel 3972698bce1SArd Biesheuvel static int crypto_aegis128_encrypt(struct aead_request *req) 398cf3d41adSArd Biesheuvel { 399cf3d41adSArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 4002698bce1SArd Biesheuvel union aegis_block tag = {}; 4012698bce1SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 402cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 4032698bce1SArd Biesheuvel unsigned int cryptlen = req->cryptlen; 4042698bce1SArd Biesheuvel struct skcipher_walk walk; 405cf3d41adSArd Biesheuvel struct aegis_state state; 406cf3d41adSArd Biesheuvel 4072698bce1SArd Biesheuvel skcipher_walk_aead_encrypt(&walk, req, false); 40852828263SArd Biesheuvel if (aegis128_do_simd()) { 40952828263SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 41052828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 411*02685906SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 4122698bce1SArd Biesheuvel crypto_aegis128_encrypt_chunk_simd); 41352828263SArd Biesheuvel crypto_aegis128_final_simd(&state, &tag, req->assoclen, 41452828263SArd Biesheuvel cryptlen); 41552828263SArd Biesheuvel } else { 41652828263SArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 41752828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 418*02685906SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 4192698bce1SArd Biesheuvel crypto_aegis128_encrypt_chunk); 4202698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 42152828263SArd Biesheuvel } 422cf3d41adSArd Biesheuvel 423cf3d41adSArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, 424cf3d41adSArd Biesheuvel authsize, 1); 425cf3d41adSArd Biesheuvel return 0; 426cf3d41adSArd Biesheuvel } 427cf3d41adSArd Biesheuvel 428cf3d41adSArd Biesheuvel static int crypto_aegis128_decrypt(struct aead_request *req) 429cf3d41adSArd Biesheuvel { 430cf3d41adSArd Biesheuvel static const u8 zeros[AEGIS128_MAX_AUTH_SIZE] = {}; 431cf3d41adSArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 432cf3d41adSArd Biesheuvel union aegis_block tag; 433cf3d41adSArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 434cf3d41adSArd Biesheuvel unsigned int cryptlen = req->cryptlen - authsize; 4352698bce1SArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 4362698bce1SArd Biesheuvel struct skcipher_walk walk; 4372698bce1SArd Biesheuvel struct aegis_state state; 438cf3d41adSArd Biesheuvel 439cf3d41adSArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, 440cf3d41adSArd Biesheuvel authsize, 0); 441cf3d41adSArd Biesheuvel 4422698bce1SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 44352828263SArd Biesheuvel if (aegis128_do_simd()) { 44452828263SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 44552828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 446*02685906SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 4472698bce1SArd Biesheuvel crypto_aegis128_decrypt_chunk_simd); 44852828263SArd Biesheuvel crypto_aegis128_final_simd(&state, &tag, req->assoclen, 44952828263SArd Biesheuvel cryptlen); 45052828263SArd Biesheuvel } else { 45152828263SArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 45252828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 453*02685906SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 4542698bce1SArd Biesheuvel crypto_aegis128_decrypt_chunk); 4552698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 45652828263SArd Biesheuvel } 457cf3d41adSArd Biesheuvel 458*02685906SArd Biesheuvel if (unlikely(crypto_memneq(tag.bytes, zeros, authsize))) { 459*02685906SArd Biesheuvel /* 460*02685906SArd Biesheuvel * From Chapter 4. 'Security Analysis' of the AEGIS spec [0] 461*02685906SArd Biesheuvel * 462*02685906SArd Biesheuvel * "3. If verification fails, the decrypted plaintext and the 463*02685906SArd Biesheuvel * wrong authentication tag should not be given as output." 464*02685906SArd Biesheuvel * 465*02685906SArd Biesheuvel * [0] https://competitions.cr.yp.to/round3/aegisv11.pdf 466*02685906SArd Biesheuvel */ 467*02685906SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 468*02685906SArd Biesheuvel crypto_aegis128_process_crypt(NULL, &walk, 469*02685906SArd Biesheuvel crypto_aegis128_wipe_chunk); 470*02685906SArd Biesheuvel memzero_explicit(&tag, sizeof(tag)); 471*02685906SArd Biesheuvel return -EBADMSG; 472*02685906SArd Biesheuvel } 473*02685906SArd Biesheuvel return 0; 474cf3d41adSArd Biesheuvel } 475cf3d41adSArd Biesheuvel 476cf3d41adSArd Biesheuvel static struct aead_alg crypto_aegis128_alg = { 477cf3d41adSArd Biesheuvel .setkey = crypto_aegis128_setkey, 478cf3d41adSArd Biesheuvel .setauthsize = crypto_aegis128_setauthsize, 479cf3d41adSArd Biesheuvel .encrypt = crypto_aegis128_encrypt, 480cf3d41adSArd Biesheuvel .decrypt = crypto_aegis128_decrypt, 481cf3d41adSArd Biesheuvel 482cf3d41adSArd Biesheuvel .ivsize = AEGIS128_NONCE_SIZE, 483cf3d41adSArd Biesheuvel .maxauthsize = AEGIS128_MAX_AUTH_SIZE, 484cf3d41adSArd Biesheuvel .chunksize = AEGIS_BLOCK_SIZE, 485cf3d41adSArd Biesheuvel 486cf3d41adSArd Biesheuvel .base = { 487cf3d41adSArd Biesheuvel .cra_blocksize = 1, 488cf3d41adSArd Biesheuvel .cra_ctxsize = sizeof(struct aegis_ctx), 489cf3d41adSArd Biesheuvel .cra_alignmask = 0, 490cf3d41adSArd Biesheuvel 491cf3d41adSArd Biesheuvel .cra_priority = 100, 492cf3d41adSArd Biesheuvel 493cf3d41adSArd Biesheuvel .cra_name = "aegis128", 494cf3d41adSArd Biesheuvel .cra_driver_name = "aegis128-generic", 495cf3d41adSArd Biesheuvel 496cf3d41adSArd Biesheuvel .cra_module = THIS_MODULE, 497cf3d41adSArd Biesheuvel } 498cf3d41adSArd Biesheuvel }; 499cf3d41adSArd Biesheuvel 500cf3d41adSArd Biesheuvel static int __init crypto_aegis128_module_init(void) 501cf3d41adSArd Biesheuvel { 5022698bce1SArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 5032698bce1SArd Biesheuvel crypto_aegis128_have_simd()) 5042698bce1SArd Biesheuvel static_branch_enable(&have_simd); 505cf3d41adSArd Biesheuvel 506cf3d41adSArd Biesheuvel return crypto_register_aead(&crypto_aegis128_alg); 507cf3d41adSArd Biesheuvel } 508cf3d41adSArd Biesheuvel 509cf3d41adSArd Biesheuvel static void __exit crypto_aegis128_module_exit(void) 510cf3d41adSArd Biesheuvel { 511cf3d41adSArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg); 512cf3d41adSArd Biesheuvel } 513cf3d41adSArd Biesheuvel 514cf3d41adSArd Biesheuvel subsys_initcall(crypto_aegis128_module_init); 515cf3d41adSArd Biesheuvel module_exit(crypto_aegis128_module_exit); 516cf3d41adSArd Biesheuvel 517cf3d41adSArd Biesheuvel MODULE_LICENSE("GPL"); 518cf3d41adSArd Biesheuvel MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>"); 519cf3d41adSArd Biesheuvel MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm"); 520cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128"); 521cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128-generic"); 522