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