linux/arch/mips/crypto/poly1305-glue.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * OpenSSL/Cryptogams accelerated Poly1305 transform for MIPS
   4 *
   5 * Copyright (C) 2019 Linaro Ltd. <ard.biesheuvel@linaro.org>
   6 */
   7
   8#include <asm/unaligned.h>
   9#include <crypto/algapi.h>
  10#include <crypto/internal/hash.h>
  11#include <crypto/internal/poly1305.h>
  12#include <linux/cpufeature.h>
  13#include <linux/crypto.h>
  14#include <linux/module.h>
  15
  16asmlinkage void poly1305_init_mips(void *state, const u8 *key);
  17asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit);
  18asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce);
  19
  20void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
  21{
  22        poly1305_init_mips(&dctx->h, key);
  23        dctx->s[0] = get_unaligned_le32(key + 16);
  24        dctx->s[1] = get_unaligned_le32(key + 20);
  25        dctx->s[2] = get_unaligned_le32(key + 24);
  26        dctx->s[3] = get_unaligned_le32(key + 28);
  27        dctx->buflen = 0;
  28}
  29EXPORT_SYMBOL(poly1305_init_arch);
  30
  31static int mips_poly1305_init(struct shash_desc *desc)
  32{
  33        struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
  34
  35        dctx->buflen = 0;
  36        dctx->rset = 0;
  37        dctx->sset = false;
  38
  39        return 0;
  40}
  41
  42static void mips_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
  43                                 u32 len, u32 hibit)
  44{
  45        if (unlikely(!dctx->sset)) {
  46                if (!dctx->rset) {
  47                        poly1305_init_mips(&dctx->h, src);
  48                        src += POLY1305_BLOCK_SIZE;
  49                        len -= POLY1305_BLOCK_SIZE;
  50                        dctx->rset = 1;
  51                }
  52                if (len >= POLY1305_BLOCK_SIZE) {
  53                        dctx->s[0] = get_unaligned_le32(src +  0);
  54                        dctx->s[1] = get_unaligned_le32(src +  4);
  55                        dctx->s[2] = get_unaligned_le32(src +  8);
  56                        dctx->s[3] = get_unaligned_le32(src + 12);
  57                        src += POLY1305_BLOCK_SIZE;
  58                        len -= POLY1305_BLOCK_SIZE;
  59                        dctx->sset = true;
  60                }
  61                if (len < POLY1305_BLOCK_SIZE)
  62                        return;
  63        }
  64
  65        len &= ~(POLY1305_BLOCK_SIZE - 1);
  66
  67        poly1305_blocks_mips(&dctx->h, src, len, hibit);
  68}
  69
  70static int mips_poly1305_update(struct shash_desc *desc, const u8 *src,
  71                                unsigned int len)
  72{
  73        struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
  74
  75        if (unlikely(dctx->buflen)) {
  76                u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen);
  77
  78                memcpy(dctx->buf + dctx->buflen, src, bytes);
  79                src += bytes;
  80                len -= bytes;
  81                dctx->buflen += bytes;
  82
  83                if (dctx->buflen == POLY1305_BLOCK_SIZE) {
  84                        mips_poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 1);
  85                        dctx->buflen = 0;
  86                }
  87        }
  88
  89        if (likely(len >= POLY1305_BLOCK_SIZE)) {
  90                mips_poly1305_blocks(dctx, src, len, 1);
  91                src += round_down(len, POLY1305_BLOCK_SIZE);
  92                len %= POLY1305_BLOCK_SIZE;
  93        }
  94
  95        if (unlikely(len)) {
  96                dctx->buflen = len;
  97                memcpy(dctx->buf, src, len);
  98        }
  99        return 0;
 100}
 101
 102void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
 103                          unsigned int nbytes)
 104{
 105        if (unlikely(dctx->buflen)) {
 106                u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen);
 107
 108                memcpy(dctx->buf + dctx->buflen, src, bytes);
 109                src += bytes;
 110                nbytes -= bytes;
 111                dctx->buflen += bytes;
 112
 113                if (dctx->buflen == POLY1305_BLOCK_SIZE) {
 114                        poly1305_blocks_mips(&dctx->h, dctx->buf,
 115                                             POLY1305_BLOCK_SIZE, 1);
 116                        dctx->buflen = 0;
 117                }
 118        }
 119
 120        if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
 121                unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
 122
 123                poly1305_blocks_mips(&dctx->h, src, len, 1);
 124                src += len;
 125                nbytes %= POLY1305_BLOCK_SIZE;
 126        }
 127
 128        if (unlikely(nbytes)) {
 129                dctx->buflen = nbytes;
 130                memcpy(dctx->buf, src, nbytes);
 131        }
 132}
 133EXPORT_SYMBOL(poly1305_update_arch);
 134
 135void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
 136{
 137        if (unlikely(dctx->buflen)) {
 138                dctx->buf[dctx->buflen++] = 1;
 139                memset(dctx->buf + dctx->buflen, 0,
 140                       POLY1305_BLOCK_SIZE - dctx->buflen);
 141                poly1305_blocks_mips(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
 142        }
 143
 144        poly1305_emit_mips(&dctx->h, dst, dctx->s);
 145        *dctx = (struct poly1305_desc_ctx){};
 146}
 147EXPORT_SYMBOL(poly1305_final_arch);
 148
 149static int mips_poly1305_final(struct shash_desc *desc, u8 *dst)
 150{
 151        struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
 152
 153        if (unlikely(!dctx->sset))
 154                return -ENOKEY;
 155
 156        poly1305_final_arch(dctx, dst);
 157        return 0;
 158}
 159
 160static struct shash_alg mips_poly1305_alg = {
 161        .init                   = mips_poly1305_init,
 162        .update                 = mips_poly1305_update,
 163        .final                  = mips_poly1305_final,
 164        .digestsize             = POLY1305_DIGEST_SIZE,
 165        .descsize               = sizeof(struct poly1305_desc_ctx),
 166
 167        .base.cra_name          = "poly1305",
 168        .base.cra_driver_name   = "poly1305-mips",
 169        .base.cra_priority      = 200,
 170        .base.cra_blocksize     = POLY1305_BLOCK_SIZE,
 171        .base.cra_module        = THIS_MODULE,
 172};
 173
 174static int __init mips_poly1305_mod_init(void)
 175{
 176        return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
 177                crypto_register_shash(&mips_poly1305_alg) : 0;
 178}
 179
 180static void __exit mips_poly1305_mod_exit(void)
 181{
 182        if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
 183                crypto_unregister_shash(&mips_poly1305_alg);
 184}
 185
 186module_init(mips_poly1305_mod_init);
 187module_exit(mips_poly1305_mod_exit);
 188
 189MODULE_LICENSE("GPL v2");
 190MODULE_ALIAS_CRYPTO("poly1305");
 191MODULE_ALIAS_CRYPTO("poly1305-mips");
 192