18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Poly1305 authenticator algorithm, RFC7539 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Martin Willi 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on public domain code by Andrew Moon and Daniel J. Bernstein. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 98c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 108c2ecf20Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 118c2ecf20Sopenharmony_ci * (at your option) any later version. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 158c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 168c2ecf20Sopenharmony_ci#include <crypto/internal/poly1305.h> 178c2ecf20Sopenharmony_ci#include <linux/crypto.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int crypto_poly1305_init(struct shash_desc *desc) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci poly1305_core_init(&dctx->h); 278c2ecf20Sopenharmony_ci dctx->buflen = 0; 288c2ecf20Sopenharmony_ci dctx->rset = 0; 298c2ecf20Sopenharmony_ci dctx->sset = false; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci return 0; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, 358c2ecf20Sopenharmony_ci const u8 *src, unsigned int srclen) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci if (!dctx->sset) { 388c2ecf20Sopenharmony_ci if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { 398c2ecf20Sopenharmony_ci poly1305_core_setkey(&dctx->core_r, src); 408c2ecf20Sopenharmony_ci src += POLY1305_BLOCK_SIZE; 418c2ecf20Sopenharmony_ci srclen -= POLY1305_BLOCK_SIZE; 428c2ecf20Sopenharmony_ci dctx->rset = 2; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci if (srclen >= POLY1305_BLOCK_SIZE) { 458c2ecf20Sopenharmony_ci dctx->s[0] = get_unaligned_le32(src + 0); 468c2ecf20Sopenharmony_ci dctx->s[1] = get_unaligned_le32(src + 4); 478c2ecf20Sopenharmony_ci dctx->s[2] = get_unaligned_le32(src + 8); 488c2ecf20Sopenharmony_ci dctx->s[3] = get_unaligned_le32(src + 12); 498c2ecf20Sopenharmony_ci src += POLY1305_BLOCK_SIZE; 508c2ecf20Sopenharmony_ci srclen -= POLY1305_BLOCK_SIZE; 518c2ecf20Sopenharmony_ci dctx->sset = true; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci return srclen; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, 588c2ecf20Sopenharmony_ci unsigned int srclen) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci unsigned int datalen; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (unlikely(!dctx->sset)) { 638c2ecf20Sopenharmony_ci datalen = crypto_poly1305_setdesckey(dctx, src, srclen); 648c2ecf20Sopenharmony_ci src += srclen - datalen; 658c2ecf20Sopenharmony_ci srclen = datalen; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci poly1305_core_blocks(&dctx->h, &dctx->core_r, src, 698c2ecf20Sopenharmony_ci srclen / POLY1305_BLOCK_SIZE, 1); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int crypto_poly1305_update(struct shash_desc *desc, 738c2ecf20Sopenharmony_ci const u8 *src, unsigned int srclen) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); 768c2ecf20Sopenharmony_ci unsigned int bytes; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (unlikely(dctx->buflen)) { 798c2ecf20Sopenharmony_ci bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen); 808c2ecf20Sopenharmony_ci memcpy(dctx->buf + dctx->buflen, src, bytes); 818c2ecf20Sopenharmony_ci src += bytes; 828c2ecf20Sopenharmony_ci srclen -= bytes; 838c2ecf20Sopenharmony_ci dctx->buflen += bytes; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (dctx->buflen == POLY1305_BLOCK_SIZE) { 868c2ecf20Sopenharmony_ci poly1305_blocks(dctx, dctx->buf, 878c2ecf20Sopenharmony_ci POLY1305_BLOCK_SIZE); 888c2ecf20Sopenharmony_ci dctx->buflen = 0; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (likely(srclen >= POLY1305_BLOCK_SIZE)) { 938c2ecf20Sopenharmony_ci poly1305_blocks(dctx, src, srclen); 948c2ecf20Sopenharmony_ci src += srclen - (srclen % POLY1305_BLOCK_SIZE); 958c2ecf20Sopenharmony_ci srclen %= POLY1305_BLOCK_SIZE; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (unlikely(srclen)) { 998c2ecf20Sopenharmony_ci dctx->buflen = srclen; 1008c2ecf20Sopenharmony_ci memcpy(dctx->buf, src, srclen); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (unlikely(!dctx->sset)) 1118c2ecf20Sopenharmony_ci return -ENOKEY; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci poly1305_final_generic(dctx, dst); 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic struct shash_alg poly1305_alg = { 1188c2ecf20Sopenharmony_ci .digestsize = POLY1305_DIGEST_SIZE, 1198c2ecf20Sopenharmony_ci .init = crypto_poly1305_init, 1208c2ecf20Sopenharmony_ci .update = crypto_poly1305_update, 1218c2ecf20Sopenharmony_ci .final = crypto_poly1305_final, 1228c2ecf20Sopenharmony_ci .descsize = sizeof(struct poly1305_desc_ctx), 1238c2ecf20Sopenharmony_ci .base = { 1248c2ecf20Sopenharmony_ci .cra_name = "poly1305", 1258c2ecf20Sopenharmony_ci .cra_driver_name = "poly1305-generic", 1268c2ecf20Sopenharmony_ci .cra_priority = 100, 1278c2ecf20Sopenharmony_ci .cra_blocksize = POLY1305_BLOCK_SIZE, 1288c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 1298c2ecf20Sopenharmony_ci }, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int __init poly1305_mod_init(void) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci return crypto_register_shash(&poly1305_alg); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void __exit poly1305_mod_exit(void) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci crypto_unregister_shash(&poly1305_alg); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cisubsys_initcall(poly1305_mod_init); 1438c2ecf20Sopenharmony_cimodule_exit(poly1305_mod_exit); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Martin Willi <martin@strongswan.org>"); 1478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Poly1305 authenticator"); 1488c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("poly1305"); 1498c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("poly1305-generic"); 150