chiark / gitweb /
faaf8d71b7889536ba77cf57a8051f84a3f2e0fc
[tripe] / server / bulkcrypto.c
1 /* -*-c-*-
2  *
3  * Bulk crypto transformations
4  *
5  * (c) 2014 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Trivial IP Encryption (TrIPE).
11  *
12  * TrIPE is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * TrIPE is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with TrIPE; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "tripe.h"
30
31 /*----- Utilities ---------------------------------------------------------*/
32
33 #define SEQSZ 4                         /* Size of sequence number packet */
34
35 #define TRACE_IV(qiv, ivsz) do { IF_TRACING(T_KEYSET, {                 \
36   trace_block(T_CRYPTO, "crypto: initialization vector",                \
37               (qiv), (ivsz));                                           \
38 }) } while (0)
39
40 #define TRACE_CT(qpk, sz) do { IF_TRACING(T_KEYSET, {                   \
41   trace_block(T_CRYPTO, "crypto: encrypted packet", (qpk), (sz));       \
42 }) } while (0)
43
44 #define TRACE_MAC(qmac, tagsz) do { IF_TRACING(T_KEYSET, {              \
45   trace_block(T_CRYPTO, "crypto: computed MAC", (qmac), (tagsz));       \
46 }) } while (0)
47
48 #define CHECK_MAC(h, pmac, tagsz) do {                                  \
49   ghash *_h = (h);                                                      \
50   const octet *_pmac = (pmac);                                          \
51   size_t _tagsz = (tagsz);                                              \
52   octet *_mac = GH_DONE(_h, 0);                                         \
53   int _eq = ct_memeq(_mac, _pmac, _tagsz);                              \
54   TRACE_MAC(_mac, _tagsz);                                              \
55   GH_DESTROY(_h);                                                       \
56   if (!_eq) {                                                           \
57     IF_TRACING(T_KEYSET, {                                              \
58       trace(T_KEYSET, "keyset: incorrect MAC: decryption failed");      \
59       trace_block(T_CRYPTO, "crypto: expected MAC", _pmac, _tagsz);     \
60     })                                                                  \
61     return (KSERR_DECRYPT);                                             \
62   }                                                                     \
63 } while (0)
64
65 /*----- The original transform --------------------------------------------*
66  *
67  * We generate a random initialization vector (if the cipher needs one).  We
68  * encrypt the input message with the cipher, and format the type, sequence
69  * number, IV, and ciphertext as follows.
70  *
71  *              +------+ +------+---...---+------...------+
72  *              | type | | seq  |   iv    |   ciphertext  |
73  *              +------+ +------+---...---+------...------+
74  *                 32       32     blksz         sz
75  *
76  * All of this is fed into the MAC to compute a tag.  The type is not
77  * transmitted: the other end knows what type of message it expects, and the
78  * type is only here to prevent us from being confused because some other
79  * kind of ciphertext has been substituted.  The tag is prepended to the
80  * remainder, to yield the finished cryptogram, as follows.
81  *
82  *              +---...---+------+---...---+------...------+
83  *              |   tag   | seq  |   iv    |   ciphertext  |
84  *              +---...---+------+---...---+------...------+
85  *                 tagsz     32     blksz         sz
86  *
87  * Decryption: checks the overall size, verifies the tag, then decrypts the
88  * ciphertext and extracts the sequence number.
89  */
90
91 static int v0_check(const algswitch *a, dstr *e)
92   { return (0); }
93
94 static size_t v0_overhead(const algswitch *a)
95   { return a->tagsz + SEQSZ + a->c->blksz; }
96
97 static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
98 {
99   ghash *h;
100   gcipher *c = ks->out.c;
101   const octet *p = BCUR(b);
102   size_t sz = BLEFT(b);
103   octet *qmac, *qseq, *qiv, *qpk;
104   uint32 oseq;
105   size_t ivsz = GC_CLASS(c)->blksz;
106   size_t tagsz = ks->tagsz;
107   octet t[4];
108
109   /* --- Determine the ciphertext layout --- */
110
111   if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0);
112   qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz;
113   BSTEP(bb, tagsz + SEQSZ + ivsz + sz);
114
115   /* --- Store the type --- *
116    *
117    * This isn't transmitted, but it's covered by the MAC.
118    */
119
120   STORE32(t, ty);
121
122   /* --- Store the sequence number --- */
123
124   oseq = ks->oseq++;
125   STORE32(qseq, oseq);
126
127   /* --- Establish an initialization vector if necessary --- */
128
129   if (ivsz) {
130     rand_get(RAND_GLOBAL, qiv, ivsz);
131     GC_SETIV(c, qiv);
132     TRACE_IV(qiv, ivsz);
133   }
134
135   /* --- Encrypt the packet --- */
136
137   GC_ENCRYPT(c, p, qpk, sz);
138   TRACE_CT(qpk, sz);
139
140   /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */
141
142   if (tagsz) {
143     h = GM_INIT(ks->out.m);
144     GH_HASH(h, t, sizeof(t));
145     GH_HASH(h, qseq, SEQSZ + ivsz + sz);
146     memcpy(qmac, GH_DONE(h, 0), tagsz);
147     GH_DESTROY(h);
148     TRACE_MAC(qmac, tagsz);
149   }
150
151   /* --- We're done --- */
152
153   return (0);
154 }
155
156 static int v0_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
157 {
158   const octet *pmac, *piv, *pseq, *ppk;
159   size_t psz = BLEFT(b);
160   size_t sz;
161   octet *q = BCUR(bb);
162   ghash *h;
163   gcipher *c = ks->in.c;
164   size_t ivsz = GC_CLASS(c)->blksz;
165   size_t tagsz = ks->tagsz;
166   octet t[4];
167
168   /* --- Break up the packet into its components --- */
169
170   if (psz < ivsz + SEQSZ + tagsz) {
171     T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
172     return (KSERR_MALFORMED);
173   }
174   sz = psz - ivsz - SEQSZ - tagsz;
175   pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
176   STORE32(t, ty);
177
178   /* --- Verify the MAC on the packet --- */
179
180   if (tagsz) {
181     h = GM_INIT(ks->in.m);
182     GH_HASH(h, t, sizeof(t));
183     GH_HASH(h, pseq, SEQSZ + ivsz + sz);
184     CHECK_MAC(h, pmac, tagsz);
185   }
186
187   /* --- Decrypt the packet --- */
188
189   if (ivsz) {
190     TRACE_IV(piv, ivsz);
191     GC_SETIV(c, piv);
192   }
193   GC_DECRYPT(c, ppk, q, sz);
194
195   /* --- Finished --- */
196
197   *seq = LOAD32(pseq);
198   BSTEP(bb, sz);
199   return (0);
200 }
201
202 /*----- Bulk crypto transform table ---------------------------------------*/
203
204 const bulkcrypto bulktab[] = {
205
206 #define BULK(name, pre, prim)                                           \
207   { name, prim, pre##_check, pre##_overhead, pre##_encrypt, pre##_decrypt }
208
209   BULK("v0", v0, BCP_CIPHER | BCP_MAC),
210
211 #undef BULK
212   { 0 }
213 };
214
215 /*----- That's all, folks -------------------------------------------------*/