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