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
32280304Sjkimsize_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
33280304Sjkim                                   unsigned char *out, size_t len,
34280304Sjkim                                   const void *key, unsigned char ivec[16],
35280304Sjkim                                   block128_f block)
36280304Sjkim{
37280304Sjkim    size_t residue, n;
38238384Sjkim
39280304Sjkim    assert(in && out && key && ivec);
40238384Sjkim
41280304Sjkim    if (len <= 16)
42280304Sjkim        return 0;
43238384Sjkim
44280304Sjkim    if ((residue = len % 16) == 0)
45280304Sjkim        residue = 16;
46238384Sjkim
47280304Sjkim    len -= residue;
48238384Sjkim
49280304Sjkim    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
50238384Sjkim
51280304Sjkim    in += len;
52280304Sjkim    out += len;
53238384Sjkim
54280304Sjkim    for (n = 0; n < residue; ++n)
55280304Sjkim        ivec[n] ^= in[n];
56280304Sjkim    (*block) (ivec, ivec, key);
57280304Sjkim    memcpy(out, out - 16, residue);
58280304Sjkim    memcpy(out - 16, ivec, 16);
59238384Sjkim
60280304Sjkim    return len + residue;
61238384Sjkim}
62238384Sjkim
63280304Sjkimsize_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in,
64280304Sjkim                                       unsigned char *out, size_t len,
65280304Sjkim                                       const void *key,
66280304Sjkim                                       unsigned char ivec[16],
67280304Sjkim                                       block128_f block)
68280304Sjkim{
69280304Sjkim    size_t residue, n;
70238384Sjkim
71280304Sjkim    assert(in && out && key && ivec);
72238384Sjkim
73280304Sjkim    if (len < 16)
74280304Sjkim        return 0;
75238384Sjkim
76280304Sjkim    residue = len % 16;
77238384Sjkim
78280304Sjkim    len -= residue;
79238384Sjkim
80280304Sjkim    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
81238384Sjkim
82280304Sjkim    if (residue == 0)
83280304Sjkim        return len;
84238384Sjkim
85280304Sjkim    in += len;
86280304Sjkim    out += len;
87238384Sjkim
88280304Sjkim    for (n = 0; n < residue; ++n)
89280304Sjkim        ivec[n] ^= in[n];
90280304Sjkim    (*block) (ivec, ivec, key);
91280304Sjkim    memcpy(out - 16 + residue, ivec, 16);
92238384Sjkim
93280304Sjkim    return len + residue;
94238384Sjkim}
95238384Sjkim
96238384Sjkimsize_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
97280304Sjkim                             size_t len, const void *key,
98280304Sjkim                             unsigned char ivec[16], cbc128_f cbc)
99280304Sjkim{
100280304Sjkim    size_t residue;
101280304Sjkim    union {
102280304Sjkim        size_t align;
103280304Sjkim        unsigned char c[16];
104280304Sjkim    } tmp;
105238384Sjkim
106280304Sjkim    assert(in && out && key && ivec);
107238384Sjkim
108280304Sjkim    if (len <= 16)
109280304Sjkim        return 0;
110238384Sjkim
111280304Sjkim    if ((residue = len % 16) == 0)
112280304Sjkim        residue = 16;
113238384Sjkim
114280304Sjkim    len -= residue;
115238384Sjkim
116280304Sjkim    (*cbc) (in, out, len, key, ivec, 1);
117238384Sjkim
118280304Sjkim    in += len;
119280304Sjkim    out += len;
120238384Sjkim
121238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
122280304Sjkim    memcpy(tmp.c, out - 16, 16);
123280304Sjkim    (*cbc) (in, out - 16, residue, key, ivec, 1);
124280304Sjkim    memcpy(out, tmp.c, residue);
125238384Sjkim#else
126280304Sjkim    memset(tmp.c, 0, sizeof(tmp));
127280304Sjkim    memcpy(tmp.c, in, residue);
128280304Sjkim    memcpy(out, out - 16, residue);
129280304Sjkim    (*cbc) (tmp.c, out - 16, 16, key, ivec, 1);
130238384Sjkim#endif
131280304Sjkim    return len + residue;
132238384Sjkim}
133238384Sjkim
134238384Sjkimsize_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
135280304Sjkim                                 size_t len, const void *key,
136280304Sjkim                                 unsigned char ivec[16], cbc128_f cbc)
137280304Sjkim{
138280304Sjkim    size_t residue;
139280304Sjkim    union {
140280304Sjkim        size_t align;
141280304Sjkim        unsigned char c[16];
142280304Sjkim    } tmp;
143238384Sjkim
144280304Sjkim    assert(in && out && key && ivec);
145238384Sjkim
146280304Sjkim    if (len < 16)
147280304Sjkim        return 0;
148238384Sjkim
149280304Sjkim    residue = len % 16;
150238384Sjkim
151280304Sjkim    len -= residue;
152238384Sjkim
153280304Sjkim    (*cbc) (in, out, len, key, ivec, 1);
154238384Sjkim
155280304Sjkim    if (residue == 0)
156280304Sjkim        return len;
157238384Sjkim
158280304Sjkim    in += len;
159280304Sjkim    out += len;
160238384Sjkim
161238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
162280304Sjkim    (*cbc) (in, out - 16 + residue, residue, key, ivec, 1);
163238384Sjkim#else
164280304Sjkim    memset(tmp.c, 0, sizeof(tmp));
165280304Sjkim    memcpy(tmp.c, in, residue);
166280304Sjkim    (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1);
167238384Sjkim#endif
168280304Sjkim    return len + residue;
169238384Sjkim}
170238384Sjkim
171280304Sjkimsize_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
172280304Sjkim                                   unsigned char *out, size_t len,
173280304Sjkim                                   const void *key, unsigned char ivec[16],
174280304Sjkim                                   block128_f block)
175280304Sjkim{
176280304Sjkim    size_t residue, n;
177280304Sjkim    union {
178280304Sjkim        size_t align;
179280304Sjkim        unsigned char c[32];
180280304Sjkim    } tmp;
181238384Sjkim
182280304Sjkim    assert(in && out && key && ivec);
183238384Sjkim
184280304Sjkim    if (len <= 16)
185280304Sjkim        return 0;
186238384Sjkim
187280304Sjkim    if ((residue = len % 16) == 0)
188280304Sjkim        residue = 16;
189238384Sjkim
190280304Sjkim    len -= 16 + residue;
191238384Sjkim
192280304Sjkim    if (len) {
193280304Sjkim        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
194280304Sjkim        in += len;
195280304Sjkim        out += len;
196280304Sjkim    }
197238384Sjkim
198280304Sjkim    (*block) (in, tmp.c + 16, key);
199238384Sjkim
200280304Sjkim    memcpy(tmp.c, tmp.c + 16, 16);
201280304Sjkim    memcpy(tmp.c, in + 16, residue);
202280304Sjkim    (*block) (tmp.c, tmp.c, key);
203238384Sjkim
204280304Sjkim    for (n = 0; n < 16; ++n) {
205280304Sjkim        unsigned char c = in[n];
206280304Sjkim        out[n] = tmp.c[n] ^ ivec[n];
207280304Sjkim        ivec[n] = c;
208280304Sjkim    }
209280304Sjkim    for (residue += 16; n < residue; ++n)
210280304Sjkim        out[n] = tmp.c[n] ^ in[n];
211238384Sjkim
212280304Sjkim    return 16 + len + residue;
213238384Sjkim}
214238384Sjkim
215280304Sjkimsize_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in,
216280304Sjkim                                       unsigned char *out, size_t len,
217280304Sjkim                                       const void *key,
218280304Sjkim                                       unsigned char ivec[16],
219280304Sjkim                                       block128_f block)
220280304Sjkim{
221280304Sjkim    size_t residue, n;
222280304Sjkim    union {
223280304Sjkim        size_t align;
224280304Sjkim        unsigned char c[32];
225280304Sjkim    } tmp;
226238384Sjkim
227280304Sjkim    assert(in && out && key && ivec);
228238384Sjkim
229280304Sjkim    if (len < 16)
230280304Sjkim        return 0;
231238384Sjkim
232280304Sjkim    residue = len % 16;
233238384Sjkim
234280304Sjkim    if (residue == 0) {
235280304Sjkim        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
236280304Sjkim        return len;
237280304Sjkim    }
238238384Sjkim
239280304Sjkim    len -= 16 + residue;
240238384Sjkim
241280304Sjkim    if (len) {
242280304Sjkim        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
243280304Sjkim        in += len;
244280304Sjkim        out += len;
245280304Sjkim    }
246238384Sjkim
247280304Sjkim    (*block) (in + residue, tmp.c + 16, key);
248238384Sjkim
249280304Sjkim    memcpy(tmp.c, tmp.c + 16, 16);
250280304Sjkim    memcpy(tmp.c, in, residue);
251280304Sjkim    (*block) (tmp.c, tmp.c, key);
252238384Sjkim
253280304Sjkim    for (n = 0; n < 16; ++n) {
254280304Sjkim        unsigned char c = in[n];
255280304Sjkim        out[n] = tmp.c[n] ^ ivec[n];
256280304Sjkim        ivec[n] = in[n + residue];
257280304Sjkim        tmp.c[n] = c;
258280304Sjkim    }
259280304Sjkim    for (residue += 16; n < residue; ++n)
260280304Sjkim        out[n] = tmp.c[n] ^ tmp.c[n - 16];
261238384Sjkim
262280304Sjkim    return 16 + len + residue;
263238384Sjkim}
264238384Sjkim
265238384Sjkimsize_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
266280304Sjkim                             size_t len, const void *key,
267280304Sjkim                             unsigned char ivec[16], cbc128_f cbc)
268280304Sjkim{
269280304Sjkim    size_t residue;
270280304Sjkim    union {
271280304Sjkim        size_t align;
272280304Sjkim        unsigned char c[32];
273280304Sjkim    } tmp;
274238384Sjkim
275280304Sjkim    assert(in && out && key && ivec);
276238384Sjkim
277280304Sjkim    if (len <= 16)
278280304Sjkim        return 0;
279238384Sjkim
280280304Sjkim    if ((residue = len % 16) == 0)
281280304Sjkim        residue = 16;
282238384Sjkim
283280304Sjkim    len -= 16 + residue;
284238384Sjkim
285280304Sjkim    if (len) {
286280304Sjkim        (*cbc) (in, out, len, key, ivec, 0);
287280304Sjkim        in += len;
288280304Sjkim        out += len;
289280304Sjkim    }
290238384Sjkim
291280304Sjkim    memset(tmp.c, 0, sizeof(tmp));
292280304Sjkim    /*
293280304Sjkim     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
294280304Sjkim     */
295280304Sjkim    (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0);
296238384Sjkim
297280304Sjkim    memcpy(tmp.c, in + 16, residue);
298238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
299280304Sjkim    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
300238384Sjkim#else
301280304Sjkim    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
302280304Sjkim    memcpy(out, tmp.c, 16 + residue);
303238384Sjkim#endif
304280304Sjkim    return 16 + len + residue;
305238384Sjkim}
306238384Sjkim
307238384Sjkimsize_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
308280304Sjkim                                 size_t len, const void *key,
309280304Sjkim                                 unsigned char ivec[16], cbc128_f cbc)
310280304Sjkim{
311280304Sjkim    size_t residue;
312280304Sjkim    union {
313280304Sjkim        size_t align;
314280304Sjkim        unsigned char c[32];
315280304Sjkim    } tmp;
316238384Sjkim
317280304Sjkim    assert(in && out && key && ivec);
318238384Sjkim
319280304Sjkim    if (len < 16)
320280304Sjkim        return 0;
321238384Sjkim
322280304Sjkim    residue = len % 16;
323238384Sjkim
324280304Sjkim    if (residue == 0) {
325280304Sjkim        (*cbc) (in, out, len, key, ivec, 0);
326280304Sjkim        return len;
327280304Sjkim    }
328238384Sjkim
329280304Sjkim    len -= 16 + residue;
330238384Sjkim
331280304Sjkim    if (len) {
332280304Sjkim        (*cbc) (in, out, len, key, ivec, 0);
333280304Sjkim        in += len;
334280304Sjkim        out += len;
335280304Sjkim    }
336238384Sjkim
337280304Sjkim    memset(tmp.c, 0, sizeof(tmp));
338280304Sjkim    /*
339280304Sjkim     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
340280304Sjkim     */
341280304Sjkim    (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0);
342238384Sjkim
343280304Sjkim    memcpy(tmp.c, in, residue);
344238384Sjkim#if defined(CBC_HANDLES_TRUNCATED_IO)
345280304Sjkim    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
346238384Sjkim#else
347280304Sjkim    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
348280304Sjkim    memcpy(out, tmp.c, 16 + residue);
349238384Sjkim#endif
350280304Sjkim    return 16 + len + residue;
351238384Sjkim}
352238384Sjkim
353238384Sjkim#if defined(SELFTEST)
354280304Sjkim# include <stdio.h>
355280304Sjkim# 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] =
360280304Sjkim    "I would like the" " General Gau's C"
361280304Sjkim    "hicken, please, " "and wonton soup.";
362280304Sjkimstatic const unsigned char test_iv[16] =
363280304Sjkim    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
364238384Sjkim
365280304Sjkimstatic const unsigned char vector_17[17] = {
366280304Sjkim    0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
367280304Sjkim    0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
368280304Sjkim    0x97
369280304Sjkim};
370238384Sjkim
371280304Sjkimstatic const unsigned char vector_31[31] = {
372280304Sjkim    0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
373280304Sjkim    0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
374280304Sjkim    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
375280304Sjkim    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5
376280304Sjkim};
377280304Sjkim
378280304Sjkimstatic const unsigned char vector_32[32] = {
379280304Sjkim    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
380280304Sjkim    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
381280304Sjkim    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
382280304Sjkim    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84
383280304Sjkim};
384280304Sjkim
385280304Sjkimstatic const unsigned char vector_47[47] = {
386280304Sjkim    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
387280304Sjkim    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
388280304Sjkim    0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
389280304Sjkim    0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
390280304Sjkim    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
391280304Sjkim    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5
392280304Sjkim};
393280304Sjkim
394280304Sjkimstatic const unsigned char vector_48[48] = {
395280304Sjkim    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
396280304Sjkim    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
397280304Sjkim    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
398280304Sjkim    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
399280304Sjkim    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
400280304Sjkim    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
401280304Sjkim};
402280304Sjkim
403280304Sjkimstatic const unsigned char vector_64[64] = {
404280304Sjkim    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
405280304Sjkim    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
406280304Sjkim    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
407280304Sjkim    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
408280304Sjkim    0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
409280304Sjkim    0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
410280304Sjkim    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
411280304Sjkim    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
412280304Sjkim};
413280304Sjkim
414238384Sjkimstatic AES_KEY encks, decks;
415238384Sjkim
416280304Sjkimvoid test_vector(const unsigned char *vector, size_t len)
417280304Sjkim{
418280304Sjkim    unsigned char iv[sizeof(test_iv)];
419280304Sjkim    unsigned char cleartext[64], ciphertext[64];
420280304Sjkim    size_t tail;
421238384Sjkim
422280304Sjkim    printf("vector_%d\n", len);
423280304Sjkim    fflush(stdout);
424238384Sjkim
425280304Sjkim    if ((tail = len % 16) == 0)
426280304Sjkim        tail = 16;
427280304Sjkim    tail += 16;
428238384Sjkim
429280304Sjkim    /* test block-based encryption */
430280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
431280304Sjkim    CRYPTO_cts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
432280304Sjkim                                (block128_f) AES_encrypt);
433280304Sjkim    if (memcmp(ciphertext, vector, len))
434280304Sjkim        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
435280304Sjkim    if (memcmp(iv, vector + len - tail, sizeof(iv)))
436280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
437238384Sjkim
438280304Sjkim    /* test block-based decryption */
439280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
440280304Sjkim    CRYPTO_cts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
441280304Sjkim                                (block128_f) AES_decrypt);
442280304Sjkim    if (memcmp(cleartext, test_input, len))
443280304Sjkim        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
444280304Sjkim    if (memcmp(iv, vector + len - tail, sizeof(iv)))
445280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
446238384Sjkim
447280304Sjkim    /* test streamed encryption */
448280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
449280304Sjkim    CRYPTO_cts128_encrypt(test_input, ciphertext, len, &encks, iv,
450280304Sjkim                          (cbc128_f) AES_cbc_encrypt);
451280304Sjkim    if (memcmp(ciphertext, vector, len))
452280304Sjkim        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
453280304Sjkim    if (memcmp(iv, vector + len - tail, sizeof(iv)))
454280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
455238384Sjkim
456280304Sjkim    /* test streamed decryption */
457280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
458280304Sjkim    CRYPTO_cts128_decrypt(ciphertext, cleartext, len, &decks, iv,
459280304Sjkim                          (cbc128_f) AES_cbc_encrypt);
460280304Sjkim    if (memcmp(cleartext, test_input, len))
461280304Sjkim        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
462280304Sjkim    if (memcmp(iv, vector + len - tail, sizeof(iv)))
463280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
464238384Sjkim}
465238384Sjkim
466280304Sjkimvoid test_nistvector(const unsigned char *vector, size_t len)
467280304Sjkim{
468280304Sjkim    unsigned char iv[sizeof(test_iv)];
469280304Sjkim    unsigned char cleartext[64], ciphertext[64], nistvector[64];
470280304Sjkim    size_t tail;
471238384Sjkim
472280304Sjkim    printf("nistvector_%d\n", len);
473280304Sjkim    fflush(stdout);
474238384Sjkim
475280304Sjkim    if ((tail = len % 16) == 0)
476280304Sjkim        tail = 16;
477238384Sjkim
478280304Sjkim    len -= 16 + tail;
479280304Sjkim    memcpy(nistvector, vector, len);
480280304Sjkim    /* flip two last blocks */
481280304Sjkim    memcpy(nistvector + len, vector + len + 16, tail);
482280304Sjkim    memcpy(nistvector + len + tail, vector + len, 16);
483280304Sjkim    len += 16 + tail;
484280304Sjkim    tail = 16;
485238384Sjkim
486280304Sjkim    /* test block-based encryption */
487280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
488280304Sjkim    CRYPTO_nistcts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
489280304Sjkim                                    (block128_f) AES_encrypt);
490280304Sjkim    if (memcmp(ciphertext, nistvector, len))
491280304Sjkim        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
492280304Sjkim    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
493280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
494238384Sjkim
495280304Sjkim    /* test block-based decryption */
496280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
497280304Sjkim    CRYPTO_nistcts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
498280304Sjkim                                    (block128_f) AES_decrypt);
499280304Sjkim    if (memcmp(cleartext, test_input, len))
500280304Sjkim        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
501280304Sjkim    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
502280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
503238384Sjkim
504280304Sjkim    /* test streamed encryption */
505280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
506280304Sjkim    CRYPTO_nistcts128_encrypt(test_input, ciphertext, len, &encks, iv,
507280304Sjkim                              (cbc128_f) AES_cbc_encrypt);
508280304Sjkim    if (memcmp(ciphertext, nistvector, len))
509280304Sjkim        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
510280304Sjkim    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
511280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
512238384Sjkim
513280304Sjkim    /* test streamed decryption */
514280304Sjkim    memcpy(iv, test_iv, sizeof(test_iv));
515280304Sjkim    CRYPTO_nistcts128_decrypt(ciphertext, cleartext, len, &decks, iv,
516280304Sjkim                              (cbc128_f) AES_cbc_encrypt);
517280304Sjkim    if (memcmp(cleartext, test_input, len))
518280304Sjkim        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
519280304Sjkim    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
520280304Sjkim        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
521238384Sjkim}
522238384Sjkim
523238384Sjkimint main()
524238384Sjkim{
525280304Sjkim    AES_set_encrypt_key(test_key, 128, &encks);
526280304Sjkim    AES_set_decrypt_key(test_key, 128, &decks);
527238384Sjkim
528280304Sjkim    test_vector(vector_17, sizeof(vector_17));
529280304Sjkim    test_vector(vector_31, sizeof(vector_31));
530280304Sjkim    test_vector(vector_32, sizeof(vector_32));
531280304Sjkim    test_vector(vector_47, sizeof(vector_47));
532280304Sjkim    test_vector(vector_48, sizeof(vector_48));
533280304Sjkim    test_vector(vector_64, sizeof(vector_64));
534238384Sjkim
535280304Sjkim    test_nistvector(vector_17, sizeof(vector_17));
536280304Sjkim    test_nistvector(vector_31, sizeof(vector_31));
537280304Sjkim    test_nistvector(vector_32, sizeof(vector_32));
538280304Sjkim    test_nistvector(vector_47, sizeof(vector_47));
539280304Sjkim    test_nistvector(vector_48, sizeof(vector_48));
540280304Sjkim    test_nistvector(vector_64, sizeof(vector_64));
541238384Sjkim
542280304Sjkim    return 0;
543238384Sjkim}
544238384Sjkim#endif
545