1238384Sjkim/* ====================================================================
2238384Sjkim * Copyright (c) 2008 The OpenSSL Project. All rights reserved.
3238384Sjkim *
4238384Sjkim * Rights for redistribution and usage in source and binary
5238384Sjkim * forms are granted according to the OpenSSL license.
6238384Sjkim */
7238384Sjkim
8238384Sjkim#include <openssl/crypto.h>
9238384Sjkim#include "modes_lcl.h"
10238384Sjkim#include <string.h>
11238384Sjkim
12238384Sjkim#ifndef MODES_DEBUG
13238384Sjkim# ifndef NDEBUG
14238384Sjkim#  define NDEBUG
15238384Sjkim# endif
16238384Sjkim#endif
17238384Sjkim#include <assert.h>
18238384Sjkim
19238384Sjkim/*
20238384Sjkim * Trouble with Ciphertext Stealing, CTS, mode is that there is no
21238384Sjkim * common official specification, but couple of cipher/application
22238384Sjkim * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to
23238384Sjkim * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which
24238384Sjkim * deviates from mentioned RFCs. Most notably it allows input to be
25238384Sjkim * of block length and it doesn't flip the order of the last two
26238384Sjkim * blocks. CTS is being discussed even in ECB context, but it's not
27238384Sjkim * adopted for any known application. This implementation provides
28238384Sjkim * two interfaces: one compliant with above mentioned RFCs and one
29238384Sjkim * compliant with the NIST proposal, both extending CBC mode.
30238384Sjkim */
31238384Sjkim
32296341Sdelphijsize_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
33296341Sdelphij                                   unsigned char *out, size_t len,
34296341Sdelphij                                   const void *key, unsigned char ivec[16],
35296341Sdelphij                                   block128_f block)
36296341Sdelphij{
37296341Sdelphij    size_t residue, n;
38238384Sjkim
39296341Sdelphij    assert(in && out && key && ivec);
40238384Sjkim
41296341Sdelphij    if (len <= 16)
42296341Sdelphij        return 0;
43238384Sjkim
44296341Sdelphij    if ((residue = len % 16) == 0)
45296341Sdelphij        residue = 16;
46238384Sjkim
47296341Sdelphij    len -= residue;
48238384Sjkim
49296341Sdelphij    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
50238384Sjkim
51296341Sdelphij    in += len;
52296341Sdelphij    out += len;
53238384Sjkim
54296341Sdelphij    for (n = 0; n < residue; ++n)
55296341Sdelphij        ivec[n] ^= in[n];
56296341Sdelphij    (*block) (ivec, ivec, key);
57296341Sdelphij    memcpy(out, out - 16, residue);
58296341Sdelphij    memcpy(out - 16, ivec, 16);
59238384Sjkim
60296341Sdelphij    return len + residue;
61238384Sjkim}
62238384Sjkim
63296341Sdelphijsize_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in,
64296341Sdelphij                                       unsigned char *out, size_t len,
65296341Sdelphij                                       const void *key,
66296341Sdelphij                                       unsigned char ivec[16],
67296341Sdelphij                                       block128_f block)
68296341Sdelphij{
69296341Sdelphij    size_t residue, n;
70238384Sjkim
71296341Sdelphij    assert(in && out && key && ivec);
72238384Sjkim
73296341Sdelphij    if (len < 16)
74296341Sdelphij        return 0;
75238384Sjkim
76296341Sdelphij    residue = len % 16;
77238384Sjkim
78296341Sdelphij    len -= residue;
79238384Sjkim
80296341Sdelphij    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
81238384Sjkim
82296341Sdelphij    if (residue == 0)
83296341Sdelphij        return len;
84238384Sjkim
85296341Sdelphij    in += len;
86296341Sdelphij    out += len;
87238384Sjkim
88296341Sdelphij    for (n = 0; n < residue; ++n)
89296341Sdelphij        ivec[n] ^= in[n];
90296341Sdelphij    (*block) (ivec, ivec, key);
91296341Sdelphij    memcpy(out - 16 + residue, ivec, 16);
92238384Sjkim
93296341Sdelphij    return len + residue;
94238384Sjkim}
95238384Sjkim
96238384Sjkimsize_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
97296341Sdelphij                             size_t len, const void *key,
98296341Sdelphij                             unsigned char ivec[16], cbc128_f cbc)
99296341Sdelphij{
100296341Sdelphij    size_t residue;
101296341Sdelphij    union {
102296341Sdelphij        size_t align;
103296341Sdelphij        unsigned char c[16];
104296341Sdelphij    } tmp;
105238384Sjkim
106296341Sdelphij    assert(in && out && key && ivec);
107238384Sjkim
108296341Sdelphij    if (len <= 16)
109296341Sdelphij        return 0;
110238384Sjkim
111296341Sdelphij    if ((residue = len % 16) == 0)
112296341Sdelphij        residue = 16;
113238384Sjkim
114296341Sdelphij    len -= residue;
115238384Sjkim
116296341Sdelphij    (*cbc) (in, out, len, key, ivec, 1);
117238384Sjkim
118296341Sdelphij    in += len;
119296341Sdelphij    out += len;
120238384Sjkim
121238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
122296341Sdelphij    memcpy(tmp.c, out - 16, 16);
123296341Sdelphij    (*cbc) (in, out - 16, residue, key, ivec, 1);
124296341Sdelphij    memcpy(out, tmp.c, residue);
125238384Sjkim#else
126296341Sdelphij    memset(tmp.c, 0, sizeof(tmp));
127296341Sdelphij    memcpy(tmp.c, in, residue);
128296341Sdelphij    memcpy(out, out - 16, residue);
129296341Sdelphij    (*cbc) (tmp.c, out - 16, 16, key, ivec, 1);
130238384Sjkim#endif
131296341Sdelphij    return len + residue;
132238384Sjkim}
133238384Sjkim
134238384Sjkimsize_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
135296341Sdelphij                                 size_t len, const void *key,
136296341Sdelphij                                 unsigned char ivec[16], cbc128_f cbc)
137296341Sdelphij{
138296341Sdelphij    size_t residue;
139296341Sdelphij    union {
140296341Sdelphij        size_t align;
141296341Sdelphij        unsigned char c[16];
142296341Sdelphij    } tmp;
143238384Sjkim
144296341Sdelphij    assert(in && out && key && ivec);
145238384Sjkim
146296341Sdelphij    if (len < 16)
147296341Sdelphij        return 0;
148238384Sjkim
149296341Sdelphij    residue = len % 16;
150238384Sjkim
151296341Sdelphij    len -= residue;
152238384Sjkim
153296341Sdelphij    (*cbc) (in, out, len, key, ivec, 1);
154238384Sjkim
155296341Sdelphij    if (residue == 0)
156296341Sdelphij        return len;
157238384Sjkim
158296341Sdelphij    in += len;
159296341Sdelphij    out += len;
160238384Sjkim
161238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
162296341Sdelphij    (*cbc) (in, out - 16 + residue, residue, key, ivec, 1);
163238384Sjkim#else
164296341Sdelphij    memset(tmp.c, 0, sizeof(tmp));
165296341Sdelphij    memcpy(tmp.c, in, residue);
166296341Sdelphij    (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1);
167238384Sjkim#endif
168296341Sdelphij    return len + residue;
169238384Sjkim}
170238384Sjkim
171296341Sdelphijsize_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
172296341Sdelphij                                   unsigned char *out, size_t len,
173296341Sdelphij                                   const void *key, unsigned char ivec[16],
174296341Sdelphij                                   block128_f block)
175296341Sdelphij{
176296341Sdelphij    size_t residue, n;
177296341Sdelphij    union {
178296341Sdelphij        size_t align;
179296341Sdelphij        unsigned char c[32];
180296341Sdelphij    } tmp;
181238384Sjkim
182296341Sdelphij    assert(in && out && key && ivec);
183238384Sjkim
184296341Sdelphij    if (len <= 16)
185296341Sdelphij        return 0;
186238384Sjkim
187296341Sdelphij    if ((residue = len % 16) == 0)
188296341Sdelphij        residue = 16;
189238384Sjkim
190296341Sdelphij    len -= 16 + residue;
191238384Sjkim
192296341Sdelphij    if (len) {
193296341Sdelphij        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
194296341Sdelphij        in += len;
195296341Sdelphij        out += len;
196296341Sdelphij    }
197238384Sjkim
198296341Sdelphij    (*block) (in, tmp.c + 16, key);
199238384Sjkim
200296341Sdelphij    memcpy(tmp.c, tmp.c + 16, 16);
201296341Sdelphij    memcpy(tmp.c, in + 16, residue);
202296341Sdelphij    (*block) (tmp.c, tmp.c, key);
203238384Sjkim
204296341Sdelphij    for (n = 0; n < 16; ++n) {
205296341Sdelphij        unsigned char c = in[n];
206296341Sdelphij        out[n] = tmp.c[n] ^ ivec[n];
207296341Sdelphij        ivec[n] = c;
208296341Sdelphij    }
209296341Sdelphij    for (residue += 16; n < residue; ++n)
210296341Sdelphij        out[n] = tmp.c[n] ^ in[n];
211238384Sjkim
212296341Sdelphij    return 16 + len + residue;
213238384Sjkim}
214238384Sjkim
215296341Sdelphijsize_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in,
216296341Sdelphij                                       unsigned char *out, size_t len,
217296341Sdelphij                                       const void *key,
218296341Sdelphij                                       unsigned char ivec[16],
219296341Sdelphij                                       block128_f block)
220296341Sdelphij{
221296341Sdelphij    size_t residue, n;
222296341Sdelphij    union {
223296341Sdelphij        size_t align;
224296341Sdelphij        unsigned char c[32];
225296341Sdelphij    } tmp;
226238384Sjkim
227296341Sdelphij    assert(in && out && key && ivec);
228238384Sjkim
229296341Sdelphij    if (len < 16)
230296341Sdelphij        return 0;
231238384Sjkim
232296341Sdelphij    residue = len % 16;
233238384Sjkim
234296341Sdelphij    if (residue == 0) {
235296341Sdelphij        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
236296341Sdelphij        return len;
237296341Sdelphij    }
238238384Sjkim
239296341Sdelphij    len -= 16 + residue;
240238384Sjkim
241296341Sdelphij    if (len) {
242296341Sdelphij        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
243296341Sdelphij        in += len;
244296341Sdelphij        out += len;
245296341Sdelphij    }
246238384Sjkim
247296341Sdelphij    (*block) (in + residue, tmp.c + 16, key);
248238384Sjkim
249296341Sdelphij    memcpy(tmp.c, tmp.c + 16, 16);
250296341Sdelphij    memcpy(tmp.c, in, residue);
251296341Sdelphij    (*block) (tmp.c, tmp.c, key);
252238384Sjkim
253296341Sdelphij    for (n = 0; n < 16; ++n) {
254296341Sdelphij        unsigned char c = in[n];
255296341Sdelphij        out[n] = tmp.c[n] ^ ivec[n];
256296341Sdelphij        ivec[n] = in[n + residue];
257296341Sdelphij        tmp.c[n] = c;
258296341Sdelphij    }
259296341Sdelphij    for (residue += 16; n < residue; ++n)
260296341Sdelphij        out[n] = tmp.c[n] ^ tmp.c[n - 16];
261238384Sjkim
262296341Sdelphij    return 16 + len + residue;
263238384Sjkim}
264238384Sjkim
265238384Sjkimsize_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
266296341Sdelphij                             size_t len, const void *key,
267296341Sdelphij                             unsigned char ivec[16], cbc128_f cbc)
268296341Sdelphij{
269296341Sdelphij    size_t residue;
270296341Sdelphij    union {
271296341Sdelphij        size_t align;
272296341Sdelphij        unsigned char c[32];
273296341Sdelphij    } tmp;
274238384Sjkim
275296341Sdelphij    assert(in && out && key && ivec);
276238384Sjkim
277296341Sdelphij    if (len <= 16)
278296341Sdelphij        return 0;
279238384Sjkim
280296341Sdelphij    if ((residue = len % 16) == 0)
281296341Sdelphij        residue = 16;
282238384Sjkim
283296341Sdelphij    len -= 16 + residue;
284238384Sjkim
285296341Sdelphij    if (len) {
286296341Sdelphij        (*cbc) (in, out, len, key, ivec, 0);
287296341Sdelphij        in += len;
288296341Sdelphij        out += len;
289296341Sdelphij    }
290238384Sjkim
291296341Sdelphij    memset(tmp.c, 0, sizeof(tmp));
292296341Sdelphij    /*
293296341Sdelphij     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
294296341Sdelphij     */
295296341Sdelphij    (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0);
296238384Sjkim
297296341Sdelphij    memcpy(tmp.c, in + 16, residue);
298238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
299296341Sdelphij    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
300238384Sjkim#else
301296341Sdelphij    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
302296341Sdelphij    memcpy(out, tmp.c, 16 + residue);
303238384Sjkim#endif
304296341Sdelphij    return 16 + len + residue;
305238384Sjkim}
306238384Sjkim
307238384Sjkimsize_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
308296341Sdelphij                                 size_t len, const void *key,
309296341Sdelphij                                 unsigned char ivec[16], cbc128_f cbc)
310296341Sdelphij{
311296341Sdelphij    size_t residue;
312296341Sdelphij    union {
313296341Sdelphij        size_t align;
314296341Sdelphij        unsigned char c[32];
315296341Sdelphij    } tmp;
316238384Sjkim
317296341Sdelphij    assert(in && out && key && ivec);
318238384Sjkim
319296341Sdelphij    if (len < 16)
320296341Sdelphij        return 0;
321238384Sjkim
322296341Sdelphij    residue = len % 16;
323238384Sjkim
324296341Sdelphij    if (residue == 0) {
325296341Sdelphij        (*cbc) (in, out, len, key, ivec, 0);
326296341Sdelphij        return len;
327296341Sdelphij    }
328238384Sjkim
329296341Sdelphij    len -= 16 + residue;
330238384Sjkim
331296341Sdelphij    if (len) {
332296341Sdelphij        (*cbc) (in, out, len, key, ivec, 0);
333296341Sdelphij        in += len;
334296341Sdelphij        out += len;
335296341Sdelphij    }
336238384Sjkim
337296341Sdelphij    memset(tmp.c, 0, sizeof(tmp));
338296341Sdelphij    /*
339296341Sdelphij     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
340296341Sdelphij     */
341296341Sdelphij    (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0);
342238384Sjkim
343296341Sdelphij    memcpy(tmp.c, in, residue);
344238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
345296341Sdelphij    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
346238384Sjkim#else
347296341Sdelphij    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
348296341Sdelphij    memcpy(out, tmp.c, 16 + residue);
349238384Sjkim#endif
350296341Sdelphij    return 16 + len + residue;
351238384Sjkim}
352238384Sjkim
353238384Sjkim#if defined(SELFTEST)
354296341Sdelphij# include <stdio.h>
355296341Sdelphij# include <openssl/aes.h>
356238384Sjkim
357238384Sjkim/* test vectors from RFC 3962 */
358238384Sjkimstatic const unsigned char test_key[16] = "chicken teriyaki";
359238384Sjkimstatic const unsigned char test_input[64] =
360296341Sdelphij    "I would like the" " General Gau's C"
361296341Sdelphij    "hicken, please, " "and wonton soup.";
362296341Sdelphijstatic const unsigned char test_iv[16] =
363296341Sdelphij    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
364238384Sjkim
365296341Sdelphijstatic const unsigned char vector_17[17] = {
366296341Sdelphij    0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
367296341Sdelphij    0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
368296341Sdelphij    0x97
369296341Sdelphij};
370238384Sjkim
371296341Sdelphijstatic const unsigned char vector_31[31] = {
372296341Sdelphij    0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
373296341Sdelphij    0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
374296341Sdelphij    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
375296341Sdelphij    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5
376296341Sdelphij};
377296341Sdelphij
378296341Sdelphijstatic const unsigned char vector_32[32] = {
379296341Sdelphij    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
380296341Sdelphij    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
381296341Sdelphij    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
382296341Sdelphij    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84
383296341Sdelphij};
384296341Sdelphij
385296341Sdelphijstatic const unsigned char vector_47[47] = {
386296341Sdelphij    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
387296341Sdelphij    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
388296341Sdelphij    0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
389296341Sdelphij    0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
390296341Sdelphij    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
391296341Sdelphij    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5
392296341Sdelphij};
393296341Sdelphij
394296341Sdelphijstatic const unsigned char vector_48[48] = {
395296341Sdelphij    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
396296341Sdelphij    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
397296341Sdelphij    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
398296341Sdelphij    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
399296341Sdelphij    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
400296341Sdelphij    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
401296341Sdelphij};
402296341Sdelphij
403296341Sdelphijstatic const unsigned char vector_64[64] = {
404296341Sdelphij    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
405296341Sdelphij    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
406296341Sdelphij    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
407296341Sdelphij    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
408296341Sdelphij    0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
409296341Sdelphij    0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
410296341Sdelphij    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
411296341Sdelphij    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
412296341Sdelphij};
413296341Sdelphij
414238384Sjkimstatic AES_KEY encks, decks;
415238384Sjkim
416296341Sdelphijvoid test_vector(const unsigned char *vector, size_t len)
417296341Sdelphij{
418296341Sdelphij    unsigned char iv[sizeof(test_iv)];
419296341Sdelphij    unsigned char cleartext[64], ciphertext[64];
420296341Sdelphij    size_t tail;
421238384Sjkim
422296341Sdelphij    printf("vector_%d\n", len);
423296341Sdelphij    fflush(stdout);
424238384Sjkim
425296341Sdelphij    if ((tail = len % 16) == 0)
426296341Sdelphij        tail = 16;
427296341Sdelphij    tail += 16;
428238384Sjkim
429296341Sdelphij    /* test block-based encryption */
430296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
431296341Sdelphij    CRYPTO_cts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
432296341Sdelphij                                (block128_f) AES_encrypt);
433296341Sdelphij    if (memcmp(ciphertext, vector, len))
434296341Sdelphij        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
435296341Sdelphij    if (memcmp(iv, vector + len - tail, sizeof(iv)))
436296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
437238384Sjkim
438296341Sdelphij    /* test block-based decryption */
439296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
440296341Sdelphij    CRYPTO_cts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
441296341Sdelphij                                (block128_f) AES_decrypt);
442296341Sdelphij    if (memcmp(cleartext, test_input, len))
443296341Sdelphij        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
444296341Sdelphij    if (memcmp(iv, vector + len - tail, sizeof(iv)))
445296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
446238384Sjkim
447296341Sdelphij    /* test streamed encryption */
448296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
449296341Sdelphij    CRYPTO_cts128_encrypt(test_input, ciphertext, len, &encks, iv,
450296341Sdelphij                          (cbc128_f) AES_cbc_encrypt);
451296341Sdelphij    if (memcmp(ciphertext, vector, len))
452296341Sdelphij        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
453296341Sdelphij    if (memcmp(iv, vector + len - tail, sizeof(iv)))
454296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
455238384Sjkim
456296341Sdelphij    /* test streamed decryption */
457296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
458296341Sdelphij    CRYPTO_cts128_decrypt(ciphertext, cleartext, len, &decks, iv,
459296341Sdelphij                          (cbc128_f) AES_cbc_encrypt);
460296341Sdelphij    if (memcmp(cleartext, test_input, len))
461296341Sdelphij        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
462296341Sdelphij    if (memcmp(iv, vector + len - tail, sizeof(iv)))
463296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
464238384Sjkim}
465238384Sjkim
466296341Sdelphijvoid test_nistvector(const unsigned char *vector, size_t len)
467296341Sdelphij{
468296341Sdelphij    unsigned char iv[sizeof(test_iv)];
469296341Sdelphij    unsigned char cleartext[64], ciphertext[64], nistvector[64];
470296341Sdelphij    size_t tail;
471238384Sjkim
472296341Sdelphij    printf("nistvector_%d\n", len);
473296341Sdelphij    fflush(stdout);
474238384Sjkim
475296341Sdelphij    if ((tail = len % 16) == 0)
476296341Sdelphij        tail = 16;
477238384Sjkim
478296341Sdelphij    len -= 16 + tail;
479296341Sdelphij    memcpy(nistvector, vector, len);
480296341Sdelphij    /* flip two last blocks */
481296341Sdelphij    memcpy(nistvector + len, vector + len + 16, tail);
482296341Sdelphij    memcpy(nistvector + len + tail, vector + len, 16);
483296341Sdelphij    len += 16 + tail;
484296341Sdelphij    tail = 16;
485238384Sjkim
486296341Sdelphij    /* test block-based encryption */
487296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
488296341Sdelphij    CRYPTO_nistcts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
489296341Sdelphij                                    (block128_f) AES_encrypt);
490296341Sdelphij    if (memcmp(ciphertext, nistvector, len))
491296341Sdelphij        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
492296341Sdelphij    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
493296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
494238384Sjkim
495296341Sdelphij    /* test block-based decryption */
496296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
497296341Sdelphij    CRYPTO_nistcts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
498296341Sdelphij                                    (block128_f) AES_decrypt);
499296341Sdelphij    if (memcmp(cleartext, test_input, len))
500296341Sdelphij        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
501296341Sdelphij    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
502296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
503238384Sjkim
504296341Sdelphij    /* test streamed encryption */
505296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
506296341Sdelphij    CRYPTO_nistcts128_encrypt(test_input, ciphertext, len, &encks, iv,
507296341Sdelphij                              (cbc128_f) AES_cbc_encrypt);
508296341Sdelphij    if (memcmp(ciphertext, nistvector, len))
509296341Sdelphij        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
510296341Sdelphij    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
511296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
512238384Sjkim
513296341Sdelphij    /* test streamed decryption */
514296341Sdelphij    memcpy(iv, test_iv, sizeof(test_iv));
515296341Sdelphij    CRYPTO_nistcts128_decrypt(ciphertext, cleartext, len, &decks, iv,
516296341Sdelphij                              (cbc128_f) AES_cbc_encrypt);
517296341Sdelphij    if (memcmp(cleartext, test_input, len))
518296341Sdelphij        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
519296341Sdelphij    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
520296341Sdelphij        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
521238384Sjkim}
522238384Sjkim
523238384Sjkimint main()
524238384Sjkim{
525296341Sdelphij    AES_set_encrypt_key(test_key, 128, &encks);
526296341Sdelphij    AES_set_decrypt_key(test_key, 128, &decks);
527238384Sjkim
528296341Sdelphij    test_vector(vector_17, sizeof(vector_17));
529296341Sdelphij    test_vector(vector_31, sizeof(vector_31));
530296341Sdelphij    test_vector(vector_32, sizeof(vector_32));
531296341Sdelphij    test_vector(vector_47, sizeof(vector_47));
532296341Sdelphij    test_vector(vector_48, sizeof(vector_48));
533296341Sdelphij    test_vector(vector_64, sizeof(vector_64));
534238384Sjkim
535296341Sdelphij    test_nistvector(vector_17, sizeof(vector_17));
536296341Sdelphij    test_nistvector(vector_31, sizeof(vector_31));
537296341Sdelphij    test_nistvector(vector_32, sizeof(vector_32));
538296341Sdelphij    test_nistvector(vector_47, sizeof(vector_47));
539296341Sdelphij    test_nistvector(vector_48, sizeof(vector_48));
540296341Sdelphij    test_nistvector(vector_64, sizeof(vector_64));
541238384Sjkim
542296341Sdelphij    return 0;
543238384Sjkim}
544238384Sjkim#endif
545