3 * Bulk crypto transformations
5 * (c) 2014 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Trivial IP Encryption (TrIPE).
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.
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.
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.
27 /*----- Header files ------------------------------------------------------*/
31 /*----- Utilities ---------------------------------------------------------*/
33 #define SEQSZ 4 /* Size of sequence number packet */
35 #define TRACE_IV(qiv, ivsz) do { IF_TRACING(T_KEYSET, { \
36 trace_block(T_CRYPTO, "crypto: initialization vector", \
40 #define TRACE_CT(qpk, sz) do { IF_TRACING(T_KEYSET, { \
41 trace_block(T_CRYPTO, "crypto: encrypted packet", (qpk), (sz)); \
44 #define TRACE_MAC(qmac, tagsz) do { IF_TRACING(T_KEYSET, { \
45 trace_block(T_CRYPTO, "crypto: computed MAC", (qmac), (tagsz)); \
48 #define CHECK_MAC(h, pmac, tagsz) do { \
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); \
57 IF_TRACING(T_KEYSET, { \
58 trace(T_KEYSET, "keyset: incorrect MAC: decryption failed"); \
59 trace_block(T_CRYPTO, "crypto: expected MAC", _pmac, _tagsz); \
61 return (KSERR_DECRYPT); \
65 /*----- The original transform --------------------------------------------*
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.
71 * +------+ +------+---...---+------...------+
72 * | type | | seq | iv | ciphertext |
73 * +------+ +------+---...---+------...------+
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.
82 * +---...---+------+---...---+------...------+
83 * | tag | seq | iv | ciphertext |
84 * +---...---+------+---...---+------...------+
87 * Decryption: checks the overall size, verifies the tag, then decrypts the
88 * ciphertext and extracts the sequence number.
91 static int v0_check(const algswitch
*a
, dstr
*e
)
94 static size_t v0_overhead(const algswitch
*a
)
95 { return a
->tagsz
+ SEQSZ
+ a
->c
->blksz
; }
97 static int v0_encrypt(keyset
*ks
, unsigned ty
, buf
*b
, buf
*bb
)
100 gcipher
*c
= ks
->out
.c
;
101 const octet
*p
= BCUR(b
);
102 size_t sz
= BLEFT(b
);
103 octet
*qmac
, *qseq
, *qiv
, *qpk
;
105 size_t ivsz
= GC_CLASS(c
)->blksz
;
106 size_t tagsz
= ks
->tagsz
;
109 /* --- Determine the ciphertext layout --- */
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
);
115 /* --- Store the type --- *
117 * This isn't transmitted, but it's covered by the MAC.
122 /* --- Store the sequence number --- */
127 /* --- Establish an initialization vector if necessary --- */
130 rand_get(RAND_GLOBAL
, qiv
, ivsz
);
135 /* --- Encrypt the packet --- */
137 GC_ENCRYPT(c
, p
, qpk
, sz
);
140 /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */
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
);
148 TRACE_MAC(qmac
, tagsz
);
151 /* --- We're done --- */
156 static int v0_decrypt(keyset
*ks
, unsigned ty
, buf
*b
, buf
*bb
, uint32
*seq
)
158 const octet
*pmac
, *piv
, *pseq
, *ppk
;
159 size_t psz
= BLEFT(b
);
163 gcipher
*c
= ks
->in
.c
;
164 size_t ivsz
= GC_CLASS(c
)->blksz
;
165 size_t tagsz
= ks
->tagsz
;
168 /* --- Break up the packet into its components --- */
170 if (psz
< ivsz
+ SEQSZ
+ tagsz
) {
171 T( trace(T_KEYSET
, "keyset: block too small for keyset %u", ks
->seq
); )
172 return (KSERR_MALFORMED
);
174 sz
= psz
- ivsz
- SEQSZ
- tagsz
;
175 pmac
= BCUR(b
); pseq
= pmac
+ tagsz
; piv
= pseq
+ SEQSZ
; ppk
= piv
+ ivsz
;
178 /* --- Verify the MAC on the packet --- */
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
);
187 /* --- Decrypt the packet --- */
193 GC_DECRYPT(c
, ppk
, q
, sz
);
195 /* --- Finished --- */
202 /*----- The implicit-IV transform -----------------------------------------*
204 * The v0 transform makes everything explicit. There's an IV because the
205 * cipher needs an IV; there's a sequence number because replay prevention
206 * needs a sequence number.
208 * This new transform works rather differently. We make use of a block
209 * cipher to encrypt the sequence number, and use that as the IV. We
210 * transmit the sequence number in the clear, as before. This reduces
211 * overhead; and it's not a significant privacy leak because the adversary
212 * can see the order in which the messages are transmitted -- i.e., the
213 * sequence numbers are almost completely predictable anyway.
215 * So, a MAC is computed over
217 * +------+ +------+------...------+
218 * | type | | seq | ciphertext |
219 * +------+ +------+------...------+
222 * and we actually transmit the following as the cryptogram.
224 * +---...---+------+------...------+
225 * | tag | seq | ciphertext |
226 * +---...---+------+------...------+
230 static int iiv_check(const algswitch
*a
, dstr
*e
)
232 if (a
->b
->blksz
< a
->c
->blksz
) {
233 a_format(e
, "blkc", "%.*s", strlen(a
->b
->name
) - 4, a
->b
->name
,
234 "blksz-insufficient", A_END
);
240 static size_t iiv_overhead(const algswitch
*a
)
241 { return a
->tagsz
+ SEQSZ
; }
243 #define TRACE_PRESEQ(qseq, ivsz) do { IF_TRACING(T_KEYSET, { \
244 trace_block(T_CRYPTO, "crypto: IV derivation input", (qseq), (ivsz)); \
247 static int iiv_encrypt(keyset
*ks
, unsigned ty
, buf
*b
, buf
*bb
)
250 gcipher
*c
= ks
->out
.c
, *blkc
= ks
->out
.b
;
251 const octet
*p
= BCUR(b
);
252 size_t sz
= BLEFT(b
);
253 octet
*qmac
, *qseq
, *qpk
;
255 size_t ivsz
= GC_CLASS(c
)->blksz
, blkcsz
= GC_CLASS(blkc
)->blksz
;
256 size_t tagsz
= ks
->tagsz
;
259 /* --- Determine the ciphertext layout --- */
261 if (buf_ensure(bb
, tagsz
+ SEQSZ
+ sz
)) return (0);
262 qmac
= BCUR(bb
); qseq
= qmac
+ tagsz
; qpk
= qseq
+ SEQSZ
;
263 BSTEP(bb
, tagsz
+ SEQSZ
+ sz
);
265 /* --- Store the type --- *
267 * This isn't transmitted, but it's covered by the MAC.
272 /* --- Store the sequence number --- */
277 /* --- Establish an initialization vector if necessary --- */
280 memset(buf_u
, 0, blkcsz
- SEQSZ
);
281 memcpy(buf_u
+ blkcsz
- SEQSZ
, qseq
, SEQSZ
);
282 TRACE_PRESEQ(buf_u
, ivsz
);
283 GC_ENCRYPT(blkc
, buf_u
, buf_u
, blkcsz
);
285 TRACE_IV(buf_u
, ivsz
);
288 /* --- Encrypt the packet --- */
290 GC_ENCRYPT(c
, p
, qpk
, sz
);
293 /* --- Compute a MAC over type, sequence number, and ciphertext --- */
296 h
= GM_INIT(ks
->out
.m
);
297 GH_HASH(h
, t
, sizeof(t
));
298 GH_HASH(h
, qseq
, SEQSZ
+ sz
);
299 memcpy(qmac
, GH_DONE(h
, 0), tagsz
);
301 TRACE_MAC(qmac
, tagsz
);
304 /* --- We're done --- */
309 static int iiv_decrypt(keyset
*ks
, unsigned ty
, buf
*b
, buf
*bb
, uint32
*seq
)
311 const octet
*pmac
, *pseq
, *ppk
;
312 size_t psz
= BLEFT(b
);
316 gcipher
*c
= ks
->in
.c
, *blkc
= ks
->in
.b
;
317 size_t ivsz
= GC_CLASS(c
)->blksz
, blkcsz
= GC_CLASS(blkc
)->blksz
;
318 size_t tagsz
= ks
->tagsz
;
321 /* --- Break up the packet into its components --- */
323 if (psz
< SEQSZ
+ tagsz
) {
324 T( trace(T_KEYSET
, "keyset: block too small for keyset %u", ks
->seq
); )
325 return (KSERR_MALFORMED
);
327 sz
= psz
- SEQSZ
- tagsz
;
328 pmac
= BCUR(b
); pseq
= pmac
+ tagsz
; ppk
= pseq
+ SEQSZ
;
331 /* --- Verify the MAC on the packet --- */
334 h
= GM_INIT(ks
->in
.m
);
335 GH_HASH(h
, t
, sizeof(t
));
336 GH_HASH(h
, pseq
, SEQSZ
+ sz
);
337 CHECK_MAC(h
, pmac
, tagsz
);
340 /* --- Decrypt the packet --- */
343 memset(buf_u
, 0, blkcsz
- SEQSZ
);
344 memcpy(buf_u
+ blkcsz
- SEQSZ
, pseq
, SEQSZ
);
345 TRACE_PRESEQ(buf_u
, ivsz
);
346 GC_ENCRYPT(blkc
, buf_u
, buf_u
, blkcsz
);
348 TRACE_IV(buf_u
, ivsz
);
350 GC_DECRYPT(c
, ppk
, q
, sz
);
352 /* --- Finished --- */
359 /*----- Bulk crypto transform table ---------------------------------------*/
361 const bulkcrypto bulktab
[] = {
363 #define BULK(name, pre, prim) \
364 { name, prim, pre##_check, pre##_overhead, pre##_encrypt, pre##_decrypt }
366 BULK("v0", v0
, BCP_CIPHER
| BCP_MAC
),
367 BULK("iiv", iiv
, BCP_CIPHER
| BCP_MAC
| BCP_BLKC
),
373 /*----- That's all, folks -------------------------------------------------*/