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, 89ac50aec4SArd Biesheuvel const union aegis_block *msg, 90ac50aec4SArd Biesheuvel bool do_simd) 91cf3d41adSArd Biesheuvel { 92*0464e0efSArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 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 101ac50aec4SArd Biesheuvel static void crypto_aegis128_update_u(struct aegis_state *state, const void *msg, 102ac50aec4SArd Biesheuvel bool do_simd) 103cf3d41adSArd Biesheuvel { 104*0464e0efSArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 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++) { 133ac50aec4SArd Biesheuvel crypto_aegis128_update_a(state, key, false); 134ac50aec4SArd 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, 139ac50aec4SArd Biesheuvel const u8 *src, unsigned int size, 140ac50aec4SArd 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) { 147ac50aec4SArd 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) { 154ac50aec4SArd 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 186ac50aec4SArd 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 202ac50aec4SArd 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 221ac50aec4SArd 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 247ac50aec4SArd 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 263ac50aec4SArd 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 285ac50aec4SArd 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, 293ac50aec4SArd Biesheuvel unsigned int assoclen, 294ac50aec4SArd 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); 311ac50aec4SArd 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 317ac50aec4SArd 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); 333ac50aec4SArd 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++) 375ac50aec4SArd 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 403ac50aec4SArd 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); 415ac50aec4SArd 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 425ac50aec4SArd 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); 441ac50aec4SArd 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 464ac50aec4SArd Biesheuvel static int crypto_aegis128_encrypt_simd(struct aead_request *req) 465ac50aec4SArd Biesheuvel { 466ac50aec4SArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 467ac50aec4SArd Biesheuvel union aegis_block tag = {}; 468ac50aec4SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 469ac50aec4SArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 470ac50aec4SArd Biesheuvel unsigned int cryptlen = req->cryptlen; 471ac50aec4SArd Biesheuvel struct skcipher_walk walk; 472ac50aec4SArd Biesheuvel struct aegis_state state; 473ac50aec4SArd Biesheuvel 474ac50aec4SArd Biesheuvel if (!aegis128_do_simd()) 475ac50aec4SArd Biesheuvel return crypto_aegis128_encrypt_generic(req); 476ac50aec4SArd Biesheuvel 477ac50aec4SArd Biesheuvel skcipher_walk_aead_encrypt(&walk, req, false); 478ac50aec4SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 479ac50aec4SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen, true); 480ac50aec4SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 481ac50aec4SArd Biesheuvel crypto_aegis128_encrypt_chunk_simd); 482ac50aec4SArd Biesheuvel crypto_aegis128_final_simd(&state, &tag, req->assoclen, cryptlen, 0); 483ac50aec4SArd Biesheuvel 484ac50aec4SArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, 485ac50aec4SArd Biesheuvel authsize, 1); 486ac50aec4SArd Biesheuvel return 0; 487ac50aec4SArd Biesheuvel } 488ac50aec4SArd Biesheuvel 489ac50aec4SArd Biesheuvel static int crypto_aegis128_decrypt_simd(struct aead_request *req) 490ac50aec4SArd Biesheuvel { 491ac50aec4SArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 492ac50aec4SArd Biesheuvel union aegis_block tag; 493ac50aec4SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 494ac50aec4SArd Biesheuvel unsigned int cryptlen = req->cryptlen - authsize; 495ac50aec4SArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 496ac50aec4SArd Biesheuvel struct skcipher_walk walk; 497ac50aec4SArd Biesheuvel struct aegis_state state; 498ac50aec4SArd Biesheuvel 499ac50aec4SArd Biesheuvel if (!aegis128_do_simd()) 500ac50aec4SArd Biesheuvel return crypto_aegis128_decrypt_generic(req); 501ac50aec4SArd Biesheuvel 502ac50aec4SArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, 503ac50aec4SArd Biesheuvel authsize, 0); 504ac50aec4SArd Biesheuvel 505ac50aec4SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 506ac50aec4SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 507ac50aec4SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen, true); 508ac50aec4SArd Biesheuvel crypto_aegis128_process_crypt(&state, &walk, 509ac50aec4SArd Biesheuvel crypto_aegis128_decrypt_chunk_simd); 510ac50aec4SArd Biesheuvel 511ac50aec4SArd Biesheuvel if (unlikely(crypto_aegis128_final_simd(&state, &tag, req->assoclen, 512ac50aec4SArd Biesheuvel cryptlen, authsize))) { 513ac50aec4SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 514ac50aec4SArd Biesheuvel crypto_aegis128_process_crypt(NULL, &walk, 515ac50aec4SArd Biesheuvel crypto_aegis128_wipe_chunk); 516ac50aec4SArd Biesheuvel return -EBADMSG; 517ac50aec4SArd Biesheuvel } 518ac50aec4SArd Biesheuvel return 0; 519ac50aec4SArd Biesheuvel } 520ac50aec4SArd Biesheuvel 521ac50aec4SArd Biesheuvel static struct aead_alg crypto_aegis128_alg_generic = { 522cf3d41adSArd Biesheuvel .setkey = crypto_aegis128_setkey, 523cf3d41adSArd Biesheuvel .setauthsize = crypto_aegis128_setauthsize, 524ac50aec4SArd Biesheuvel .encrypt = crypto_aegis128_encrypt_generic, 525ac50aec4SArd 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 531ac50aec4SArd Biesheuvel .base.cra_blocksize = 1, 532ac50aec4SArd Biesheuvel .base.cra_ctxsize = sizeof(struct aegis_ctx), 533ac50aec4SArd Biesheuvel .base.cra_alignmask = 0, 534ac50aec4SArd Biesheuvel .base.cra_priority = 100, 535ac50aec4SArd Biesheuvel .base.cra_name = "aegis128", 536ac50aec4SArd Biesheuvel .base.cra_driver_name = "aegis128-generic", 537ac50aec4SArd Biesheuvel .base.cra_module = THIS_MODULE, 538ac50aec4SArd Biesheuvel }; 539cf3d41adSArd Biesheuvel 540ac50aec4SArd Biesheuvel static struct aead_alg crypto_aegis128_alg_simd = { 541ac50aec4SArd Biesheuvel .setkey = crypto_aegis128_setkey, 542ac50aec4SArd Biesheuvel .setauthsize = crypto_aegis128_setauthsize, 543ac50aec4SArd Biesheuvel .encrypt = crypto_aegis128_encrypt_simd, 544ac50aec4SArd Biesheuvel .decrypt = crypto_aegis128_decrypt_simd, 545cf3d41adSArd Biesheuvel 546ac50aec4SArd Biesheuvel .ivsize = AEGIS128_NONCE_SIZE, 547ac50aec4SArd Biesheuvel .maxauthsize = AEGIS128_MAX_AUTH_SIZE, 548ac50aec4SArd Biesheuvel .chunksize = AEGIS_BLOCK_SIZE, 549cf3d41adSArd Biesheuvel 550ac50aec4SArd Biesheuvel .base.cra_blocksize = 1, 551ac50aec4SArd Biesheuvel .base.cra_ctxsize = sizeof(struct aegis_ctx), 552ac50aec4SArd Biesheuvel .base.cra_alignmask = 0, 553ac50aec4SArd Biesheuvel .base.cra_priority = 200, 554ac50aec4SArd Biesheuvel .base.cra_name = "aegis128", 555ac50aec4SArd Biesheuvel .base.cra_driver_name = "aegis128-simd", 556ac50aec4SArd Biesheuvel .base.cra_module = THIS_MODULE, 557cf3d41adSArd Biesheuvel }; 558cf3d41adSArd Biesheuvel 559cf3d41adSArd Biesheuvel static int __init crypto_aegis128_module_init(void) 560cf3d41adSArd Biesheuvel { 561ac50aec4SArd Biesheuvel int ret; 562cf3d41adSArd Biesheuvel 563ac50aec4SArd Biesheuvel ret = crypto_register_aead(&crypto_aegis128_alg_generic); 564ac50aec4SArd Biesheuvel if (ret) 565ac50aec4SArd Biesheuvel return ret; 566ac50aec4SArd Biesheuvel 567ac50aec4SArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 568ac50aec4SArd Biesheuvel crypto_aegis128_have_simd()) { 569ac50aec4SArd Biesheuvel ret = crypto_register_aead(&crypto_aegis128_alg_simd); 570ac50aec4SArd Biesheuvel if (ret) { 571ac50aec4SArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg_generic); 572ac50aec4SArd Biesheuvel return ret; 573ac50aec4SArd Biesheuvel } 574ac50aec4SArd Biesheuvel static_branch_enable(&have_simd); 575ac50aec4SArd Biesheuvel } 576ac50aec4SArd Biesheuvel return 0; 577cf3d41adSArd Biesheuvel } 578cf3d41adSArd Biesheuvel 579cf3d41adSArd Biesheuvel static void __exit crypto_aegis128_module_exit(void) 580cf3d41adSArd Biesheuvel { 581ac50aec4SArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 582ac50aec4SArd Biesheuvel crypto_aegis128_have_simd()) 583ac50aec4SArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg_simd); 584ac50aec4SArd Biesheuvel 585ac50aec4SArd 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"); 596ac50aec4SArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128-simd"); 597