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