/src/nettle/chacha-poly1305.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* chacha-poly1305.c |
2 | | |
3 | | AEAD mechanism based on chacha and poly1305. |
4 | | |
5 | | Copyright (C) 2014, 2015 Niels Möller |
6 | | |
7 | | This file is part of GNU Nettle. |
8 | | |
9 | | GNU Nettle is free software: you can redistribute it and/or |
10 | | modify it under the terms of either: |
11 | | |
12 | | * the GNU Lesser General Public License as published by the Free |
13 | | Software Foundation; either version 3 of the License, or (at your |
14 | | option) any later version. |
15 | | |
16 | | or |
17 | | |
18 | | * the GNU General Public License as published by the Free |
19 | | Software Foundation; either version 2 of the License, or (at your |
20 | | option) any later version. |
21 | | |
22 | | or both in parallel, as here. |
23 | | |
24 | | GNU Nettle is distributed in the hope that it will be useful, |
25 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
27 | | General Public License for more details. |
28 | | |
29 | | You should have received copies of the GNU General Public License and |
30 | | the GNU Lesser General Public License along with this program. If |
31 | | not, see http://www.gnu.org/licenses/. |
32 | | */ |
33 | | |
34 | | /* This implements chacha-poly1305 according to |
35 | | draft-irtf-cfrg-chacha20-poly1305-08. The inputs to poly1305 are: |
36 | | |
37 | | associated data |
38 | | zero padding |
39 | | ciphertext |
40 | | zero padding |
41 | | length of associated data (64-bit, little endian) |
42 | | length of ciphertext (64-bit, little endian) |
43 | | |
44 | | where the padding fields are 0-15 zero bytes, filling up to a |
45 | | 16-byte boundary. |
46 | | */ |
47 | | |
48 | | #if HAVE_CONFIG_H |
49 | | # include "config.h" |
50 | | #endif |
51 | | |
52 | | #include <assert.h> |
53 | | #include <string.h> |
54 | | |
55 | | #include "chacha-internal.h" |
56 | | #include "chacha-poly1305.h" |
57 | | #include "poly1305-internal.h" |
58 | | |
59 | | #include "macros.h" |
60 | | |
61 | 0 | #define CHACHA_ROUNDS 20 |
62 | | |
63 | | /* FIXME: Also set nonce to zero, and implement nonce |
64 | | auto-increment? */ |
65 | | void |
66 | | chacha_poly1305_set_key (struct chacha_poly1305_ctx *ctx, |
67 | | const uint8_t *key) |
68 | 0 | { |
69 | 0 | chacha_set_key (&ctx->chacha, key); |
70 | 0 | } |
71 | | |
72 | | void |
73 | | chacha_poly1305_set_nonce (struct chacha_poly1305_ctx *ctx, |
74 | | const uint8_t *nonce) |
75 | 0 | { |
76 | 0 | union { |
77 | 0 | uint32_t x[_CHACHA_STATE_LENGTH]; |
78 | 0 | uint8_t subkey[32]; |
79 | 0 | } u; |
80 | |
|
81 | 0 | chacha_set_nonce96 (&ctx->chacha, nonce); |
82 | | /* Generate authentication key */ |
83 | 0 | _nettle_chacha_core (u.x, ctx->chacha.state, CHACHA_ROUNDS); |
84 | 0 | _nettle_poly1305_set_key (&ctx->poly1305, u.subkey); |
85 | | /* For final poly1305 processing */ |
86 | 0 | memcpy (ctx->s.b, u.subkey + 16, 16); |
87 | | /* Increment block count */ |
88 | 0 | ctx->chacha.state[12] = 1; |
89 | |
|
90 | 0 | ctx->auth_size = ctx->data_size = ctx->index = 0; |
91 | 0 | } |
92 | | |
93 | | /* FIXME: Duplicated in poly1305-aes128.c */ |
94 | | #define COMPRESS(ctx, data) _nettle_poly1305_block(&(ctx)->poly1305, (data), 1) |
95 | | |
96 | | static void |
97 | | poly1305_update (struct chacha_poly1305_ctx *ctx, |
98 | | size_t length, const uint8_t *data) |
99 | 0 | { |
100 | 0 | ctx->index = _nettle_poly1305_update (&(ctx)->poly1305, |
101 | 0 | ctx->block, ctx->index, length, data); |
102 | 0 | } |
103 | | |
104 | | static void |
105 | | poly1305_pad (struct chacha_poly1305_ctx *ctx) |
106 | 0 | { |
107 | 0 | if (ctx->index) |
108 | 0 | { |
109 | 0 | memset (ctx->block + ctx->index, 0, |
110 | 0 | POLY1305_BLOCK_SIZE - ctx->index); |
111 | 0 | _nettle_poly1305_block(&ctx->poly1305, ctx->block, 1); |
112 | 0 | ctx->index = 0; |
113 | 0 | } |
114 | 0 | } |
115 | | void |
116 | | chacha_poly1305_update (struct chacha_poly1305_ctx *ctx, |
117 | | size_t length, const uint8_t *data) |
118 | 0 | { |
119 | 0 | assert (ctx->data_size == 0); |
120 | 0 | poly1305_update (ctx, length, data); |
121 | 0 | ctx->auth_size += length; |
122 | 0 | } |
123 | | |
124 | | |
125 | | void |
126 | | chacha_poly1305_encrypt (struct chacha_poly1305_ctx *ctx, |
127 | | size_t length, uint8_t *dst, const uint8_t *src) |
128 | 0 | { |
129 | 0 | if (!length) |
130 | 0 | return; |
131 | | |
132 | 0 | assert (ctx->data_size % CHACHA_POLY1305_BLOCK_SIZE == 0); |
133 | 0 | poly1305_pad (ctx); |
134 | |
|
135 | 0 | chacha_crypt32 (&ctx->chacha, length, dst, src); |
136 | 0 | poly1305_update (ctx, length, dst); |
137 | 0 | ctx->data_size += length; |
138 | 0 | } |
139 | | |
140 | | void |
141 | | chacha_poly1305_decrypt (struct chacha_poly1305_ctx *ctx, |
142 | | size_t length, uint8_t *dst, const uint8_t *src) |
143 | 0 | { |
144 | 0 | if (!length) |
145 | 0 | return; |
146 | | |
147 | 0 | assert (ctx->data_size % CHACHA_POLY1305_BLOCK_SIZE == 0); |
148 | 0 | poly1305_pad (ctx); |
149 | |
|
150 | 0 | poly1305_update (ctx, length, src); |
151 | 0 | chacha_crypt32 (&ctx->chacha, length, dst, src); |
152 | 0 | ctx->data_size += length; |
153 | 0 | } |
154 | | |
155 | | void |
156 | | chacha_poly1305_digest (struct chacha_poly1305_ctx *ctx, |
157 | | size_t length, uint8_t *digest) |
158 | 0 | { |
159 | 0 | uint8_t buf[16]; |
160 | |
|
161 | 0 | poly1305_pad (ctx); |
162 | 0 | LE_WRITE_UINT64 (buf, ctx->auth_size); |
163 | 0 | LE_WRITE_UINT64 (buf + 8, ctx->data_size); |
164 | |
|
165 | 0 | _nettle_poly1305_block (&ctx->poly1305, buf, 1); |
166 | |
|
167 | 0 | _nettle_poly1305_digest (&ctx->poly1305, &ctx->s); |
168 | 0 | memcpy (digest, &ctx->s.b, length); |
169 | 0 | } |