Coverage Report

Created: 2025-04-22 06:18

/src/openssl/crypto/modes/cts128.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <string.h>
11
#include <openssl/crypto.h>
12
#include "crypto/modes.h"
13
14
/*
15
 * Trouble with Ciphertext Stealing, CTS, mode is that there is no
16
 * common official specification, but couple of cipher/application
17
 * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to
18
 * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which
19
 * deviates from mentioned RFCs. Most notably it allows input to be
20
 * of block length and it doesn't flip the order of the last two
21
 * blocks. CTS is being discussed even in ECB context, but it's not
22
 * adopted for any known application. This implementation provides
23
 * two interfaces: one compliant with above mentioned RFCs and one
24
 * compliant with the NIST proposal, both extending CBC mode.
25
 */
26
27
size_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
28
                                   unsigned char *out, size_t len,
29
                                   const void *key, unsigned char ivec[16],
30
                                   block128_f block)
31
0
{
32
0
    size_t residue, n;
33
34
0
    if (len <= 16)
35
0
        return 0;
36
37
0
    if ((residue = len % 16) == 0)
38
0
        residue = 16;
39
40
0
    len -= residue;
41
42
0
    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
43
44
0
    in += len;
45
0
    out += len;
46
47
0
    for (n = 0; n < residue; ++n)
48
0
        ivec[n] ^= in[n];
49
0
    (*block) (ivec, ivec, key);
50
0
    memcpy(out, out - 16, residue);
51
0
    memcpy(out - 16, ivec, 16);
52
53
0
    return len + residue;
54
0
}
55
56
size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in,
57
                                       unsigned char *out, size_t len,
58
                                       const void *key,
59
                                       unsigned char ivec[16],
60
                                       block128_f block)
61
0
{
62
0
    size_t residue, n;
63
64
0
    if (len < 16)
65
0
        return 0;
66
67
0
    residue = len % 16;
68
69
0
    len -= residue;
70
71
0
    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
72
73
0
    if (residue == 0)
74
0
        return len;
75
76
0
    in += len;
77
0
    out += len;
78
79
0
    for (n = 0; n < residue; ++n)
80
0
        ivec[n] ^= in[n];
81
0
    (*block) (ivec, ivec, key);
82
0
    memcpy(out - 16 + residue, ivec, 16);
83
84
0
    return len + residue;
85
0
}
86
87
size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
88
                             size_t len, const void *key,
89
                             unsigned char ivec[16], cbc128_f cbc)
90
0
{
91
0
    size_t residue;
92
0
    union {
93
0
        size_t align;
94
0
        unsigned char c[16];
95
0
    } tmp;
96
97
0
    if (len <= 16)
98
0
        return 0;
99
100
0
    if ((residue = len % 16) == 0)
101
0
        residue = 16;
102
103
0
    len -= residue;
104
105
0
    (*cbc) (in, out, len, key, ivec, 1);
106
107
0
    in += len;
108
0
    out += len;
109
110
#if defined(CBC_HANDLES_TRUNCATED_IO)
111
    memcpy(tmp.c, out - 16, 16);
112
    (*cbc) (in, out - 16, residue, key, ivec, 1);
113
    memcpy(out, tmp.c, residue);
114
#else
115
0
    memset(tmp.c, 0, sizeof(tmp));
116
0
    memcpy(tmp.c, in, residue);
117
0
    memcpy(out, out - 16, residue);
118
0
    (*cbc) (tmp.c, out - 16, 16, key, ivec, 1);
119
0
#endif
120
0
    return len + residue;
121
0
}
122
123
size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
124
                                 size_t len, const void *key,
125
                                 unsigned char ivec[16], cbc128_f cbc)
126
0
{
127
0
    size_t residue;
128
0
    union {
129
0
        size_t align;
130
0
        unsigned char c[16];
131
0
    } tmp;
132
133
0
    if (len < 16)
134
0
        return 0;
135
136
0
    residue = len % 16;
137
138
0
    len -= residue;
139
140
0
    (*cbc) (in, out, len, key, ivec, 1);
141
142
0
    if (residue == 0)
143
0
        return len;
144
145
0
    in += len;
146
0
    out += len;
147
148
#if defined(CBC_HANDLES_TRUNCATED_IO)
149
    (*cbc) (in, out - 16 + residue, residue, key, ivec, 1);
150
#else
151
0
    memset(tmp.c, 0, sizeof(tmp));
152
0
    memcpy(tmp.c, in, residue);
153
0
    (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1);
154
0
#endif
155
0
    return len + residue;
156
0
}
157
158
size_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
159
                                   unsigned char *out, size_t len,
160
                                   const void *key, unsigned char ivec[16],
161
                                   block128_f block)
