lib:replace: Add getprogname()
[samba.git] / lib / crypto / aes_gcm_128.c
1 /*
2    AES-GCM-128
3
4    Copyright (C) Stefan Metzmacher 2014
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "../lib/crypto/crypto.h"
22 #include "lib/util/byteorder.h"
23
24 static inline void aes_gcm_128_inc32(uint8_t inout[AES_BLOCK_SIZE])
25 {
26         uint32_t v;
27
28         v = RIVAL(inout, AES_BLOCK_SIZE - 4);
29         v += 1;
30         RSIVAL(inout, AES_BLOCK_SIZE - 4, v);
31 }
32
33 static inline void aes_gcm_128_mul(const uint8_t x[AES_BLOCK_SIZE],
34                                    const uint8_t y[AES_BLOCK_SIZE],
35                                    uint8_t v[AES_BLOCK_SIZE],
36                                    uint8_t z[AES_BLOCK_SIZE])
37 {
38         uint8_t i;
39         /* 11100001 || 0^120 */
40         static const uint8_t r[AES_BLOCK_SIZE] = {
41                 0xE1, 0x00, 0x00, 0x00,
42                 0x00, 0x00, 0x00, 0x00,
43                 0x00, 0x00, 0x00, 0x00,
44                 0x00, 0x00, 0x00, 0x00,
45         };
46
47         memset(z, 0, AES_BLOCK_SIZE);
48         memcpy(v, y, AES_BLOCK_SIZE);
49
50         for (i = 0; i < AES_BLOCK_SIZE; i++) {
51                 uint8_t mask;
52                 for (mask = 0x80; mask != 0 ; mask >>= 1) {
53                         uint8_t v_lsb = v[AES_BLOCK_SIZE-1] & 1;
54                         if (x[i] & mask) {
55                                 aes_block_xor(z, v, z);
56                         }
57
58                         aes_block_rshift(v, v);
59                         if (v_lsb != 0) {
60                                 aes_block_xor(v, r, v);
61                         }
62                 }
63         }
64 }
65
66 static inline void aes_gcm_128_ghash_block(struct aes_gcm_128_context *ctx,
67                                            const uint8_t in[AES_BLOCK_SIZE])
68 {
69         aes_block_xor(ctx->Y, in, ctx->y.block);
70         aes_gcm_128_mul(ctx->y.block, ctx->H, ctx->v.block, ctx->Y);
71 }
72
73 void aes_gcm_128_init(struct aes_gcm_128_context *ctx,
74                       const uint8_t K[AES_BLOCK_SIZE],
75                       const uint8_t IV[AES_GCM_128_IV_SIZE])
76 {
77         ZERO_STRUCTP(ctx);
78
79         AES_set_encrypt_key(K, 128, &ctx->aes_key);
80
81         /*
82          * Step 1: generate H (ctx->Y is the zero block here)
83          */
84         AES_encrypt(ctx->Y, ctx->H, &ctx->aes_key);
85
86         /*
87          * Step 2: generate J0
88          */
89         memcpy(ctx->J0, IV, AES_GCM_128_IV_SIZE);
90         aes_gcm_128_inc32(ctx->J0);
91
92         /*
93          * We need to prepare CB with J0.
94          */
95         memcpy(ctx->CB, ctx->J0, AES_BLOCK_SIZE);
96         ctx->c.ofs = AES_BLOCK_SIZE;
97 }
98
99 static inline void aes_gcm_128_update_tmp(struct aes_gcm_128_context *ctx,
100                                           struct aes_gcm_128_tmp *tmp,
101                                           const uint8_t *v, size_t v_len)
102 {
103         tmp->total += v_len;
104
105         if (tmp->ofs > 0) {
106                 size_t copy = MIN(AES_BLOCK_SIZE - tmp->ofs, v_len);
107
108                 memcpy(tmp->block + tmp->ofs, v, copy);
109                 tmp->ofs += copy;
110                 v += copy;
111                 v_len -= copy;
112         }
113
114         if (tmp->ofs == AES_BLOCK_SIZE) {
115                 aes_gcm_128_ghash_block(ctx, tmp->block);
116                 tmp->ofs = 0;
117         }
118
119         while (v_len >= AES_BLOCK_SIZE) {
120                 aes_gcm_128_ghash_block(ctx, v);
121                 v += AES_BLOCK_SIZE;
122                 v_len -= AES_BLOCK_SIZE;
123         }
124
125         if (v_len == 0) {
126                 return;
127         }
128
129         ZERO_STRUCT(tmp->block);
130         memcpy(tmp->block, v, v_len);
131         tmp->ofs = v_len;
132 }
133
134 void aes_gcm_128_updateA(struct aes_gcm_128_context *ctx,
135                          const uint8_t *a, size_t a_len)
136 {
137         aes_gcm_128_update_tmp(ctx, &ctx->A, a, a_len);
138 }
139
140 void aes_gcm_128_updateC(struct aes_gcm_128_context *ctx,
141                          const uint8_t *c, size_t c_len)
142 {
143         if (ctx->A.ofs > 0) {
144                 aes_gcm_128_ghash_block(ctx, ctx->A.block);
145                 ctx->A.ofs = 0;
146         }
147
148         aes_gcm_128_update_tmp(ctx, &ctx->C, c, c_len);
149 }
150
151 static inline void aes_gcm_128_crypt_tmp(struct aes_gcm_128_context *ctx,
152                                          struct aes_gcm_128_tmp *tmp,
153                                          uint8_t *m, size_t m_len)
154 {
155         tmp->total += m_len;
156
157         while (m_len > 0) {
158                 if (tmp->ofs == AES_BLOCK_SIZE) {
159                         aes_gcm_128_inc32(ctx->CB);
160                         AES_encrypt(ctx->CB, tmp->block, &ctx->aes_key);
161                         tmp->ofs = 0;
162                 }
163
164                 if (likely(tmp->ofs == 0 && m_len >= AES_BLOCK_SIZE)) {
165                         aes_block_xor(m, tmp->block, m);
166                         m += AES_BLOCK_SIZE;
167                         m_len -= AES_BLOCK_SIZE;
168                         aes_gcm_128_inc32(ctx->CB);
169                         AES_encrypt(ctx->CB, tmp->block, &ctx->aes_key);
170                         continue;
171                 }
172
173                 m[0] ^= tmp->block[tmp->ofs];
174                 m += 1;
175                 m_len -= 1;
176                 tmp->ofs += 1;
177         }
178 }
179
180 void aes_gcm_128_crypt(struct aes_gcm_128_context *ctx,
181                        uint8_t *m, size_t m_len)
182 {
183         aes_gcm_128_crypt_tmp(ctx, &ctx->c, m, m_len);
184 }
185
186 void aes_gcm_128_digest(struct aes_gcm_128_context *ctx,
187                         uint8_t T[AES_BLOCK_SIZE])
188 {
189         if (ctx->A.ofs > 0) {
190                 aes_gcm_128_ghash_block(ctx, ctx->A.block);
191                 ctx->A.ofs = 0;
192         }
193
194         if (ctx->C.ofs > 0) {
195                 aes_gcm_128_ghash_block(ctx, ctx->C.block);
196                 ctx->C.ofs = 0;
197         }
198
199         RSBVAL(ctx->AC, 0, ctx->A.total * 8);
200         RSBVAL(ctx->AC, 8, ctx->C.total * 8);
201         aes_gcm_128_ghash_block(ctx, ctx->AC);
202
203         AES_encrypt(ctx->J0, ctx->c.block, &ctx->aes_key);
204         aes_block_xor(ctx->c.block, ctx->Y, T);
205
206         ZERO_STRUCTP(ctx);
207 }