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> 16*2698bce1SArd 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 39*2698bce1SArd 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 55*2698bce1SArd 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); 63cf3d41adSArd Biesheuvel void crypto_aegis128_encrypt_chunk_simd(struct aegis_state *state, u8 *dst, 64cf3d41adSArd Biesheuvel const u8 *src, unsigned int size); 65cf3d41adSArd Biesheuvel void crypto_aegis128_decrypt_chunk_simd(struct aegis_state *state, u8 *dst, 66cf3d41adSArd Biesheuvel const u8 *src, unsigned int size); 67cf3d41adSArd Biesheuvel 68cf3d41adSArd Biesheuvel static void crypto_aegis128_update(struct aegis_state *state) 69cf3d41adSArd Biesheuvel { 70cf3d41adSArd Biesheuvel union aegis_block tmp; 71cf3d41adSArd Biesheuvel unsigned int i; 72cf3d41adSArd Biesheuvel 73cf3d41adSArd Biesheuvel tmp = state->blocks[AEGIS128_STATE_BLOCKS - 1]; 74cf3d41adSArd Biesheuvel for (i = AEGIS128_STATE_BLOCKS - 1; i > 0; i--) 75cf3d41adSArd Biesheuvel crypto_aegis_aesenc(&state->blocks[i], &state->blocks[i - 1], 76cf3d41adSArd Biesheuvel &state->blocks[i]); 77cf3d41adSArd Biesheuvel crypto_aegis_aesenc(&state->blocks[0], &tmp, &state->blocks[0]); 78cf3d41adSArd Biesheuvel } 79cf3d41adSArd Biesheuvel 80cf3d41adSArd Biesheuvel static void crypto_aegis128_update_a(struct aegis_state *state, 81cf3d41adSArd Biesheuvel const union aegis_block *msg) 82cf3d41adSArd Biesheuvel { 83cf3d41adSArd Biesheuvel if (aegis128_do_simd()) { 84cf3d41adSArd Biesheuvel crypto_aegis128_update_simd(state, msg); 85cf3d41adSArd Biesheuvel return; 86cf3d41adSArd Biesheuvel } 87cf3d41adSArd Biesheuvel 88cf3d41adSArd Biesheuvel crypto_aegis128_update(state); 89cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[0], msg); 90cf3d41adSArd Biesheuvel } 91cf3d41adSArd Biesheuvel 92cf3d41adSArd Biesheuvel static void crypto_aegis128_update_u(struct aegis_state *state, const void *msg) 93cf3d41adSArd Biesheuvel { 94cf3d41adSArd Biesheuvel if (aegis128_do_simd()) { 95cf3d41adSArd Biesheuvel crypto_aegis128_update_simd(state, msg); 96cf3d41adSArd Biesheuvel return; 97cf3d41adSArd Biesheuvel } 98cf3d41adSArd Biesheuvel 99cf3d41adSArd Biesheuvel crypto_aegis128_update(state); 100cf3d41adSArd Biesheuvel crypto_xor(state->blocks[0].bytes, msg, AEGIS_BLOCK_SIZE); 101cf3d41adSArd Biesheuvel } 102cf3d41adSArd Biesheuvel 103cf3d41adSArd Biesheuvel static void crypto_aegis128_init(struct aegis_state *state, 104cf3d41adSArd Biesheuvel const union aegis_block *key, 105cf3d41adSArd Biesheuvel const u8 *iv) 106cf3d41adSArd Biesheuvel { 107cf3d41adSArd Biesheuvel union aegis_block key_iv; 108cf3d41adSArd Biesheuvel unsigned int i; 109cf3d41adSArd Biesheuvel 110cf3d41adSArd Biesheuvel key_iv = *key; 111cf3d41adSArd Biesheuvel crypto_xor(key_iv.bytes, iv, AEGIS_BLOCK_SIZE); 112cf3d41adSArd Biesheuvel 113cf3d41adSArd Biesheuvel state->blocks[0] = key_iv; 114cf3d41adSArd Biesheuvel state->blocks[1] = crypto_aegis_const[1]; 115cf3d41adSArd Biesheuvel state->blocks[2] = crypto_aegis_const[0]; 116cf3d41adSArd Biesheuvel state->blocks[3] = *key; 117cf3d41adSArd Biesheuvel state->blocks[4] = *key; 118cf3d41adSArd Biesheuvel 119cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[3], &crypto_aegis_const[0]); 120cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&state->blocks[4], &crypto_aegis_const[1]); 121cf3d41adSArd Biesheuvel 122cf3d41adSArd Biesheuvel for (i = 0; i < 5; i++) { 123cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, key); 124cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &key_iv); 125cf3d41adSArd Biesheuvel } 126cf3d41adSArd Biesheuvel } 127cf3d41adSArd Biesheuvel 128cf3d41adSArd Biesheuvel static void crypto_aegis128_ad(struct aegis_state *state, 129cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 130cf3d41adSArd Biesheuvel { 131cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src)) { 132cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 133cf3d41adSArd Biesheuvel (const union aegis_block *)src; 134cf3d41adSArd Biesheuvel 135cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 136cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, src_blk); 137cf3d41adSArd Biesheuvel 138cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 139cf3d41adSArd Biesheuvel src_blk++; 140cf3d41adSArd Biesheuvel } 141cf3d41adSArd Biesheuvel } else { 142cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 143cf3d41adSArd Biesheuvel crypto_aegis128_update_u(state, src); 144cf3d41adSArd Biesheuvel 145cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 146cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 147cf3d41adSArd Biesheuvel } 148cf3d41adSArd Biesheuvel } 149cf3d41adSArd Biesheuvel } 150cf3d41adSArd Biesheuvel 151cf3d41adSArd Biesheuvel static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst, 152cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 153cf3d41adSArd Biesheuvel { 154cf3d41adSArd Biesheuvel union aegis_block tmp; 155cf3d41adSArd Biesheuvel 156cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 157cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 158cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 159cf3d41adSArd Biesheuvel (union aegis_block *)dst; 160cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 161cf3d41adSArd Biesheuvel (const union aegis_block *)src; 162cf3d41adSArd Biesheuvel 163cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 164cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 165cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 166cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 167cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 168cf3d41adSArd Biesheuvel 169cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, src_blk); 170cf3d41adSArd Biesheuvel 171cf3d41adSArd Biesheuvel *dst_blk = tmp; 172cf3d41adSArd Biesheuvel 173cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 174cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 175cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 176cf3d41adSArd Biesheuvel } 177cf3d41adSArd Biesheuvel } else { 178cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 179cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 180cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 181cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 182cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 183cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 184cf3d41adSArd Biesheuvel 185cf3d41adSArd Biesheuvel crypto_aegis128_update_u(state, src); 186cf3d41adSArd Biesheuvel 187cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 188cf3d41adSArd Biesheuvel 189cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 190cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 191cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 192cf3d41adSArd Biesheuvel } 193cf3d41adSArd Biesheuvel } 194cf3d41adSArd Biesheuvel 195cf3d41adSArd Biesheuvel if (size > 0) { 196cf3d41adSArd Biesheuvel union aegis_block msg = {}; 197cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 198cf3d41adSArd Biesheuvel 199cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 200cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 201cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 202cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 203cf3d41adSArd Biesheuvel 204cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &msg); 205cf3d41adSArd Biesheuvel 206cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 207cf3d41adSArd Biesheuvel 208cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 209cf3d41adSArd Biesheuvel } 210cf3d41adSArd Biesheuvel } 211cf3d41adSArd Biesheuvel 212cf3d41adSArd Biesheuvel static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst, 213cf3d41adSArd Biesheuvel const u8 *src, unsigned int size) 214cf3d41adSArd Biesheuvel { 215cf3d41adSArd Biesheuvel union aegis_block tmp; 216cf3d41adSArd Biesheuvel 217cf3d41adSArd Biesheuvel if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { 218cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 219cf3d41adSArd Biesheuvel union aegis_block *dst_blk = 220cf3d41adSArd Biesheuvel (union aegis_block *)dst; 221cf3d41adSArd Biesheuvel const union aegis_block *src_blk = 222cf3d41adSArd Biesheuvel (const union aegis_block *)src; 223cf3d41adSArd Biesheuvel 224cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 225cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 226cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 227cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 228cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, src_blk); 229cf3d41adSArd Biesheuvel 230cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 231cf3d41adSArd Biesheuvel 232cf3d41adSArd Biesheuvel *dst_blk = tmp; 233cf3d41adSArd Biesheuvel 234cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 235cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 236cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 237cf3d41adSArd Biesheuvel } 238cf3d41adSArd Biesheuvel } else { 239cf3d41adSArd Biesheuvel while (size >= AEGIS_BLOCK_SIZE) { 240cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 241cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 242cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 243cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 244cf3d41adSArd Biesheuvel crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); 245cf3d41adSArd Biesheuvel 246cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 247cf3d41adSArd Biesheuvel 248cf3d41adSArd Biesheuvel memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); 249cf3d41adSArd Biesheuvel 250cf3d41adSArd Biesheuvel size -= AEGIS_BLOCK_SIZE; 251cf3d41adSArd Biesheuvel src += AEGIS_BLOCK_SIZE; 252cf3d41adSArd Biesheuvel dst += AEGIS_BLOCK_SIZE; 253cf3d41adSArd Biesheuvel } 254cf3d41adSArd Biesheuvel } 255cf3d41adSArd Biesheuvel 256cf3d41adSArd Biesheuvel if (size > 0) { 257cf3d41adSArd Biesheuvel union aegis_block msg = {}; 258cf3d41adSArd Biesheuvel memcpy(msg.bytes, src, size); 259cf3d41adSArd Biesheuvel 260cf3d41adSArd Biesheuvel tmp = state->blocks[2]; 261cf3d41adSArd Biesheuvel crypto_aegis_block_and(&tmp, &state->blocks[3]); 262cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[4]); 263cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[1]); 264cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&msg, &tmp); 265cf3d41adSArd Biesheuvel 266cf3d41adSArd Biesheuvel memset(msg.bytes + size, 0, AEGIS_BLOCK_SIZE - size); 267cf3d41adSArd Biesheuvel 268cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &msg); 269cf3d41adSArd Biesheuvel 270cf3d41adSArd Biesheuvel memcpy(dst, msg.bytes, size); 271cf3d41adSArd Biesheuvel } 272cf3d41adSArd Biesheuvel } 273cf3d41adSArd Biesheuvel 274cf3d41adSArd Biesheuvel static void crypto_aegis128_process_ad(struct aegis_state *state, 275cf3d41adSArd Biesheuvel struct scatterlist *sg_src, 276cf3d41adSArd Biesheuvel unsigned int assoclen) 277cf3d41adSArd Biesheuvel { 278cf3d41adSArd Biesheuvel struct scatter_walk walk; 279cf3d41adSArd Biesheuvel union aegis_block buf; 280cf3d41adSArd Biesheuvel unsigned int pos = 0; 281cf3d41adSArd Biesheuvel 282cf3d41adSArd Biesheuvel scatterwalk_start(&walk, sg_src); 283cf3d41adSArd Biesheuvel while (assoclen != 0) { 284cf3d41adSArd Biesheuvel unsigned int size = scatterwalk_clamp(&walk, assoclen); 285cf3d41adSArd Biesheuvel unsigned int left = size; 286cf3d41adSArd Biesheuvel void *mapped = scatterwalk_map(&walk); 287cf3d41adSArd Biesheuvel const u8 *src = (const u8 *)mapped; 288cf3d41adSArd Biesheuvel 289cf3d41adSArd Biesheuvel if (pos + size >= AEGIS_BLOCK_SIZE) { 290cf3d41adSArd Biesheuvel if (pos > 0) { 291cf3d41adSArd Biesheuvel unsigned int fill = AEGIS_BLOCK_SIZE - pos; 292cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, fill); 293cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &buf); 294cf3d41adSArd Biesheuvel pos = 0; 295cf3d41adSArd Biesheuvel left -= fill; 296cf3d41adSArd Biesheuvel src += fill; 297cf3d41adSArd Biesheuvel } 298cf3d41adSArd Biesheuvel 299cf3d41adSArd Biesheuvel crypto_aegis128_ad(state, src, left); 300cf3d41adSArd Biesheuvel src += left & ~(AEGIS_BLOCK_SIZE - 1); 301cf3d41adSArd Biesheuvel left &= AEGIS_BLOCK_SIZE - 1; 302cf3d41adSArd Biesheuvel } 303cf3d41adSArd Biesheuvel 304cf3d41adSArd Biesheuvel memcpy(buf.bytes + pos, src, left); 305cf3d41adSArd Biesheuvel 306cf3d41adSArd Biesheuvel pos += left; 307cf3d41adSArd Biesheuvel assoclen -= size; 308cf3d41adSArd Biesheuvel scatterwalk_unmap(mapped); 309cf3d41adSArd Biesheuvel scatterwalk_advance(&walk, size); 310cf3d41adSArd Biesheuvel scatterwalk_done(&walk, 0, assoclen); 311cf3d41adSArd Biesheuvel } 312cf3d41adSArd Biesheuvel 313cf3d41adSArd Biesheuvel if (pos > 0) { 314cf3d41adSArd Biesheuvel memset(buf.bytes + pos, 0, AEGIS_BLOCK_SIZE - pos); 315cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &buf); 316cf3d41adSArd Biesheuvel } 317cf3d41adSArd Biesheuvel } 318cf3d41adSArd Biesheuvel 319*2698bce1SArd Biesheuvel static __always_inline 320*2698bce1SArd Biesheuvel int crypto_aegis128_process_crypt(struct aegis_state *state, 321cf3d41adSArd Biesheuvel struct aead_request *req, 322*2698bce1SArd Biesheuvel struct skcipher_walk *walk, 323*2698bce1SArd Biesheuvel void (*crypt)(struct aegis_state *state, 324*2698bce1SArd Biesheuvel u8 *dst, const u8 *src, 325*2698bce1SArd Biesheuvel unsigned int size)) 326cf3d41adSArd Biesheuvel { 327*2698bce1SArd Biesheuvel int err = 0; 328cf3d41adSArd Biesheuvel 329*2698bce1SArd Biesheuvel while (walk->nbytes) { 330*2698bce1SArd Biesheuvel unsigned int nbytes = walk->nbytes; 331cf3d41adSArd Biesheuvel 332*2698bce1SArd Biesheuvel if (nbytes < walk->total) 333*2698bce1SArd Biesheuvel nbytes = round_down(nbytes, walk->stride); 334cf3d41adSArd Biesheuvel 335*2698bce1SArd Biesheuvel crypt(state, walk->dst.virt.addr, walk->src.virt.addr, nbytes); 336cf3d41adSArd Biesheuvel 337*2698bce1SArd Biesheuvel err = skcipher_walk_done(walk, walk->nbytes - nbytes); 338cf3d41adSArd Biesheuvel } 339*2698bce1SArd Biesheuvel return err; 340cf3d41adSArd Biesheuvel } 341cf3d41adSArd Biesheuvel 342cf3d41adSArd Biesheuvel static void crypto_aegis128_final(struct aegis_state *state, 343cf3d41adSArd Biesheuvel union aegis_block *tag_xor, 344cf3d41adSArd Biesheuvel u64 assoclen, u64 cryptlen) 345cf3d41adSArd Biesheuvel { 346cf3d41adSArd Biesheuvel u64 assocbits = assoclen * 8; 347cf3d41adSArd Biesheuvel u64 cryptbits = cryptlen * 8; 348cf3d41adSArd Biesheuvel 349cf3d41adSArd Biesheuvel union aegis_block tmp; 350cf3d41adSArd Biesheuvel unsigned int i; 351cf3d41adSArd Biesheuvel 352cf3d41adSArd Biesheuvel tmp.words64[0] = cpu_to_le64(assocbits); 353cf3d41adSArd Biesheuvel tmp.words64[1] = cpu_to_le64(cryptbits); 354cf3d41adSArd Biesheuvel 355cf3d41adSArd Biesheuvel crypto_aegis_block_xor(&tmp, &state->blocks[3]); 356cf3d41adSArd Biesheuvel 357cf3d41adSArd Biesheuvel for (i = 0; i < 7; i++) 358cf3d41adSArd Biesheuvel crypto_aegis128_update_a(state, &tmp); 359cf3d41adSArd Biesheuvel 360cf3d41adSArd Biesheuvel for (i = 0; i < AEGIS128_STATE_BLOCKS; i++) 361cf3d41adSArd Biesheuvel crypto_aegis_block_xor(tag_xor, &state->blocks[i]); 362cf3d41adSArd Biesheuvel } 363cf3d41adSArd Biesheuvel 364cf3d41adSArd Biesheuvel static int crypto_aegis128_setkey(struct crypto_aead *aead, const u8 *key, 365cf3d41adSArd Biesheuvel unsigned int keylen) 366cf3d41adSArd Biesheuvel { 367cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(aead); 368cf3d41adSArd Biesheuvel 369cf3d41adSArd Biesheuvel if (keylen != AEGIS128_KEY_SIZE) { 370cf3d41adSArd Biesheuvel crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); 371cf3d41adSArd Biesheuvel return -EINVAL; 372cf3d41adSArd Biesheuvel } 373cf3d41adSArd Biesheuvel 374cf3d41adSArd Biesheuvel memcpy(ctx->key.bytes, key, AEGIS128_KEY_SIZE); 375cf3d41adSArd Biesheuvel return 0; 376cf3d41adSArd Biesheuvel } 377cf3d41adSArd Biesheuvel 378cf3d41adSArd Biesheuvel static int crypto_aegis128_setauthsize(struct crypto_aead *tfm, 379cf3d41adSArd Biesheuvel unsigned int authsize) 380cf3d41adSArd Biesheuvel { 381cf3d41adSArd Biesheuvel if (authsize > AEGIS128_MAX_AUTH_SIZE) 382cf3d41adSArd Biesheuvel return -EINVAL; 383cf3d41adSArd Biesheuvel if (authsize < AEGIS128_MIN_AUTH_SIZE) 384cf3d41adSArd Biesheuvel return -EINVAL; 385cf3d41adSArd Biesheuvel return 0; 386cf3d41adSArd Biesheuvel } 387cf3d41adSArd Biesheuvel 388*2698bce1SArd Biesheuvel static int crypto_aegis128_encrypt(struct aead_request *req) 389cf3d41adSArd Biesheuvel { 390cf3d41adSArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 391*2698bce1SArd Biesheuvel union aegis_block tag = {}; 392*2698bce1SArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 393cf3d41adSArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 394*2698bce1SArd Biesheuvel unsigned int cryptlen = req->cryptlen; 395*2698bce1SArd Biesheuvel struct skcipher_walk walk; 396cf3d41adSArd Biesheuvel struct aegis_state state; 397cf3d41adSArd Biesheuvel 398cf3d41adSArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 399cf3d41adSArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 400cf3d41adSArd Biesheuvel 401*2698bce1SArd Biesheuvel skcipher_walk_aead_encrypt(&walk, req, false); 402cf3d41adSArd Biesheuvel if (aegis128_do_simd()) 403*2698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 404*2698bce1SArd Biesheuvel crypto_aegis128_encrypt_chunk_simd); 405*2698bce1SArd Biesheuvel else 406*2698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 407*2698bce1SArd Biesheuvel crypto_aegis128_encrypt_chunk); 408*2698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 409cf3d41adSArd Biesheuvel 410cf3d41adSArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, 411cf3d41adSArd Biesheuvel authsize, 1); 412cf3d41adSArd Biesheuvel return 0; 413cf3d41adSArd Biesheuvel } 414cf3d41adSArd Biesheuvel 415cf3d41adSArd Biesheuvel static int crypto_aegis128_decrypt(struct aead_request *req) 416cf3d41adSArd Biesheuvel { 417cf3d41adSArd Biesheuvel static const u8 zeros[AEGIS128_MAX_AUTH_SIZE] = {}; 418cf3d41adSArd Biesheuvel struct crypto_aead *tfm = crypto_aead_reqtfm(req); 419cf3d41adSArd Biesheuvel union aegis_block tag; 420cf3d41adSArd Biesheuvel unsigned int authsize = crypto_aead_authsize(tfm); 421cf3d41adSArd Biesheuvel unsigned int cryptlen = req->cryptlen - authsize; 422*2698bce1SArd Biesheuvel struct aegis_ctx *ctx = crypto_aead_ctx(tfm); 423*2698bce1SArd Biesheuvel struct skcipher_walk walk; 424*2698bce1SArd Biesheuvel struct aegis_state state; 425cf3d41adSArd Biesheuvel 426cf3d41adSArd Biesheuvel scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, 427cf3d41adSArd Biesheuvel authsize, 0); 428cf3d41adSArd Biesheuvel 429*2698bce1SArd Biesheuvel crypto_aegis128_init(&state, &ctx->key, req->iv); 430*2698bce1SArd Biesheuvel crypto_aegis128_process_ad(&state, req->src, req->assoclen); 431cf3d41adSArd Biesheuvel 432*2698bce1SArd Biesheuvel skcipher_walk_aead_decrypt(&walk, req, false); 433*2698bce1SArd Biesheuvel if (aegis128_do_simd()) 434*2698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 435*2698bce1SArd Biesheuvel crypto_aegis128_decrypt_chunk_simd); 436*2698bce1SArd Biesheuvel else 437*2698bce1SArd Biesheuvel crypto_aegis128_process_crypt(&state, req, &walk, 438*2698bce1SArd Biesheuvel crypto_aegis128_decrypt_chunk); 439*2698bce1SArd Biesheuvel crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen); 440cf3d41adSArd Biesheuvel 441cf3d41adSArd Biesheuvel return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; 442cf3d41adSArd Biesheuvel } 443cf3d41adSArd Biesheuvel 444cf3d41adSArd Biesheuvel static struct aead_alg crypto_aegis128_alg = { 445cf3d41adSArd Biesheuvel .setkey = crypto_aegis128_setkey, 446cf3d41adSArd Biesheuvel .setauthsize = crypto_aegis128_setauthsize, 447cf3d41adSArd Biesheuvel .encrypt = crypto_aegis128_encrypt, 448cf3d41adSArd Biesheuvel .decrypt = crypto_aegis128_decrypt, 449cf3d41adSArd Biesheuvel 450cf3d41adSArd Biesheuvel .ivsize = AEGIS128_NONCE_SIZE, 451cf3d41adSArd Biesheuvel .maxauthsize = AEGIS128_MAX_AUTH_SIZE, 452cf3d41adSArd Biesheuvel .chunksize = AEGIS_BLOCK_SIZE, 453cf3d41adSArd Biesheuvel 454cf3d41adSArd Biesheuvel .base = { 455cf3d41adSArd Biesheuvel .cra_blocksize = 1, 456cf3d41adSArd Biesheuvel .cra_ctxsize = sizeof(struct aegis_ctx), 457cf3d41adSArd Biesheuvel .cra_alignmask = 0, 458cf3d41adSArd Biesheuvel 459cf3d41adSArd Biesheuvel .cra_priority = 100, 460cf3d41adSArd Biesheuvel 461cf3d41adSArd Biesheuvel .cra_name = "aegis128", 462cf3d41adSArd Biesheuvel .cra_driver_name = "aegis128-generic", 463cf3d41adSArd Biesheuvel 464cf3d41adSArd Biesheuvel .cra_module = THIS_MODULE, 465cf3d41adSArd Biesheuvel } 466cf3d41adSArd Biesheuvel }; 467cf3d41adSArd Biesheuvel 468cf3d41adSArd Biesheuvel static int __init crypto_aegis128_module_init(void) 469cf3d41adSArd Biesheuvel { 470*2698bce1SArd Biesheuvel if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && 471*2698bce1SArd Biesheuvel crypto_aegis128_have_simd()) 472*2698bce1SArd Biesheuvel static_branch_enable(&have_simd); 473cf3d41adSArd Biesheuvel 474cf3d41adSArd Biesheuvel return crypto_register_aead(&crypto_aegis128_alg); 475cf3d41adSArd Biesheuvel } 476cf3d41adSArd Biesheuvel 477cf3d41adSArd Biesheuvel static void __exit crypto_aegis128_module_exit(void) 478cf3d41adSArd Biesheuvel { 479cf3d41adSArd Biesheuvel crypto_unregister_aead(&crypto_aegis128_alg); 480cf3d41adSArd Biesheuvel } 481cf3d41adSArd Biesheuvel 482cf3d41adSArd Biesheuvel subsys_initcall(crypto_aegis128_module_init); 483cf3d41adSArd Biesheuvel module_exit(crypto_aegis128_module_exit); 484cf3d41adSArd Biesheuvel 485cf3d41adSArd Biesheuvel MODULE_LICENSE("GPL"); 486cf3d41adSArd Biesheuvel MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>"); 487cf3d41adSArd Biesheuvel MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm"); 488cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128"); 489cf3d41adSArd Biesheuvel MODULE_ALIAS_CRYPTO("aegis128-generic"); 490