162
0
{
163
0
    size_t residue, n;
164
0
    union {
165
0
        size_t align;
166
0
        unsigned char c[32];
167
0
    } tmp;
168
169
0
    if (len <= 16)
170
0
        return 0;
171
172
0
    if ((residue = len % 16) == 0)
173
0
        residue = 16;
174
175
0
    len -= 16 + residue;
176
177
0
    if (len) {
178
0
        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
179
0
        in += len;
180
0
        out += len;
181
0
    }
182
183
0
    (*block) (in, tmp.c + 16, key);
184
185
0
    memcpy(tmp.c, tmp.c + 16, 16);
186
0
    memcpy(tmp.c, in + 16, residue);
187
0
    (*block) (tmp.c, tmp.c, key);
188
189
0
    for (n = 0; n < 16; ++n) {
190
0
        unsigned char c = in[n];
191
0
        out[n] = tmp.c[n] ^ ivec[n];
192
0
        ivec[n] = c;
193
0
    }
194
0
    for (residue += 16; n < residue; ++n)
195
0
        out[n] = tmp.c[n] ^ in[n];
196
197
0
    return 16 + len + residue;
198
0
}
199
200
size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in,
201
                                       unsigned char *out, size_t len,
202
                                       const void *key,
203
                                       unsigned char ivec[16],
204
                                       block128_f block)
205
0
{
206
0
    size_t residue, n;
207
0
    union {
208
0
        size_t align;
209
0
        unsigned char c[32];
210
0
    } tmp;
211
212
0
    if (len < 16)
213
0
        return 0;
214
215
0
    residue = len % 16;
216
217
0
    if (residue == 0) {
218
0
        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
219
0
        return len;
220
0
    }
221
222
0
    len -= 16 + residue;
223
224
0
    if (len) {
225
0
        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
226
0
        in += len;
227
0
        out += len;
228
0
    }
229
230
0
    (*block) (in + residue, tmp.c + 16, key);
231
232
0
    memcpy(tmp.c, tmp.c + 16, 16);
233
0
    memcpy(tmp.c, in, residue);
234
0
    (*block) (tmp.c, tmp.c, key);
235
236
0
    for (n = 0; n < 16; ++n) {
237
0
        unsigned char c = in[n];
238
0
        out[n] = tmp.c[n] ^ ivec[n];
239
0
        ivec[n] = in[n + residue];
240
0
        tmp.c[n] = c;
241
0
    }
242
0
    for (residue += 16; n < residue; ++n)
243
0
        out[n] = tmp.c[n] ^ tmp.c[n - 16];
244
245
0
    return 16 + len + residue;
246
0
}
247
248
size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
249
                             size_t len, const void *key,
250
                             unsigned char ivec[16], cbc128_f cbc)
251
0
{
252
0
    size_t residue;
253
0
    union {
254
0
        size_t align;
255
0
        unsigned char c[32];
256
0
    } tmp;
257
258
0
    if (len <= 16)
259
0
        return 0;
260
261
0
    if ((residue = len % 16) == 0)
262
0
        residue = 16;
263
264
0
    len -= 16 + residue;
265
266
0
    if (len) {
267
0
        (*cbc) (in, out, len, key, ivec, 0);
268
0
        in += len;
269
0
        out += len;
270
0
    }
271
272
0
    memset(tmp.c, 0, sizeof(tmp));
273
    /*
274
     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
275
     */
276
0
    (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0);
277
278
0
    memcpy(tmp.c, in + 16, residue);
279
#if defined(CBC_HANDLES_TRUNCATED_IO)
280
    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
281
#else
282
0
    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
283
0
    memcpy(out, tmp.c, 16 + residue);
284
0
#endif
285
0
    return 16 + len + residue;
286
0
}
287
288
size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
289
                                 size_t len, const void *key,
290
                                 unsigned char ivec[16], cbc128_f cbc)
291
0
{
292
0
    size_t residue;
293
0
    union {
294
0
        size_t align;
295
0
        unsigned char c[32];
296
0
    } tmp;
297
298
0
    if (len < 16)
299
0
        return 0;
300
301
0
    residue = len % 16;
302
303
0
    if (residue == 0) {
304
0
        (*cbc) (in, out, len, key, ivec, 0);
305
0
        return len;
306
0
    }
307
308
0
    len -= 16 + residue;
309
310
0
    if (len) {
311
0
        (*cbc) (in, out, len, key, ivec, 0);
312
0
        in += len;
313
0
        out += len;
314
0
    }
315
316
0
    memset(tmp.c, 0, sizeof(tmp));
317
    /*
318
     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
319
     */
320
0
    (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0);
321
322
0
    memcpy(tmp.c, in, residue);
323
#if defined(CBC_HANDLES_TRUNCATED_IO)
324
    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
325
#else
326
0
    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
327
0
    memcpy(out, tmp.c, 16 + residue);
328
0
#endif
329
0
    return 16 + len + residue;
330
0
}