1 /* 1 /* 2 * Poly1305 authenticator algorithm, RFC7539 2 * Poly1305 authenticator algorithm, RFC7539 3 * 3 * 4 * Copyright (C) 2015 Martin Willi 4 * Copyright (C) 2015 Martin Willi 5 * 5 * 6 * Based on public domain code by Andrew Moon 6 * Based on public domain code by Andrew Moon and Daniel J. Bernstein. 7 * 7 * 8 * This program is free software; you can redi 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Publi 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either versio 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 11 * (at your option) any later version. 12 */ 12 */ 13 13 14 #include <crypto/algapi.h> 14 #include <crypto/algapi.h> 15 #include <crypto/internal/hash.h> 15 #include <crypto/internal/hash.h> 16 #include <crypto/internal/poly1305.h> 16 #include <crypto/internal/poly1305.h> 17 #include <linux/crypto.h> 17 #include <linux/crypto.h> 18 #include <linux/kernel.h> 18 #include <linux/kernel.h> 19 #include <linux/module.h> 19 #include <linux/module.h> 20 #include <asm/unaligned.h> 20 #include <asm/unaligned.h> 21 21 22 static int crypto_poly1305_init(struct shash_d 22 static int crypto_poly1305_init(struct shash_desc *desc) 23 { 23 { 24 struct poly1305_desc_ctx *dctx = shash 24 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); 25 25 26 poly1305_core_init(&dctx->h); 26 poly1305_core_init(&dctx->h); 27 dctx->buflen = 0; 27 dctx->buflen = 0; 28 dctx->rset = 0; 28 dctx->rset = 0; 29 dctx->sset = false; 29 dctx->sset = false; 30 30 31 return 0; 31 return 0; 32 } 32 } 33 33 34 static unsigned int crypto_poly1305_setdesckey 34 static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, 35 35 const u8 *src, unsigned int srclen) 36 { 36 { 37 if (!dctx->sset) { 37 if (!dctx->sset) { 38 if (!dctx->rset && srclen >= P 38 if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { 39 poly1305_core_setkey(& 39 poly1305_core_setkey(&dctx->core_r, src); 40 src += POLY1305_BLOCK_ 40 src += POLY1305_BLOCK_SIZE; 41 srclen -= POLY1305_BLO 41 srclen -= POLY1305_BLOCK_SIZE; 42 dctx->rset = 2; 42 dctx->rset = 2; 43 } 43 } 44 if (srclen >= POLY1305_BLOCK_S 44 if (srclen >= POLY1305_BLOCK_SIZE) { 45 dctx->s[0] = get_unali 45 dctx->s[0] = get_unaligned_le32(src + 0); 46 dctx->s[1] = get_unali 46 dctx->s[1] = get_unaligned_le32(src + 4); 47 dctx->s[2] = get_unali 47 dctx->s[2] = get_unaligned_le32(src + 8); 48 dctx->s[3] = get_unali 48 dctx->s[3] = get_unaligned_le32(src + 12); 49 src += POLY1305_BLOCK_ 49 src += POLY1305_BLOCK_SIZE; 50 srclen -= POLY1305_BLO 50 srclen -= POLY1305_BLOCK_SIZE; 51 dctx->sset = true; 51 dctx->sset = true; 52 } 52 } 53 } 53 } 54 return srclen; 54 return srclen; 55 } 55 } 56 56 57 static void poly1305_blocks(struct poly1305_de 57 static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, 58 unsigned int srcle 58 unsigned int srclen) 59 { 59 { 60 unsigned int datalen; 60 unsigned int datalen; 61 61 62 if (unlikely(!dctx->sset)) { 62 if (unlikely(!dctx->sset)) { 63 datalen = crypto_poly1305_setd 63 datalen = crypto_poly1305_setdesckey(dctx, src, srclen); 64 src += srclen - datalen; 64 src += srclen - datalen; 65 srclen = datalen; 65 srclen = datalen; 66 } 66 } 67 67 68 poly1305_core_blocks(&dctx->h, &dctx-> 68 poly1305_core_blocks(&dctx->h, &dctx->core_r, src, 69 srclen / POLY1305 69 srclen / POLY1305_BLOCK_SIZE, 1); 70 } 70 } 71 71 72 static int crypto_poly1305_update(struct shash 72 static int crypto_poly1305_update(struct shash_desc *desc, 73 const u8 *sr 73 const u8 *src, unsigned int srclen) 74 { 74 { 75 struct poly1305_desc_ctx *dctx = shash 75 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); 76 unsigned int bytes; 76 unsigned int bytes; 77 77 78 if (unlikely(dctx->buflen)) { 78 if (unlikely(dctx->buflen)) { 79 bytes = min(srclen, POLY1305_B 79 bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen); 80 memcpy(dctx->buf + dctx->bufle 80 memcpy(dctx->buf + dctx->buflen, src, bytes); 81 src += bytes; 81 src += bytes; 82 srclen -= bytes; 82 srclen -= bytes; 83 dctx->buflen += bytes; 83 dctx->buflen += bytes; 84 84 85 if (dctx->buflen == POLY1305_B 85 if (dctx->buflen == POLY1305_BLOCK_SIZE) { 86 poly1305_blocks(dctx, 86 poly1305_blocks(dctx, dctx->buf, 87 POLY13 87 POLY1305_BLOCK_SIZE); 88 dctx->buflen = 0; 88 dctx->buflen = 0; 89 } 89 } 90 } 90 } 91 91 92 if (likely(srclen >= POLY1305_BLOCK_SI 92 if (likely(srclen >= POLY1305_BLOCK_SIZE)) { 93 poly1305_blocks(dctx, src, src 93 poly1305_blocks(dctx, src, srclen); 94 src += srclen - (srclen % POLY 94 src += srclen - (srclen % POLY1305_BLOCK_SIZE); 95 srclen %= POLY1305_BLOCK_SIZE; 95 srclen %= POLY1305_BLOCK_SIZE; 96 } 96 } 97 97 98 if (unlikely(srclen)) { 98 if (unlikely(srclen)) { 99 dctx->buflen = srclen; 99 dctx->buflen = srclen; 100 memcpy(dctx->buf, src, srclen) 100 memcpy(dctx->buf, src, srclen); 101 } 101 } 102 102 103 return 0; 103 return 0; 104 } 104 } 105 105 106 static int crypto_poly1305_final(struct shash_ 106 static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) 107 { 107 { 108 struct poly1305_desc_ctx *dctx = shash 108 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); 109 109 110 if (unlikely(!dctx->sset)) 110 if (unlikely(!dctx->sset)) 111 return -ENOKEY; 111 return -ENOKEY; 112 112 113 poly1305_final_generic(dctx, dst); 113 poly1305_final_generic(dctx, dst); 114 return 0; 114 return 0; 115 } 115 } 116 116 117 static struct shash_alg poly1305_alg = { 117 static struct shash_alg poly1305_alg = { 118 .digestsize = POLY1305_DIGEST_SIZE 118 .digestsize = POLY1305_DIGEST_SIZE, 119 .init = crypto_poly1305_init 119 .init = crypto_poly1305_init, 120 .update = crypto_poly1305_upda 120 .update = crypto_poly1305_update, 121 .final = crypto_poly1305_fina 121 .final = crypto_poly1305_final, 122 .descsize = sizeof(struct poly13 122 .descsize = sizeof(struct poly1305_desc_ctx), 123 .base = { 123 .base = { 124 .cra_name = "pol 124 .cra_name = "poly1305", 125 .cra_driver_name = "pol 125 .cra_driver_name = "poly1305-generic", 126 .cra_priority = 100, 126 .cra_priority = 100, 127 .cra_blocksize = POLY 127 .cra_blocksize = POLY1305_BLOCK_SIZE, 128 .cra_module = THIS 128 .cra_module = THIS_MODULE, 129 }, 129 }, 130 }; 130 }; 131 131 132 static int __init poly1305_mod_init(void) 132 static int __init poly1305_mod_init(void) 133 { 133 { 134 return crypto_register_shash(&poly1305 134 return crypto_register_shash(&poly1305_alg); 135 } 135 } 136 136 137 static void __exit poly1305_mod_exit(void) 137 static void __exit poly1305_mod_exit(void) 138 { 138 { 139 crypto_unregister_shash(&poly1305_alg) 139 crypto_unregister_shash(&poly1305_alg); 140 } 140 } 141 141 142 subsys_initcall(poly1305_mod_init); 142 subsys_initcall(poly1305_mod_init); 143 module_exit(poly1305_mod_exit); 143 module_exit(poly1305_mod_exit); 144 144 145 MODULE_LICENSE("GPL"); 145 MODULE_LICENSE("GPL"); 146 MODULE_AUTHOR("Martin Willi <martin@strongswan 146 MODULE_AUTHOR("Martin Willi <martin@strongswan.org>"); 147 MODULE_DESCRIPTION("Poly1305 authenticator"); 147 MODULE_DESCRIPTION("Poly1305 authenticator"); 148 MODULE_ALIAS_CRYPTO("poly1305"); 148 MODULE_ALIAS_CRYPTO("poly1305"); 149 MODULE_ALIAS_CRYPTO("poly1305-generic"); 149 MODULE_ALIAS_CRYPTO("poly1305-generic"); 150 150
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.