linux/arch/sparc/crypto/sha256_glue.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Glue code for SHA256 hashing optimized for sparc64 crypto opcodes.
   3 *
   4 * This is based largely upon crypto/sha256_generic.c
   5 *
   6 * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
   7 * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
   8 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
   9 * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.com>
  10 */
  11
  12#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
  13
  14#include <crypto/internal/hash.h>
  15#include <linux/init.h>
  16#include <linux/module.h>
  17#include <linux/mm.h>
  18#include <linux/cryptohash.h>
  19#include <linux/types.h>
  20#include <crypto/sha.h>
  21
  22#include <asm/pstate.h>
  23#include <asm/elf.h>
  24
  25#include "opcodes.h"
  26
  27asmlinkage void sha256_sparc64_transform(u32 *digest, const char *data,
  28                                         unsigned int rounds);
  29
  30static int sha224_sparc64_init(struct shash_desc *desc)
  31{
  32        struct sha256_state *sctx = shash_desc_ctx(desc);
  33        sctx->state[0] = SHA224_H0;
  34        sctx->state[1] = SHA224_H1;
  35        sctx->state[2] = SHA224_H2;
  36        sctx->state[3] = SHA224_H3;
  37        sctx->state[4] = SHA224_H4;
  38        sctx->state[5] = SHA224_H5;
  39        sctx->state[6] = SHA224_H6;
  40        sctx->state[7] = SHA224_H7;
  41        sctx->count = 0;
  42
  43        return 0;
  44}
  45
  46static int sha256_sparc64_init(struct shash_desc *desc)
  47{
  48        struct sha256_state *sctx = shash_desc_ctx(desc);
  49        sctx->state[0] = SHA256_H0;
  50        sctx->state[1] = SHA256_H1;
  51        sctx->state[2] = SHA256_H2;
  52        sctx->state[3] = SHA256_H3;
  53        sctx->state[4] = SHA256_H4;
  54        sctx->state[5] = SHA256_H5;
  55        sctx->state[6] = SHA256_H6;
  56        sctx->state[7] = SHA256_H7;
  57        sctx->count = 0;
  58
  59        return 0;
  60}
  61
  62static void __sha256_sparc64_update(struct sha256_state *sctx, const u8 *data,
  63                                    unsigned int len, unsigned int partial)
  64{
  65        unsigned int done = 0;
  66
  67        sctx->count += len;
  68        if (partial) {
  69                done = SHA256_BLOCK_SIZE - partial;
  70                memcpy(sctx->buf + partial, data, done);
  71                sha256_sparc64_transform(sctx->state, sctx->buf, 1);
  72        }
  73        if (len - done >= SHA256_BLOCK_SIZE) {
  74                const unsigned int rounds = (len - done) / SHA256_BLOCK_SIZE;
  75
  76                sha256_sparc64_transform(sctx->state, data + done, rounds);
  77                done += rounds * SHA256_BLOCK_SIZE;
  78        }
  79
  80        memcpy(sctx->buf, data + done, len - done);
  81}
  82
  83static int sha256_sparc64_update(struct shash_desc *desc, const u8 *data,
  84                                 unsigned int len)
  85{
  86        struct sha256_state *sctx = shash_desc_ctx(desc);
  87        unsigned int partial = sctx->count % SHA256_BLOCK_SIZE;
  88
  89        /* Handle the fast case right here */
  90        if (partial + len < SHA256_BLOCK_SIZE) {
  91                sctx->count += len;
  92                memcpy(sctx->buf + partial, data, len);
  93        } else
  94                __sha256_sparc64_update(sctx, data, len, partial);
  95
  96        return 0;
  97}
  98
  99static int sha256_sparc64_final(struct shash_desc *desc, u8 *out)
 100{
 101        struct sha256_state *sctx = shash_desc_ctx(desc);
 102        unsigned int i, index, padlen;
 103        __be32 *dst = (__be32 *)out;
 104        __be64 bits;
 105        static const u8 padding[SHA256_BLOCK_SIZE] = { 0x80, };
 106
 107        bits = cpu_to_be64(sctx->count << 3);
 108
 109        /* Pad out to 56 mod 64 and append length */
 110        index = sctx->count % SHA256_BLOCK_SIZE;
 111        padlen = (index < 56) ? (56 - index) : ((SHA256_BLOCK_SIZE+56) - index);
 112
 113        /* We need to fill a whole block for __sha256_sparc64_update() */
 114        if (padlen <= 56) {
 115                sctx->count += padlen;
 116                memcpy(sctx->buf + index, padding, padlen);
 117        } else {
 118                __sha256_sparc64_update(sctx, padding, padlen, index);
 119        }
 120        __sha256_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 56);
 121
 122        /* Store state in digest */
 123        for (i = 0; i < 8; i++)
 124                dst[i] = cpu_to_be32(sctx->state[i]);
 125
 126        /* Wipe context */
 127        memset(sctx, 0, sizeof(*sctx));
 128
 129        return 0;
 130}
 131
 132static int sha224_sparc64_final(struct shash_desc *desc, u8 *hash)
 133{
 134        u8 D[SHA256_DIGEST_SIZE];
 135
 136        sha256_sparc64_final(desc, D);
 137
 138        memcpy(hash, D, SHA224_DIGEST_SIZE);
 139        memzero_explicit(D, SHA256_DIGEST_SIZE);
 140
 141        return 0;
 142}
 143
 144static int sha256_sparc64_export(struct shash_desc *desc, void *out)
 145{
 146        struct sha256_state *sctx = shash_desc_ctx(desc);
 147
 148        memcpy(out, sctx, sizeof(*sctx));
 149        return 0;
 150}
 151
 152static int sha256_sparc64_import(struct shash_desc *desc, const void *in)
 153{
 154        struct sha256_state *sctx = shash_desc_ctx(desc);
 155
 156        memcpy(sctx, in, sizeof(*sctx));
 157        return 0;
 158}
 159
 160static struct shash_alg sha256 = {
 161        .digestsize     =       SHA256_DIGEST_SIZE,
 162        .init           =       sha256_sparc64_init,
 163        .update         =       sha256_sparc64_update,
 164        .final          =       sha256_sparc64_final,
 165        .export         =       sha256_sparc64_export,
 166        .import         =       sha256_sparc64_import,
 167        .descsize       =       sizeof(struct sha256_state),
 168        .statesize      =       sizeof(struct sha256_state),
 169        .base           =       {
 170                .cra_name       =       "sha256",
 171                .cra_driver_name=       "sha256-sparc64",
 172                .cra_priority   =       SPARC_CR_OPCODE_PRIORITY,
 173                .cra_blocksize  =       SHA256_BLOCK_SIZE,
 174                .cra_module     =       THIS_MODULE,
 175        }
 176};
 177
 178static struct shash_alg sha224 = {
 179        .digestsize     =       SHA224_DIGEST_SIZE,
 180        .init           =       sha224_sparc64_init,
 181        .update         =       sha256_sparc64_update,
 182        .final          =       sha224_sparc64_final,
 183        .descsize       =       sizeof(struct sha256_state),
 184        .base           =       {
 185                .cra_name       =       "sha224",
 186                .cra_driver_name=       "sha224-sparc64",
 187                .cra_priority   =       SPARC_CR_OPCODE_PRIORITY,
 188                .cra_blocksize  =       SHA224_BLOCK_SIZE,
 189                .cra_module     =       THIS_MODULE,
 190        }
 191};
 192
 193static bool __init sparc64_has_sha256_opcode(void)
 194{
 195        unsigned long cfr;
 196
 197        if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
 198                return false;
 199
 200        __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
 201        if (!(cfr & CFR_SHA256))
 202                return false;
 203
 204        return true;
 205}
 206
 207static int __init sha256_sparc64_mod_init(void)
 208{
 209        if (sparc64_has_sha256_opcode()) {
 210                int ret = crypto_register_shash(&sha224);
 211                if (ret < 0)
 212                        return ret;
 213
 214                ret = crypto_register_shash(&sha256);
 215                if (ret < 0) {
 216                        crypto_unregister_shash(&sha224);
 217                        return ret;
 218                }
 219
 220                pr_info("Using sparc64 sha256 opcode optimized SHA-256/SHA-224 implementation\n");
 221                return 0;
 222        }
 223        pr_info("sparc64 sha256 opcode not available.\n");
 224        return -ENODEV;
 225}
 226
 227static void __exit sha256_sparc64_mod_fini(void)
 228{
 229        crypto_unregister_shash(&sha224);
 230        crypto_unregister_shash(&sha256);
 231}
 232
 233module_init(sha256_sparc64_mod_init);
 234module_exit(sha256_sparc64_mod_fini);
 235
 236MODULE_LICENSE("GPL");
 237MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm, sparc64 sha256 opcode accelerated");
 238
 239MODULE_ALIAS_CRYPTO("sha224");
 240MODULE_ALIAS_CRYPTO("sha256");
 241
 242#include "crop_devid.c"
 243