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