linux/crypto/morus640.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * The MORUS-640 Authenticated-Encryption Algorithm
   4 *
   5 * Copyright (c) 2016-2018 Ondrej Mosnacek <omosnacek@gmail.com>
   6 * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
   7 */
   8
   9#include <asm/unaligned.h>
  10#include <crypto/algapi.h>
  11#include <crypto/internal/aead.h>
  12#include <crypto/internal/skcipher.h>
  13#include <crypto/morus_common.h>
  14#include <crypto/scatterwalk.h>
  15#include <linux/err.h>
  16#include <linux/init.h>
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/scatterlist.h>
  20
  21#define MORUS640_WORD_SIZE 4
  22#define MORUS640_BLOCK_SIZE (MORUS_BLOCK_WORDS * MORUS640_WORD_SIZE)
  23#define MORUS640_BLOCK_ALIGN (__alignof__(__le32))
  24#define MORUS640_ALIGNED(p) IS_ALIGNED((uintptr_t)p, MORUS640_BLOCK_ALIGN)
  25
  26struct morus640_block {
  27        u32 words[MORUS_BLOCK_WORDS];
  28};
  29
  30union morus640_block_in {
  31        __le32 words[MORUS_BLOCK_WORDS];
  32        u8 bytes[MORUS640_BLOCK_SIZE];
  33};
  34
  35struct morus640_state {
  36        struct morus640_block s[MORUS_STATE_BLOCKS];
  37};
  38
  39struct morus640_ctx {
  40        struct morus640_block key;
  41};
  42
  43struct morus640_ops {
  44        int (*skcipher_walk_init)(struct skcipher_walk *walk,
  45                                  struct aead_request *req, bool atomic);
  46
  47        void (*crypt_chunk)(struct morus640_state *state,
  48                            u8 *dst, const u8 *src, unsigned int size);
  49};
  50
  51static const struct morus640_block crypto_morus640_const[2] = {
  52        { .words = {
  53                U32_C(0x02010100),
  54                U32_C(0x0d080503),
  55                U32_C(0x59372215),
  56                U32_C(0x6279e990),
  57        } },
  58        { .words = {
  59                U32_C(0x55183ddb),
  60                U32_C(0xf12fc26d),
  61                U32_C(0x42311120),
  62                U32_C(0xdd28b573),
  63        } },
  64};
  65
  66static void crypto_morus640_round(struct morus640_block *b0,
  67                                  struct morus640_block *b1,
  68                                  struct morus640_block *b2,
  69                                  struct morus640_block *b3,
  70                                  struct morus640_block *b4,
  71                                  const struct morus640_block *m,
  72                                  unsigned int b, unsigned int w)
  73{
  74        unsigned int i;
  75        struct morus640_block tmp;
  76
  77        for (i = 0; i < MORUS_BLOCK_WORDS; i++) {
  78                b0->words[i] ^= b1->words[i] & b2->words[i];
  79                b0->words[i] ^= b3->words[i];
  80                b0->words[i] ^= m->words[i];
  81                b0->words[i] = rol32(b0->words[i], b);
  82        }
  83
  84        tmp = *b3;
  85        for (i = 0; i < MORUS_BLOCK_WORDS; i++)
  86                b3->words[(i + w) % MORUS_BLOCK_WORDS] = tmp.words[i];
  87}
  88
  89static void crypto_morus640_update(struct morus640_state *state,
  90                                   const struct morus640_block *m)
  91{
  92        static const struct morus640_block z = {};
  93
  94        struct morus640_block *s = state->s;
  95
  96        crypto_morus640_round(&s[0], &s[1], &s[2], &s[3], &s[4], &z,  5, 1);
  97        crypto_morus640_round(&s[1], &s[2], &s[3], &s[4], &s[0], m,  31, 2);
  98        crypto_morus640_round(&s[2], &s[3], &s[4], &s[0], &s[1], m,   7, 3);
  99        crypto_morus640_round(&s[3], &s[4], &s[0], &s[1], &s[2], m,  22, 2);
 100        crypto_morus640_round(&s[4], &s[0], &s[1], &s[2], &s[3], m,  13, 1);
 101}
 102
 103static void crypto_morus640_load_a(struct morus640_block *dst, const u8 *src)
 104{
 105        unsigned int i;
 106        for (i = 0; i < MORUS_BLOCK_WORDS; i++) {
 107                dst->words[i] = le32_to_cpu(*(const __le32 *)src);
 108                src += MORUS640_WORD_SIZE;
 109        }
 110}
 111
 112static void crypto_morus640_load_u(struct morus640_block *dst, const u8 *src)
 113{
 114        unsigned int i;
 115        for (i = 0; i < MORUS_BLOCK_WORDS; i++) {
 116                dst->words[i] = get_unaligned_le32(src);
 117                src += MORUS640_WORD_SIZE;
 118        }
 119}
 120
 121static void crypto_morus640_load(struct morus640_block *dst, const u8 *src)
 122{
 123        if (MORUS640_ALIGNED(src))
 124                crypto_morus640_load_a(dst, src);
 125        else
 126                crypto_morus640_load_u(dst, src);
 127}
 128
 129static void crypto_morus640_store_a(u8 *dst, const struct morus640_block *src)
 130{
 131        unsigned int i;
 132        for (i = 0; i < MORUS_BLOCK_WORDS; i++) {
 133                *(__le32 *)dst = cpu_to_le32(src->words[i]);
 134                dst += MORUS640_WORD_SIZE;
 135        }
 136}
 137
 138static void crypto_morus640_store_u(u8 *dst, const struct morus640_block *src)
 139{
 140        unsigned int i;
 141        for (i = 0; i < MORUS_BLOCK_WORDS; i++) {
 142                put_unaligned_le32(src->words[i], dst);
 143                dst += MORUS640_WORD_SIZE;
 144        }
 145}
 146
 147static void crypto_morus640_store(u8 *dst, const struct morus640_block *src)
 148{
 149        if (MORUS640_ALIGNED(dst))
 150                crypto_morus640_store_a(dst, src);
 151        else
 152                crypto_morus640_store_u(dst, src);
 153}
 154
 155static void crypto_morus640_ad(struct morus640_state *state, const u8 *src,
 156                               unsigned int size)
 157{
 158        struct morus640_block m;
 159
 160        if (MORUS640_ALIGNED(src)) {
 161                while (size >= MORUS640_BLOCK_SIZE) {
 162                        crypto_morus640_load_a(&m, src);
 163                        crypto_morus640_update(state, &m);
 164
 165                        size -= MORUS640_BLOCK_SIZE;
 166                        src += MORUS640_BLOCK_SIZE;
 167                }
 168        } else {
 169                while (size >= MORUS640_BLOCK_SIZE) {
 170                        crypto_morus640_load_u(&m, src);
 171                        crypto_morus640_update(state, &m);
 172
 173                        size -= MORUS640_BLOCK_SIZE;
 174                        src += MORUS640_BLOCK_SIZE;
 175                }
 176        }
 177}
 178
 179static void crypto_morus640_core(const struct morus640_state *state,
 180                                 struct morus640_block *blk)
 181{
 182        unsigned int i;
 183
 184        for (i = 0; i < MORUS_BLOCK_WORDS; i++)
 185                blk->words[(i + 3) % MORUS_BLOCK_WORDS] ^= state->s[1].words[i];
 186
 187        for (i = 0; i < MORUS_BLOCK_WORDS; i++) {
 188                blk->words[i] ^= state->s[0].words[i];
 189                blk->words[i] ^= state->s[2].words[i] & state->s[3].words[i];
 190        }
 191}
 192
 193static void crypto_morus640_encrypt_chunk(struct morus640_state *state, u8 *dst,
 194                                          const u8 *src, unsigned int size)
 195{
 196        struct morus640_block c, m;
 197
 198        if (MORUS640_ALIGNED(src) && MORUS640_ALIGNED(dst)) {
 199                while (size >= MORUS640_BLOCK_SIZE) {
 200                        crypto_morus640_load_a(&m, src);
 201                        c = m;
 202                        crypto_morus640_core(state, &c);
 203                        crypto_morus640_store_a(dst, &c);
 204                        crypto_morus640_update(state, &m);
 205
 206                        src += MORUS640_BLOCK_SIZE;
 207                        dst += MORUS640_BLOCK_SIZE;
 208                        size -= MORUS640_BLOCK_SIZE;
 209                }
 210        } else {
 211                while (size >= MORUS640_BLOCK_SIZE) {
 212                        crypto_morus640_load_u(&m, src);
 213                        c = m;
 214                        crypto_morus640_core(state, &c);
 215                        crypto_morus640_store_u(dst, &c);
 216                        crypto_morus640_update(state, &m);
 217
 218                        src += MORUS640_BLOCK_SIZE;
 219                        dst += MORUS640_BLOCK_SIZE;
 220                        size -= MORUS640_BLOCK_SIZE;
 221                }
 222        }
 223
 224        if (size > 0) {
 225                union morus640_block_in tail;
 226
 227                memcpy(tail.bytes, src, size);
 228                memset(tail.bytes + size, 0, MORUS640_BLOCK_SIZE - size);
 229
 230                crypto_morus640_load_a(&m, tail.bytes);
 231                c = m;
 232                crypto_morus640_core(state, &c);
 233                crypto_morus640_store_a(tail.bytes, &c);
 234                crypto_morus640_update(state, &m);
 235
 236                memcpy(dst, tail.bytes, size);
 237        }
 238}
 239
 240static void crypto_morus640_decrypt_chunk(struct morus640_state *state, u8 *dst,
 241                                          const u8 *src, unsigned int size)
 242{
 243        struct morus640_block m;
 244
 245        if (MORUS640_ALIGNED(src) && MORUS640_ALIGNED(dst)) {
 246                while (size >= MORUS640_BLOCK_SIZE) {
 247                        crypto_morus640_load_a(&m, src);
 248                        crypto_morus640_core(state, &m);
 249                        crypto_morus640_store_a(dst, &m);
 250                        crypto_morus640_update(state, &m);
 251
 252                        src += MORUS640_BLOCK_SIZE;
 253                        dst += MORUS640_BLOCK_SIZE;
 254                        size -= MORUS640_BLOCK_SIZE;
 255                }
 256        } else {
 257                while (size >= MORUS640_BLOCK_SIZE) {
 258                        crypto_morus640_load_u(&m, src);
 259                        crypto_morus640_core(state, &m);
 260                        crypto_morus640_store_u(dst, &m);
 261                        crypto_morus640_update(state, &m);
 262
 263                        src += MORUS640_BLOCK_SIZE;
 264                        dst += MORUS640_BLOCK_SIZE;
 265                        size -= MORUS640_BLOCK_SIZE;
 266                }
 267        }
 268
 269        if (size > 0) {
 270                union morus640_block_in tail;
 271
 272                memcpy(tail.bytes, src, size);
 273                memset(tail.bytes + size, 0, MORUS640_BLOCK_SIZE - size);
 274
 275                crypto_morus640_load_a(&m, tail.bytes);
 276                crypto_morus640_core(state, &m);
 277                crypto_morus640_store_a(tail.bytes, &m);
 278                memset(tail.bytes + size, 0, MORUS640_BLOCK_SIZE - size);
 279                crypto_morus640_load_a(&m, tail.bytes);
 280                crypto_morus640_update(state, &m);
 281
 282                memcpy(dst, tail.bytes, size);
 283        }
 284}
 285
 286static void crypto_morus640_init(struct morus640_state *state,
 287                                 const struct morus640_block *key,
 288                                 const u8 *iv)
 289{
 290        static const struct morus640_block z = {};
 291
 292        unsigned int i;
 293
 294        crypto_morus640_load(&state->s[0], iv);
 295        state->s[1] = *key;
 296        for (i = 0; i < MORUS_BLOCK_WORDS; i++)
 297                state->s[2].words[i] = U32_C(0xFFFFFFFF);
 298        state->s[3] = crypto_morus640_const[0];
 299        state->s[4] = crypto_morus640_const[1];
 300
 301        for (i = 0; i < 16; i++)
 302                crypto_morus640_update(state, &z);
 303
 304        for (i = 0; i < MORUS_BLOCK_WORDS; i++)
 305                state->s[1].words[i] ^= key->words[i];
 306}
 307
 308static void crypto_morus640_process_ad(struct morus640_state *state,
 309                                       struct scatterlist *sg_src,
 310                                       unsigned int assoclen)
 311{
 312        struct scatter_walk walk;
 313        struct morus640_block m;
 314        union morus640_block_in buf;
 315        unsigned int pos = 0;
 316
 317        scatterwalk_start(&walk, sg_src);
 318        while (assoclen != 0) {
 319                unsigned int size = scatterwalk_clamp(&walk, assoclen);
 320                unsigned int left = size;
 321                void *mapped = scatterwalk_map(&walk);
 322                const u8 *src = (const u8 *)mapped;
 323
 324                if (pos + size >= MORUS640_BLOCK_SIZE) {
 325                        if (pos > 0) {
 326                                unsigned int fill = MORUS640_BLOCK_SIZE - pos;
 327                                memcpy(buf.bytes + pos, src, fill);
 328
 329                                crypto_morus640_load_a(&m, buf.bytes);
 330                                crypto_morus640_update(state, &m);
 331
 332                                pos = 0;
 333                                left -= fill;
 334                                src += fill;
 335                        }
 336
 337                        crypto_morus640_ad(state, src, left);
 338                        src += left & ~(MORUS640_BLOCK_SIZE - 1);
 339                        left &= MORUS640_BLOCK_SIZE - 1;
 340                }
 341
 342                memcpy(buf.bytes + pos, src, left);
 343
 344                pos += left;
 345                assoclen -= size;
 346                scatterwalk_unmap(mapped);
 347                scatterwalk_advance(&walk, size);
 348                scatterwalk_done(&walk, 0, assoclen);
 349        }
 350
 351        if (pos > 0) {
 352                memset(buf.bytes + pos, 0, MORUS640_BLOCK_SIZE - pos);
 353
 354                crypto_morus640_load_a(&m, buf.bytes);
 355                crypto_morus640_update(state, &m);
 356        }
 357}
 358
 359static void crypto_morus640_process_crypt(struct morus640_state *state,
 360                                          struct aead_request *req,
 361                                          const struct morus640_ops *ops)
 362{
 363        struct skcipher_walk walk;
 364
 365        ops->skcipher_walk_init(&walk, req, false);
 366
 367        while (walk.nbytes) {
 368                unsigned int nbytes = walk.nbytes;
 369
 370                if (nbytes < walk.total)
 371                        nbytes = round_down(nbytes, walk.stride);
 372
 373                ops->crypt_chunk(state, walk.dst.virt.addr, walk.src.virt.addr,
 374                                 nbytes);
 375
 376                skcipher_walk_done(&walk, walk.nbytes - nbytes);
 377        }
 378}
 379
 380static void crypto_morus640_final(struct morus640_state *state,
 381                                  struct morus640_block *tag_xor,
 382                                  u64 assoclen, u64 cryptlen)
 383{
 384        struct morus640_block tmp;
 385        unsigned int i;
 386
 387        tmp.words[0] = lower_32_bits(assoclen * 8);
 388        tmp.words[1] = upper_32_bits(assoclen * 8);
 389        tmp.words[2] = lower_32_bits(cryptlen * 8);
 390        tmp.words[3] = upper_32_bits(cryptlen * 8);
 391
 392        for (i = 0; i < MORUS_BLOCK_WORDS; i++)
 393                state->s[4].words[i] ^= state->s[0].words[i];
 394
 395        for (i = 0; i < 10; i++)
 396                crypto_morus640_update(state, &tmp);
 397
 398        crypto_morus640_core(state, tag_xor);
 399}
 400
 401static int crypto_morus640_setkey(struct crypto_aead *aead, const u8 *key,
 402                                  unsigned int keylen)
 403{
 404        struct morus640_ctx *ctx = crypto_aead_ctx(aead);
 405
 406        if (keylen != MORUS640_BLOCK_SIZE) {
 407                crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
 408                return -EINVAL;
 409        }
 410
 411        crypto_morus640_load(&ctx->key, key);
 412        return 0;
 413}
 414
 415static int crypto_morus640_setauthsize(struct crypto_aead *tfm,
 416                                       unsigned int authsize)
 417{
 418        return (authsize <= MORUS_MAX_AUTH_SIZE) ? 0 : -EINVAL;
 419}
 420
 421static void crypto_morus640_crypt(struct aead_request *req,
 422                                  struct morus640_block *tag_xor,
 423                                  unsigned int cryptlen,
 424                                  const struct morus640_ops *ops)
 425{
 426        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 427        struct morus640_ctx *ctx = crypto_aead_ctx(tfm);
 428        struct morus640_state state;
 429
 430        crypto_morus640_init(&state, &ctx->key, req->iv);
 431        crypto_morus640_process_ad(&state, req->src, req->assoclen);
 432        crypto_morus640_process_crypt(&state, req, ops);
 433        crypto_morus640_final(&state, tag_xor, req->assoclen, cryptlen);
 434}
 435
 436static int crypto_morus640_encrypt(struct aead_request *req)
 437{
 438        static const struct morus640_ops ops = {
 439                .skcipher_walk_init = skcipher_walk_aead_encrypt,
 440                .crypt_chunk = crypto_morus640_encrypt_chunk,
 441        };
 442
 443        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 444        struct morus640_block tag = {};
 445        union morus640_block_in tag_out;
 446        unsigned int authsize = crypto_aead_authsize(tfm);
 447        unsigned int cryptlen = req->cryptlen;
 448
 449        crypto_morus640_crypt(req, &tag, cryptlen, &ops);
 450        crypto_morus640_store(tag_out.bytes, &tag);
 451
 452        scatterwalk_map_and_copy(tag_out.bytes, req->dst,
 453                                 req->assoclen + cryptlen, authsize, 1);
 454        return 0;
 455}
 456
 457static int crypto_morus640_decrypt(struct aead_request *req)
 458{
 459        static const struct morus640_ops ops = {
 460                .skcipher_walk_init = skcipher_walk_aead_decrypt,
 461                .crypt_chunk = crypto_morus640_decrypt_chunk,
 462        };
 463        static const u8 zeros[MORUS640_BLOCK_SIZE] = {};
 464
 465        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 466        union morus640_block_in tag_in;
 467        struct morus640_block tag;
 468        unsigned int authsize = crypto_aead_authsize(tfm);
 469        unsigned int cryptlen = req->cryptlen - authsize;
 470
 471        scatterwalk_map_and_copy(tag_in.bytes, req->src,
 472                                 req->assoclen + cryptlen, authsize, 0);
 473
 474        crypto_morus640_load(&tag, tag_in.bytes);
 475        crypto_morus640_crypt(req, &tag, cryptlen, &ops);
 476        crypto_morus640_store(tag_in.bytes, &tag);
 477
 478        return crypto_memneq(tag_in.bytes, zeros, authsize) ? -EBADMSG : 0;
 479}
 480
 481static int crypto_morus640_init_tfm(struct crypto_aead *tfm)
 482{
 483        return 0;
 484}
 485
 486static void crypto_morus640_exit_tfm(struct crypto_aead *tfm)
 487{
 488}
 489
 490static struct aead_alg crypto_morus640_alg = {
 491        .setkey = crypto_morus640_setkey,
 492        .setauthsize = crypto_morus640_setauthsize,
 493        .encrypt = crypto_morus640_encrypt,
 494        .decrypt = crypto_morus640_decrypt,
 495        .init = crypto_morus640_init_tfm,
 496        .exit = crypto_morus640_exit_tfm,
 497
 498        .ivsize = MORUS_NONCE_SIZE,
 499        .maxauthsize = MORUS_MAX_AUTH_SIZE,
 500        .chunksize = MORUS640_BLOCK_SIZE,
 501
 502        .base = {
 503                .cra_blocksize = 1,
 504                .cra_ctxsize = sizeof(struct morus640_ctx),
 505                .cra_alignmask = 0,
 506
 507                .cra_priority = 100,
 508
 509                .cra_name = "morus640",
 510                .cra_driver_name = "morus640-generic",
 511
 512                .cra_module = THIS_MODULE,
 513        }
 514};
 515
 516static int __init crypto_morus640_module_init(void)
 517{
 518        return crypto_register_aead(&crypto_morus640_alg);
 519}
 520
 521static void __exit crypto_morus640_module_exit(void)
 522{
 523        crypto_unregister_aead(&crypto_morus640_alg);
 524}
 525
 526subsys_initcall(crypto_morus640_module_init);
 527module_exit(crypto_morus640_module_exit);
 528
 529MODULE_LICENSE("GPL");
 530MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
 531MODULE_DESCRIPTION("MORUS-640 AEAD algorithm");
 532MODULE_ALIAS_CRYPTO("morus640");
 533MODULE_ALIAS_CRYPTO("morus640-generic");
 534