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); 63*52828263SArd Biesheuvel void crypto_aegis128_init_simd(struct aegis_state *state, 64*52828263SArd Biesheuvel const union aegis_block *key, 65*52828263SArd 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); 70*52828263SArd Biesheuvel void crypto_aegis128_final_simd(struct aegis_state *state, 71*52828263SArd Biesheuvel union aegis_block *tag_xor, 72*52828263SArd 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 157cf3d41adSArd Biesheuvel static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst, 158cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 159cf3d41adSArd Biesheuvel { 160cf3d41adSArd Biesheuvel union aegis_block tmp; 161cf3d41adSArd Biesheuvel 162cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 163cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 164cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 165cf3d41adSArd Biesheuvel (union aegis_block *)dst; 166cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 167cf3d41adSArd Biesheuvel (const union aegis_block *)src; 168cf3d41adSArd Biesheuvel 169cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 170cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 171cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 172cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 173cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 174cf3d41adSArd Biesheuvel 175cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, src_blk); 176cf3d41adSArd Biesheuvel 177cf3d41adSArd Biesheuvel *dst_blk = tmp; 178cf3d41adSArd Biesheuvel 179cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 180cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 181cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 182cf3d41adSArd Biesheuvel } 183cf3d41adSArd Biesheuvel } else { 184cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 185cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 186cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 187cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 188cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 189cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 190cf3d41adSArd Biesheuvel 191cf3d41adSArd Biesheuvel crypto_aegis128_update_u(state, src); 192cf3d41adSArd Biesheuvel 193cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 194cf3d41adSArd Biesheuvel 195cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 196cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 197cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 198cf3d41adSArd Biesheuvel } 199cf3d41adSArd Biesheuvel } 200cf3d41adSArd Biesheuvel 201cf3d41adSArd Biesheuvel if (size > 0) { 202cf3d41adSArd Biesheuvel union aegis_block msg = {}; 203cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 204cf3d41adSArd Biesheuvel 205cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 206cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 207cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 208cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 209cf3d41adSArd Biesheuvel 210cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &msg); 211cf3d41adSArd Biesheuvel 212cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 213cf3d41adSArd Biesheuvel 214cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 215cf3d41adSArd Biesheuvel } 216cf3d41adSArd Biesheuvel } 217cf3d41adSArd Biesheuvel 218cf3d41adSArd Biesheuvel static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst, 219cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 220cf3d41adSArd Biesheuvel { 221cf3d41adSArd Biesheuvel union aegis_block tmp; 222cf3d41adSArd Biesheuvel 223cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 224cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 225cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 226cf3d41adSArd Biesheuvel (union aegis_block *)dst; 227cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 228cf3d41adSArd Biesheuvel (const union aegis_block *)src; 229cf3d41adSArd Biesheuvel 230cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 231cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 232cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 233cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 234cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 235cf3d41adSArd Biesheuvel 236cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 237cf3d41adSArd Biesheuvel 238cf3d41adSArd Biesheuvel *dst_blk = tmp; 239cf3d41adSArd Biesheuvel 240cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 241cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 242cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 243cf3d41adSArd Biesheuvel } 244cf3d41adSArd Biesheuvel } else { 245cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 246cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 247cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 248cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 249cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 250cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 251cf3d41adSArd Biesheuvel 252cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 253cf3d41adSArd Biesheuvel 254cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 255cf3d41adSArd Biesheuvel 256cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 257cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 258cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 259cf3d41adSArd Biesheuvel } 260cf3d41adSArd Biesheuvel } 261cf3d41adSArd Biesheuvel 262cf3d41adSArd Biesheuvel if (size > 0) { 263cf3d41adSArd Biesheuvel union aegis_block msg = {}; 264cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 265cf3d41adSArd Biesheuvel 266cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 267cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 268cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 269cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 270cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 271cf3d41adSArd Biesheuvel 272cf3d41adSArd Biesheuvel memset(msg.bytes + size, 0, AEGIS_BLOCK_SIZE - size); 273cf3d41adSArd Biesheuvel 274cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &msg); 275cf3d41adSArd Biesheuvel 276cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 277cf3d41adSArd Biesheuvel } 278cf3d41adSArd Biesheuvel } 279cf3d41adSArd Biesheuvel 280cf3d41adSArd Biesheuvel static void crypto_aegis128_process_ad(struct aegis_state *state, 281cf3d41adSArd Biesheuvel struct scatterlist *sg_src, 282cf3d41adSArd Biesheuvel unsigned int assoclen) 283cf3d41adSArd Biesheuvel { 284cf3d41adSArd Biesheuvel struct scatter_walk walk; 285cf3d41adSArd Biesheuvel union aegis_block buf; 286cf3d41adSArd Biesheuvel unsigned int pos = 0; 287cf3d41adSArd Biesheuvel 288cf3d41adSArd Biesheuvel scatterwalk_start(&walk, sg_src); 289cf3d41adSArd Biesheuvel while (assoclen != 0) { 290cf3d41adSArd Biesheuvel unsigned int size = scatterwalk_clamp(&walk, assoclen); 291cf3d41adSArd Biesheuvel unsigned int left = size; 292cf3d41adSArd Biesheuvel void *mapped = scatterwalk_map(&walk); 293cf3d41adSArd Biesheuvel const u8 *src = (const u8 *)mapped; 294cf3d41adSArd Biesheuvel 295cf3d41adSArd Biesheuvel if (pos + size >= AEGIS_BLOCK_SIZE) { 296cf3d41adSArd Biesheuvel if (pos > 0) { 297cf3d41adSArd Biesheuvel unsigned int fill = AEGIS_BLOCK_SIZE - pos; 298cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, fill); 299cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &buf); 300cf3d41adSArd Biesheuvel pos = 0; 301cf3d41adSArd Biesheuvel left -= fill; 302cf3d41adSArd Biesheuvel src += fill; 303cf3d41adSArd Biesheuvel } 304cf3d41adSArd Biesheuvel 305cf3d41adSArd Biesheuvel crypto_aegis128_ad(state, src, left); 306cf3d41adSArd Biesheuvel src += left & ~(AEGIS_BLOCK_SIZE - 1); 307cf3d41adSArd Biesheuvel left &= AEGIS_BLOCK_SIZE - 1; 308cf3d41adSArd Biesheuvel } 309cf3d41adSArd Biesheuvel 310cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, left); 311cf3d41adSArd Biesheuvel 312cf3d41adSArd Biesheuvel pos += left; 313cf3d41adSArd Biesheuvel assoclen -= size; 314cf3d41adSArd Biesheuvel scatterwalk_unmap(mapped); 315cf3d41adSArd Biesheuvel scatterwalk_advance(&walk, size); 316cf3d41adSArd Biesheuvel scatterwalk_done(&walk, 0, assoclen); 317cf3d41adSArd Biesheuvel } 318cf3d41adSArd Biesheuvel 319cf3d41adSArd Biesheuvel if (pos > 0) { 320cf3d41adSArd Biesheuvel memset(buf.bytes + pos, 0, AEGIS_BLOCK_SIZE - pos); 321cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &buf); 322cf3d41adSArd Biesheuvel } 323cf3d41adSArd Biesheuvel } 324cf3d41adSArd Biesheuvel 3252698bce1SArd Biesheuvel static __always_inline 3262698bce1SArd Biesheuvel int crypto_aegis128_process_crypt(struct aegis_state *state, 327cf3d41adSArd Biesheuvel struct aead_request *req, 3282698bce1SArd Biesheuvel struct skcipher_walk *walk, 3292698bce1SArd Biesheuvel void (*crypt)(struct aegis_state *state, 3302698bce1SArd Biesheuvel u8 *dst, const u8 *src, 3312698bce1SArd Biesheuvel unsigned int size)) 332cf3d41adSArd Biesheuvel { 3332698bce1SArd Biesheuvel int err = 0; 334cf3d41adSArd Biesheuvel 3352698bce1SArd Biesheuvel while (walk->nbytes) { 3362698bce1SArd Biesheuvel unsigned int nbytes = walk->nbytes; 337cf3d41adSArd Biesheuvel 3382698bce1SArd Biesheuvel if (nbytes < walk->total) 3392698bce1SArd Biesheuvel nbytes = round_down(nbytes, walk->stride); 340cf3d41adSArd Biesheuvel 3412698bce1SArd Biesheuvel crypt(state, walk->dst.virt.addr, walk->src.virt.addr, nbytes); 342cf3d41adSArd Biesheuvel 3432698bce1SArd Biesheuvel err = skcipher_walk_done(walk, walk->nbytes - nbytes); 344cf3d41adSArd Biesheuvel } 3452698bce1SArd Biesheuvel return err; 346cf3d41adSArd Biesheuvel } 347cf3d41adSArd Biesheuvel 348cf3d41adSArd Biesheuvel static void crypto_aegis128_final(struct aegis_state *state, 349cf3d41adSArd Biesheuvel union aegis_block *tag_xor, 350cf3d41adSArd Biesheuvel u64 assoclen, u64 cryptlen) 351cf3d41adSArd Biesheuvel { 352cf3d41adSArd Biesheuvel u64 assocbits = assoclen * 8; 353cf3d41adSArd Biesheuvel u64 cryptbits = cryptlen * 8; 354cf3d41adSArd Biesheuvel 355cf3d41adSArd Biesheuvel union aegis_block tmp; 356cf3d41adSArd Biesheuvel unsigned int i; 357cf3d41adSArd Biesheuvel 358cf3d41adSArd Biesheuvel tmp.words64[0] = cpu_to_le64(assocbits); 359cf3d41adSArd Biesheuvel tmp.words64[1] = cpu_to_le64(cryptbits); 360cf3d41adSArd Biesheuvel 361cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[3]); 362cf3d41adSArd Biesheuvel 363cf3d41adSArd Biesheuvel for (i = 0; i < 7; i++) 364cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 365cf3d41adSArd Biesheuvel 366cf3d41adSArd Biesheuvel for (i = 0; i < AEGIS128_STATE_BLOCKS; i++) 367cf3d41adSArd Biesheuvel crypto_aegis_block_xor(tag_xor, &state->blocks[i]); 368cf3d41adSArd Biesheuvel } 369cf3d41adSArd Biesheuvel 370cf3d41adSArd Biesheuvel static int crypto_aegis128_setkey(struct crypto_aead *aead, const u8 *key, 371cf3d41adSArd Biesheuvel unsigned int keylen) 372cf3d41adSArd Biesheuvel { 373cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(aead); 374cf3d41adSArd Biesheuvel 375cf3d41adSArd Biesheuvel if (keylen != AEGIS128_KEY_SIZE) { 376cf3d41adSArd Biesheuvel crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); 377cf3d41adSArd Biesheuvel return -EINVAL; 378cf3d41adSArd Biesheuvel } 379cf3d41adSArd Biesheuvel 380cf3d41adSArd Biesheuvel memcpy(ctx->key.bytes, key, AEGIS128_KEY_SIZE); 381cf3d41adSArd Biesheuvel return 0; 382cf3d41adSArd Biesheuvel } 383cf3d41adSArd Biesheuvel 384cf3d41adSArd Biesheuvel static int crypto_aegis128_setauthsize(struct crypto_aead *tfm, 385cf3d41adSArd Biesheuvel unsigned int authsize) 386cf3d41adSArd Biesheuvel { 387cf3d41adSArd Biesheuvel if (authsize > AEGIS128_MAX_AUTH_SIZE) 388cf3d41adSArd Biesheuvel return -EINVAL; 389cf3d41adSArd Biesheuvel if (authsize < AEGIS128_MIN_AUTH_SIZE) 390cf3d41adSArd Biesheuvel return -EINVAL; 391cf3d41adSArd Biesheuvel return 0; 392cf3d41adSArd Biesheuvel } 393cf3d41adSArd Biesheuvel 3942698bce1SArd Biesheuvel static int crypto_aegis128_encrypt(struct aead_request *req) 395cf3d41adSArd Biesheuvel { 396cf3d41adSArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 3972698bce1SArd Biesheuvel union aegis_block tag = {}; 3982698bce1SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 399cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 4002698bce1SArd Biesheuvel unsigned int cryptlen = req->cryptlen; 4012698bce1SArd Biesheuvel struct skcipher_walk walk; 402cf3d41adSArd Biesheuvel struct aegis_state state; 403cf3d41adSArd Biesheuvel 4042698bce1SArd Biesheuvel skcipher_walk_aead_encrypt(&walk, req, false); 405*52828263SArd Biesheuvel if (aegis128_do_simd()) { 406*52828263SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 407*52828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 4082698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 4092698bce1SArd Biesheuvel crypto_aegis128_encrypt_chunk_simd); 410*52828263SArd Biesheuvel crypto_aegis128_final_simd(&state, &tag, req->assoclen, 411*52828263SArd Biesheuvel cryptlen); 412*52828263SArd Biesheuvel } else { 413*52828263SArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 414*52828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 4152698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 4162698bce1SArd Biesheuvel crypto_aegis128_encrypt_chunk); 4172698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 418*52828263SArd Biesheuvel } 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 425cf3d41adSArd Biesheuvel static int crypto_aegis128_decrypt(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); 440*52828263SArd Biesheuvel if (aegis128_do_simd()) { 441*52828263SArd Biesheuvel crypto_aegis128_init_simd(&state, &ctx->key, req->iv); 442*52828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 4432698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 4442698bce1SArd Biesheuvel crypto_aegis128_decrypt_chunk_simd); 445*52828263SArd Biesheuvel crypto_aegis128_final_simd(&state, &tag, req->assoclen, 446*52828263SArd Biesheuvel cryptlen); 447*52828263SArd Biesheuvel } else { 448*52828263SArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 449*52828263SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 4502698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 4512698bce1SArd Biesheuvel crypto_aegis128_decrypt_chunk); 4522698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 453*52828263SArd Biesheuvel } 454cf3d41adSArd Biesheuvel 455cf3d41adSArd Biesheuvel return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; 456cf3d41adSArd Biesheuvel } 457cf3d41adSArd Biesheuvel 458cf3d41adSArd Biesheuvel static struct aead_alg crypto_aegis128_alg = { 459cf3d41adSArd Biesheuvel .setkey = crypto_aegis128_setkey, 460cf3d41adSArd Biesheuvel .setauthsize = crypto_aegis128_setauthsize, 461cf3d41adSArd Biesheuvel .encrypt = crypto_aegis128_encrypt, 462cf3d41adSArd Biesheuvel .decrypt = crypto_aegis128_decrypt, 463cf3d41adSArd Biesheuvel 464cf3d41adSArd Biesheuvel .ivsize = AEGIS128_NONCE_SIZE, 465cf3d41adSArd Biesheuvel .maxauthsize = AEGIS128_MAX_AUTH_SIZE, 466cf3d41adSArd Biesheuvel .chunksize = AEGIS_BLOCK_SIZE, 467cf3d41adSArd Biesheuvel 468cf3d41adSArd Biesheuvel .base = { 469cf3d41adSArd Biesheuvel .cra_blocksize = 1, 470cf3d41adSArd Biesheuvel .cra_ctxsize = sizeof(struct aegis_ctx), 471cf3d41adSArd Biesheuvel .cra_alignmask = 0, 472cf3d41adSArd Biesheuvel 473cf3d41adSArd Biesheuvel .cra_priority = 100, 474cf3d41adSArd Biesheuvel 475cf3d41adSArd Biesheuvel .cra_name = "aegis128", 476cf3d41adSArd Biesheuvel .cra_driver_name = "aegis128-generic", 477cf3d41adSArd Biesheuvel 478cf3d41adSArd Biesheuvel .cra_module = THIS_MODULE, 479cf3d41adSArd Biesheuvel } 480cf3d41adSArd Biesheuvel }; 481cf3d41adSArd Biesheuvel 482cf3d41adSArd Biesheuvel static int __init crypto_aegis128_module_init(void) 483cf3d41adSArd Biesheuvel { 4842698bce1SArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 4852698bce1SArd Biesheuvel crypto_aegis128_have_simd()) 4862698bce1SArd Biesheuvel static_branch_enable(&have_simd); 487cf3d41adSArd Biesheuvel 488cf3d41adSArd Biesheuvel return crypto_register_aead(&crypto_aegis128_alg); 489cf3d41adSArd Biesheuvel } 490cf3d41adSArd Biesheuvel 491cf3d41adSArd Biesheuvel static void __exit crypto_aegis128_module_exit(void) 492cf3d41adSArd Biesheuvel { 493cf3d41adSArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg); 494cf3d41adSArd Biesheuvel } 495cf3d41adSArd Biesheuvel 496cf3d41adSArd Biesheuvel subsys_initcall(crypto_aegis128_module_init); 497cf3d41adSArd Biesheuvel module_exit(crypto_aegis128_module_exit); 498cf3d41adSArd Biesheuvel 499cf3d41adSArd Biesheuvel MODULE_LICENSE("GPL"); 500cf3d41adSArd Biesheuvel MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>"); 501cf3d41adSArd Biesheuvel MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm"); 502cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128"); 503cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128-generic"); 504