linux/arch/arm64/crypto/sha1-ce-glue.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * sha1-ce-glue.c - SHA-1 secure hash using ARMv8 Crypto Extensions
   4 *
   5 * Copyright (C) 2014 - 2017 Linaro Ltd <ard.biesheuvel@linaro.org>
   6 */
   7
   8#include <asm/neon.h>
   9#include <asm/simd.h>
  10#include <asm/unaligned.h>
  11#include <crypto/internal/hash.h>
  12#include <crypto/internal/simd.h>
  13#include <crypto/sha1.h>
  14#include <crypto/sha1_base.h>
  15#include <linux/cpufeature.h>
  16#include <linux/crypto.h>
  17#include <linux/module.h>
  18
  19MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions");
  20MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
  21MODULE_LICENSE("GPL v2");
  22MODULE_ALIAS_CRYPTO("sha1");
  23
  24struct sha1_ce_state {
  25        struct sha1_state       sst;
  26        u32                     finalize;
  27};
  28
  29extern const u32 sha1_ce_offsetof_count;
  30extern const u32 sha1_ce_offsetof_finalize;
  31
  32asmlinkage int sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src,
  33                                 int blocks);
  34
  35static void __sha1_ce_transform(struct sha1_state *sst, u8 const *src,
  36                                int blocks)
  37{
  38        while (blocks) {
  39                int rem;
  40
  41                kernel_neon_begin();
  42                rem = sha1_ce_transform(container_of(sst, struct sha1_ce_state,
  43                                                     sst), src, blocks);
  44                kernel_neon_end();
  45                src += (blocks - rem) * SHA1_BLOCK_SIZE;
  46                blocks = rem;
  47        }
  48}
  49
  50const u32 sha1_ce_offsetof_count = offsetof(struct sha1_ce_state, sst.count);
  51const u32 sha1_ce_offsetof_finalize = offsetof(struct sha1_ce_state, finalize);
  52
  53static int sha1_ce_update(struct shash_desc *desc, const u8 *data,
  54                          unsigned int len)
  55{
  56        struct sha1_ce_state *sctx = shash_desc_ctx(desc);
  57
  58        if (!crypto_simd_usable())
  59                return crypto_sha1_update(desc, data, len);
  60
  61        sctx->finalize = 0;
  62        sha1_base_do_update(desc, data, len, __sha1_ce_transform);
  63
  64        return 0;
  65}
  66
  67static int sha1_ce_finup(struct shash_desc *desc, const u8 *data,
  68                         unsigned int len, u8 *out)
  69{
  70        struct sha1_ce_state *sctx = shash_desc_ctx(desc);
  71        bool finalize = !sctx->sst.count && !(len % SHA1_BLOCK_SIZE) && len;
  72
  73        if (!crypto_simd_usable())
  74                return crypto_sha1_finup(desc, data, len, out);
  75
  76        /*
  77         * Allow the asm code to perform the finalization if there is no
  78         * partial data and the input is a round multiple of the block size.
  79         */
  80        sctx->finalize = finalize;
  81
  82        sha1_base_do_update(desc, data, len, __sha1_ce_transform);
  83        if (!finalize)
  84                sha1_base_do_finalize(desc, __sha1_ce_transform);
  85        return sha1_base_finish(desc, out);
  86}
  87
  88static int sha1_ce_final(struct shash_desc *desc, u8 *out)
  89{
  90        struct sha1_ce_state *sctx = shash_desc_ctx(desc);
  91
  92        if (!crypto_simd_usable())
  93                return crypto_sha1_finup(desc, NULL, 0, out);
  94
  95        sctx->finalize = 0;
  96        sha1_base_do_finalize(desc, __sha1_ce_transform);
  97        return sha1_base_finish(desc, out);
  98}
  99
 100static int sha1_ce_export(struct shash_desc *desc, void *out)
 101{
 102        struct sha1_ce_state *sctx = shash_desc_ctx(desc);
 103
 104        memcpy(out, &sctx->sst, sizeof(struct sha1_state));
 105        return 0;
 106}
 107
 108static int sha1_ce_import(struct shash_desc *desc, const void *in)
 109{
 110        struct sha1_ce_state *sctx = shash_desc_ctx(desc);
 111
 112        memcpy(&sctx->sst, in, sizeof(struct sha1_state));
 113        sctx->finalize = 0;
 114        return 0;
 115}
 116
 117static struct shash_alg alg = {
 118        .init                   = sha1_base_init,
 119        .update                 = sha1_ce_update,
 120        .final                  = sha1_ce_final,
 121        .finup                  = sha1_ce_finup,
 122        .import                 = sha1_ce_import,
 123        .export                 = sha1_ce_export,
 124        .descsize               = sizeof(struct sha1_ce_state),
 125        .statesize              = sizeof(struct sha1_state),
 126        .digestsize             = SHA1_DIGEST_SIZE,
 127        .base                   = {
 128                .cra_name               = "sha1",
 129                .cra_driver_name        = "sha1-ce",
 130                .cra_priority           = 200,
 131                .cra_blocksize          = SHA1_BLOCK_SIZE,
 132                .cra_module             = THIS_MODULE,
 133        }
 134};
 135
 136static int __init sha1_ce_mod_init(void)
 137{
 138        return crypto_register_shash(&alg);
 139}
 140
 141static void __exit sha1_ce_mod_fini(void)
 142{
 143        crypto_unregister_shash(&alg);
 144}
 145
 146module_cpu_feature_match(SHA1, sha1_ce_mod_init);
 147module_exit(sha1_ce_mod_fini);
 148