cfb8: Fix decrypt path
[gd/nettle] / xts.c
1 /* xts.c
2
3    XEX-based tweaked-codebook mode with ciphertext stealing (XTS)
4
5    Copyright (C) 2018 Red Hat, Inc.
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 #if HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <assert.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "xts.h"
43
44 #include "macros.h"
45 #include "memxor.h"
46 #include "nettle-internal.h"
47 #include "block-internal.h"
48
49 static void
50 check_length(size_t length, uint8_t *dst)
51 {
52   assert(length >= XTS_BLOCK_SIZE);
53   /* asserts may be compiled out, try to save the user by zeroing the dst in
54    * case the buffer contains sensitive data (like the clear text for inplace
55    * encryption) */
56   if (length < XTS_BLOCK_SIZE)
57     memset(dst, '\0', length);
58 }
59
60 /* works also for inplace encryption/decryption */
61
62 void
63 xts_encrypt_message(const void *enc_ctx, const void *twk_ctx,
64                     nettle_cipher_func *encf,
65                     const uint8_t *tweak, size_t length,
66                     uint8_t *dst, const uint8_t *src)
67 {
68   union nettle_block16 T;
69   union nettle_block16 P;
70
71   check_length(length, dst);
72
73   encf(twk_ctx, XTS_BLOCK_SIZE, T.b, tweak);
74
75   /* the zeroth power of alpha is the initial ciphertext value itself, so we
76    * skip shifting and do it at the end of each block operation instead */
77   for (;length >= 2 * XTS_BLOCK_SIZE || length == XTS_BLOCK_SIZE;
78        length -= XTS_BLOCK_SIZE, src += XTS_BLOCK_SIZE, dst += XTS_BLOCK_SIZE)
79     {
80       memxor3(P.b, src, T.b, XTS_BLOCK_SIZE);   /* P -> PP */
81       encf(enc_ctx, XTS_BLOCK_SIZE, dst, P.b);  /* CC */
82       memxor(dst, T.b, XTS_BLOCK_SIZE);         /* CC -> C */
83
84       /* shift T for next block if any */
85       if (length > XTS_BLOCK_SIZE)
86           block16_mulx_le(&T, &T);
87     }
88
89   /* if the last block is partial, handle via stealing */
90   if (length)
91     {
92       /* S Holds the real C(n-1) (Whole last block to steal from) */
93       union nettle_block16 S;
94
95       memxor3(P.b, src, T.b, XTS_BLOCK_SIZE);   /* P -> PP */
96       encf(enc_ctx, XTS_BLOCK_SIZE, S.b, P.b);  /* CC */
97       memxor(S.b, T.b, XTS_BLOCK_SIZE);         /* CC -> S */
98
99       /* shift T for next block */
100       block16_mulx_le(&T, &T);
101
102       length -= XTS_BLOCK_SIZE;
103       src += XTS_BLOCK_SIZE;
104
105       memxor3(P.b, src, T.b, length);           /* P |.. */
106       /* steal ciphertext to complete block */
107       memxor3(P.b + length, S.b + length, T.b + length,
108               XTS_BLOCK_SIZE - length);         /* ..| S_2 -> PP */
109
110       encf(enc_ctx, XTS_BLOCK_SIZE, dst, P.b);  /* CC */
111       memxor(dst, T.b, XTS_BLOCK_SIZE);         /* CC -> C(n-1) */
112
113       /* Do this after we read src so inplace operations do not break */
114       dst += XTS_BLOCK_SIZE;
115       memcpy(dst, S.b, length);                 /* S_1 -> C(n) */
116     }
117 }
118
119 void
120 xts_decrypt_message(const void *dec_ctx, const void *twk_ctx,
121                     nettle_cipher_func *decf, nettle_cipher_func *encf,
122                     const uint8_t *tweak, size_t length,
123                     uint8_t *dst, const uint8_t *src)
124 {
125   union nettle_block16 T;
126   union nettle_block16 C;
127
128   check_length(length, dst);
129
130   encf(twk_ctx, XTS_BLOCK_SIZE, T.b, tweak);
131
132   for (;length >= 2 * XTS_BLOCK_SIZE || length == XTS_BLOCK_SIZE;
133        length -= XTS_BLOCK_SIZE, src += XTS_BLOCK_SIZE, dst += XTS_BLOCK_SIZE)
134     {
135       memxor3(C.b, src, T.b, XTS_BLOCK_SIZE);   /* c -> CC */
136       decf(dec_ctx, XTS_BLOCK_SIZE, dst, C.b);  /* PP */
137       memxor(dst, T.b, XTS_BLOCK_SIZE);         /* PP -> P */
138
139       /* shift T for next block if any */
140       if (length > XTS_BLOCK_SIZE)
141           block16_mulx_le(&T, &T);
142     }
143
144   /* if the last block is partial, handle via stealing */
145   if (length)
146     {
147       union nettle_block16 T1;
148       /* S Holds the real P(n) (with part of stolen ciphertext) */
149       union nettle_block16 S;
150
151       /* we need the last T(n) and save the T(n-1) for later */
152       block16_mulx_le(&T1, &T);
153
154       memxor3(C.b, src, T1.b, XTS_BLOCK_SIZE);  /* C -> CC */
155       decf(dec_ctx, XTS_BLOCK_SIZE, S.b, C.b);  /* PP */
156       memxor(S.b, T1.b, XTS_BLOCK_SIZE);        /* PP -> S */
157
158       /* process next block (Pn-1) */
159       length -= XTS_BLOCK_SIZE;
160       src += XTS_BLOCK_SIZE;
161
162       /* Prepare C, P holds the real P(n) */
163       memxor3(C.b, src, T.b, length);           /* C_1 |.. */
164       memxor3(C.b + length, S.b + length, T.b + length,
165               XTS_BLOCK_SIZE - length);         /* ..| S_2 -> CC */
166       decf(dec_ctx, XTS_BLOCK_SIZE, dst, C.b);  /* PP */
167       memxor(dst, T.b, XTS_BLOCK_SIZE);         /* PP -> P(n-1) */
168
169       /* Do this after we read src so inplace operations do not break */
170       dst += XTS_BLOCK_SIZE;
171       memcpy(dst, S.b, length);                 /* S_1 -> P(n) */
172     }
173 }