Blame view

crypto/poly1305_generic.c 3.67 KB
f979e014c   Martin Willi   crypto: poly1305 ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Poly1305 authenticator algorithm, RFC7539
   *
   * Copyright (C) 2015 Martin Willi
   *
   * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   */
  
  #include <crypto/algapi.h>
  #include <crypto/internal/hash.h>
48ea8c6eb   Ard Biesheuvel   crypto: poly1305 ...
16
  #include <crypto/internal/poly1305.h>
f979e014c   Martin Willi   crypto: poly1305 ...
17
18
19
  #include <linux/crypto.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
109e23bd1   Jason A. Donenfeld   crypto: poly1305 ...
20
  #include <asm/unaligned.h>
f979e014c   Martin Willi   crypto: poly1305 ...
21

1b2c6a512   Ard Biesheuvel   crypto: x86/poly1...
22
  static int crypto_poly1305_init(struct shash_desc *desc)
f979e014c   Martin Willi   crypto: poly1305 ...
23
24
  {
  	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
1b6fd3d5d   Eric Biggers   crypto: poly1305 ...
25
  	poly1305_core_init(&dctx->h);
f979e014c   Martin Willi   crypto: poly1305 ...
26
  	dctx->buflen = 0;
ad8f5b883   Ard Biesheuvel   crypto: x86/poly1...
27
  	dctx->rset = 0;
c2b7b20ae   Martin Willi   crypto: poly1305 ...
28
  	dctx->sset = false;
f979e014c   Martin Willi   crypto: poly1305 ...
29
30
31
  
  	return 0;
  }
1c08a1043   Jason A. Donenfeld   crypto: poly1305 ...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
  					       const u8 *src, unsigned int srclen)
  {
  	if (!dctx->sset) {
  		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
  			poly1305_core_setkey(&dctx->core_r, src);
  			src += POLY1305_BLOCK_SIZE;
  			srclen -= POLY1305_BLOCK_SIZE;
  			dctx->rset = 2;
  		}
  		if (srclen >= POLY1305_BLOCK_SIZE) {
  			dctx->s[0] = get_unaligned_le32(src +  0);
  			dctx->s[1] = get_unaligned_le32(src +  4);
  			dctx->s[2] = get_unaligned_le32(src +  8);
  			dctx->s[3] = get_unaligned_le32(src + 12);
  			src += POLY1305_BLOCK_SIZE;
  			srclen -= POLY1305_BLOCK_SIZE;
  			dctx->sset = true;
  		}
  	}
  	return srclen;
  }
48ea8c6eb   Ard Biesheuvel   crypto: poly1305 ...
54
55
  static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
  			    unsigned int srclen)
1b6fd3d5d   Eric Biggers   crypto: poly1305 ...
56
57
58
59
60
61
62
63
  {
  	unsigned int datalen;
  
  	if (unlikely(!dctx->sset)) {
  		datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
  		src += srclen - datalen;
  		srclen = datalen;
  	}
1c08a1043   Jason A. Donenfeld   crypto: poly1305 ...
64
  	poly1305_core_blocks(&dctx->h, &dctx->core_r, src,
48ea8c6eb   Ard Biesheuvel   crypto: poly1305 ...
65
  			     srclen / POLY1305_BLOCK_SIZE, 1);
f979e014c   Martin Willi   crypto: poly1305 ...
66
  }
1b2c6a512   Ard Biesheuvel   crypto: x86/poly1...
67
68
  static int crypto_poly1305_update(struct shash_desc *desc,
  				  const u8 *src, unsigned int srclen)
f979e014c   Martin Willi   crypto: poly1305 ...
69
70
  {
  	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
f979e014c   Martin Willi   crypto: poly1305 ...
71
72
73
74
75
76
77
78
79
80
  	unsigned int bytes;
  
  	if (unlikely(dctx->buflen)) {
  		bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen);
  		memcpy(dctx->buf + dctx->buflen, src, bytes);
  		src += bytes;
  		srclen -= bytes;
  		dctx->buflen += bytes;
  
  		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
c2b7b20ae   Martin Willi   crypto: poly1305 ...
81
  			poly1305_blocks(dctx, dctx->buf,
48ea8c6eb   Ard Biesheuvel   crypto: poly1305 ...
82
  					POLY1305_BLOCK_SIZE);
f979e014c   Martin Willi   crypto: poly1305 ...
83
84
85
86
87
  			dctx->buflen = 0;
  		}
  	}
  
  	if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
48ea8c6eb   Ard Biesheuvel   crypto: poly1305 ...
88
  		poly1305_blocks(dctx, src, srclen);
1b6fd3d5d   Eric Biggers   crypto: poly1305 ...
89
90
  		src += srclen - (srclen % POLY1305_BLOCK_SIZE);
  		srclen %= POLY1305_BLOCK_SIZE;
f979e014c   Martin Willi   crypto: poly1305 ...
91
92
93
94
95
96
97
98
99
  	}
  
  	if (unlikely(srclen)) {
  		dctx->buflen = srclen;
  		memcpy(dctx->buf, src, srclen);
  	}
  
  	return 0;
  }
1b2c6a512   Ard Biesheuvel   crypto: x86/poly1...
100
  static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
1b6fd3d5d   Eric Biggers   crypto: poly1305 ...
101
102
  {
  	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
1b6fd3d5d   Eric Biggers   crypto: poly1305 ...
103
104
105
  
  	if (unlikely(!dctx->sset))
  		return -ENOKEY;
a1d930640   Ard Biesheuvel   crypto: poly1305 ...
106
  	poly1305_final_generic(dctx, dst);
f979e014c   Martin Willi   crypto: poly1305 ...
107
108
109
110
111
  	return 0;
  }
  
  static struct shash_alg poly1305_alg = {
  	.digestsize	= POLY1305_DIGEST_SIZE,
2546f811e   Martin Willi   crypto: poly1305 ...
112
113
114
  	.init		= crypto_poly1305_init,
  	.update		= crypto_poly1305_update,
  	.final		= crypto_poly1305_final,
f979e014c   Martin Willi   crypto: poly1305 ...
115
116
117
118
119
  	.descsize	= sizeof(struct poly1305_desc_ctx),
  	.base		= {
  		.cra_name		= "poly1305",
  		.cra_driver_name	= "poly1305-generic",
  		.cra_priority		= 100,
f979e014c   Martin Willi   crypto: poly1305 ...
120
  		.cra_blocksize		= POLY1305_BLOCK_SIZE,
f979e014c   Martin Willi   crypto: poly1305 ...
121
122
123
124
125
126
127
128
129
130
131
132
133
  		.cra_module		= THIS_MODULE,
  	},
  };
  
  static int __init poly1305_mod_init(void)
  {
  	return crypto_register_shash(&poly1305_alg);
  }
  
  static void __exit poly1305_mod_exit(void)
  {
  	crypto_unregister_shash(&poly1305_alg);
  }
c4741b230   Eric Biggers   crypto: run initc...
134
  subsys_initcall(poly1305_mod_init);
f979e014c   Martin Willi   crypto: poly1305 ...
135
136
137
138
139
140
141
  module_exit(poly1305_mod_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
  MODULE_DESCRIPTION("Poly1305 authenticator");
  MODULE_ALIAS_CRYPTO("poly1305");
  MODULE_ALIAS_CRYPTO("poly1305-generic");