f81f74adf0c49dcdf7670a8f7f063a3df2413425
[platform/upstream/nettle.git] / ctr.c
1 /* ctr.c
2
3    Cipher counter mode.
4
5    Copyright (C) 2005 Niels Möller
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 "ctr.h"
43
44 #include "macros.h"
45 #include "memxor.h"
46 #include "nettle-internal.h"
47
48 #define NBLOCKS 4
49
50 void
51 ctr_crypt(const void *ctx, nettle_cipher_func *f,
52           size_t block_size, uint8_t *ctr,
53           size_t length, uint8_t *dst,
54           const uint8_t *src)
55 {
56   if (src != dst)
57     {
58       if (length == block_size)
59         {
60           f(ctx, block_size, dst, ctr);
61           INCREMENT(block_size, ctr);
62           memxor(dst, src, block_size);
63         }
64       else
65         {
66           size_t left;
67           uint8_t *p;     
68
69           for (p = dst, left = length;
70                left >= block_size;
71                left -= block_size, p += block_size)
72             {
73               memcpy (p, ctr, block_size);
74               INCREMENT(block_size, ctr);
75             }
76
77           f(ctx, length - left, dst, dst);
78           memxor(dst, src, length - left);
79
80           if (left)
81             {
82               TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE);
83               TMP_ALLOC(buffer, block_size);
84
85               f(ctx, block_size, buffer, ctr);
86               INCREMENT(block_size, ctr);
87               memxor3(dst + length - left, src + length - left, buffer, left);
88             }
89         }
90     }
91   else
92     {
93       if (length > block_size)
94         {
95           TMP_DECL(buffer, uint8_t, NBLOCKS * NETTLE_MAX_CIPHER_BLOCK_SIZE);
96           size_t chunk = NBLOCKS * block_size;
97
98           TMP_ALLOC(buffer, chunk);
99
100           for (; length >= chunk;
101                length -= chunk, src += chunk, dst += chunk)
102             {
103               unsigned n;
104               uint8_t *p;         
105               for (n = 0, p = buffer; n < NBLOCKS; n++, p += block_size)
106                 {
107                   memcpy (p, ctr, block_size);
108                   INCREMENT(block_size, ctr);
109                 }
110               f(ctx, chunk, buffer, buffer);
111               memxor(dst, buffer, chunk);
112             }
113
114           if (length > 0)
115             {
116               /* Final, possibly partial, blocks */
117               for (chunk = 0; chunk < length; chunk += block_size)
118                 {
119                   memcpy (buffer + chunk, ctr, block_size);
120                   INCREMENT(block_size, ctr);
121                 }
122               f(ctx, chunk, buffer, buffer);
123               memxor3(dst, src, buffer, length);
124             }
125         }
126       else if (length > 0)
127         {
128           TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE);
129           TMP_ALLOC(buffer, block_size);
130
131           f(ctx, block_size, buffer, ctr);
132           INCREMENT(block_size, ctr);
133           memxor3(dst, src, buffer, length);
134         }
135     }
136 }