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