0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <crypto/algapi.h>
0015 #include <crypto/internal/hash.h>
0016 #include <crypto/internal/poly1305.h>
0017 #include <linux/crypto.h>
0018 #include <linux/kernel.h>
0019 #include <linux/module.h>
0020 #include <asm/unaligned.h>
0021
0022 static int crypto_poly1305_init(struct shash_desc *desc)
0023 {
0024 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
0025
0026 poly1305_core_init(&dctx->h);
0027 dctx->buflen = 0;
0028 dctx->rset = 0;
0029 dctx->sset = false;
0030
0031 return 0;
0032 }
0033
0034 static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
0035 const u8 *src, unsigned int srclen)
0036 {
0037 if (!dctx->sset) {
0038 if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
0039 poly1305_core_setkey(&dctx->core_r, src);
0040 src += POLY1305_BLOCK_SIZE;
0041 srclen -= POLY1305_BLOCK_SIZE;
0042 dctx->rset = 2;
0043 }
0044 if (srclen >= POLY1305_BLOCK_SIZE) {
0045 dctx->s[0] = get_unaligned_le32(src + 0);
0046 dctx->s[1] = get_unaligned_le32(src + 4);
0047 dctx->s[2] = get_unaligned_le32(src + 8);
0048 dctx->s[3] = get_unaligned_le32(src + 12);
0049 src += POLY1305_BLOCK_SIZE;
0050 srclen -= POLY1305_BLOCK_SIZE;
0051 dctx->sset = true;
0052 }
0053 }
0054 return srclen;
0055 }
0056
0057 static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
0058 unsigned int srclen)
0059 {
0060 unsigned int datalen;
0061
0062 if (unlikely(!dctx->sset)) {
0063 datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
0064 src += srclen - datalen;
0065 srclen = datalen;
0066 }
0067
0068 poly1305_core_blocks(&dctx->h, &dctx->core_r, src,
0069 srclen / POLY1305_BLOCK_SIZE, 1);
0070 }
0071
0072 static int crypto_poly1305_update(struct shash_desc *desc,
0073 const u8 *src, unsigned int srclen)
0074 {
0075 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
0076 unsigned int bytes;
0077
0078 if (unlikely(dctx->buflen)) {
0079 bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen);
0080 memcpy(dctx->buf + dctx->buflen, src, bytes);
0081 src += bytes;
0082 srclen -= bytes;
0083 dctx->buflen += bytes;
0084
0085 if (dctx->buflen == POLY1305_BLOCK_SIZE) {
0086 poly1305_blocks(dctx, dctx->buf,
0087 POLY1305_BLOCK_SIZE);
0088 dctx->buflen = 0;
0089 }
0090 }
0091
0092 if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
0093 poly1305_blocks(dctx, src, srclen);
0094 src += srclen - (srclen % POLY1305_BLOCK_SIZE);
0095 srclen %= POLY1305_BLOCK_SIZE;
0096 }
0097
0098 if (unlikely(srclen)) {
0099 dctx->buflen = srclen;
0100 memcpy(dctx->buf, src, srclen);
0101 }
0102
0103 return 0;
0104 }
0105
0106 static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
0107 {
0108 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
0109
0110 if (unlikely(!dctx->sset))
0111 return -ENOKEY;
0112
0113 poly1305_final_generic(dctx, dst);
0114 return 0;
0115 }
0116
0117 static struct shash_alg poly1305_alg = {
0118 .digestsize = POLY1305_DIGEST_SIZE,
0119 .init = crypto_poly1305_init,
0120 .update = crypto_poly1305_update,
0121 .final = crypto_poly1305_final,
0122 .descsize = sizeof(struct poly1305_desc_ctx),
0123 .base = {
0124 .cra_name = "poly1305",
0125 .cra_driver_name = "poly1305-generic",
0126 .cra_priority = 100,
0127 .cra_blocksize = POLY1305_BLOCK_SIZE,
0128 .cra_module = THIS_MODULE,
0129 },
0130 };
0131
0132 static int __init poly1305_mod_init(void)
0133 {
0134 return crypto_register_shash(&poly1305_alg);
0135 }
0136
0137 static void __exit poly1305_mod_exit(void)
0138 {
0139 crypto_unregister_shash(&poly1305_alg);
0140 }
0141
0142 subsys_initcall(poly1305_mod_init);
0143 module_exit(poly1305_mod_exit);
0144
0145 MODULE_LICENSE("GPL");
0146 MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
0147 MODULE_DESCRIPTION("Poly1305 authenticator");
0148 MODULE_ALIAS_CRYPTO("poly1305");
0149 MODULE_ALIAS_CRYPTO("poly1305-generic");