diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/libcrypto/modes/ctr128.c | 92 |
1 files changed, 80 insertions, 12 deletions
diff --git a/src/lib/libcrypto/modes/ctr128.c b/src/lib/libcrypto/modes/ctr128.c index 932037f551..ee642c5863 100644 --- a/src/lib/libcrypto/modes/ctr128.c +++ b/src/lib/libcrypto/modes/ctr128.c | |||
@@ -48,7 +48,8 @@ | |||
48 | * | 48 | * |
49 | */ | 49 | */ |
50 | 50 | ||
51 | #include "modes.h" | 51 | #include <openssl/crypto.h> |
52 | #include "modes_lcl.h" | ||
52 | #include <string.h> | 53 | #include <string.h> |
53 | 54 | ||
54 | #ifndef MODES_DEBUG | 55 | #ifndef MODES_DEBUG |
@@ -58,17 +59,6 @@ | |||
58 | #endif | 59 | #endif |
59 | #include <assert.h> | 60 | #include <assert.h> |
60 | 61 | ||
61 | typedef unsigned int u32; | ||
62 | typedef unsigned char u8; | ||
63 | |||
64 | #define STRICT_ALIGNMENT | ||
65 | #if defined(__i386) || defined(__i386__) || \ | ||
66 | defined(__x86_64) || defined(__x86_64__) || \ | ||
67 | defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64) || \ | ||
68 | defined(__s390__) || defined(__s390x__) | ||
69 | # undef STRICT_ALIGNMENT | ||
70 | #endif | ||
71 | |||
72 | /* NOTE: the IV/counter CTR mode is big-endian. The code itself | 62 | /* NOTE: the IV/counter CTR mode is big-endian. The code itself |
73 | * is endian-neutral. */ | 63 | * is endian-neutral. */ |
74 | 64 | ||
@@ -182,3 +172,81 @@ void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out, | |||
182 | 172 | ||
183 | *num=n; | 173 | *num=n; |
184 | } | 174 | } |
175 | |||
176 | /* increment upper 96 bits of 128-bit counter by 1 */ | ||
177 | static void ctr96_inc(unsigned char *counter) { | ||
178 | u32 n=12; | ||
179 | u8 c; | ||
180 | |||
181 | do { | ||
182 | --n; | ||
183 | c = counter[n]; | ||
184 | ++c; | ||
185 | counter[n] = c; | ||
186 | if (c) return; | ||
187 | } while (n); | ||
188 | } | ||
189 | |||
190 | void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out, | ||
191 | size_t len, const void *key, | ||
192 | unsigned char ivec[16], unsigned char ecount_buf[16], | ||
193 | unsigned int *num, ctr128_f func) | ||
194 | { | ||
195 | unsigned int n,ctr32; | ||
196 | |||
197 | assert(in && out && key && ecount_buf && num); | ||
198 | assert(*num < 16); | ||
199 | |||
200 | n = *num; | ||
201 | |||
202 | while (n && len) { | ||
203 | *(out++) = *(in++) ^ ecount_buf[n]; | ||
204 | --len; | ||
205 | n = (n+1) % 16; | ||
206 | } | ||
207 | |||
208 | ctr32 = GETU32(ivec+12); | ||
209 | while (len>=16) { | ||
210 | size_t blocks = len/16; | ||
211 | /* | ||
212 | * 1<<28 is just a not-so-small yet not-so-large number... | ||
213 | * Below condition is practically never met, but it has to | ||
214 | * be checked for code correctness. | ||
215 | */ | ||
216 | if (sizeof(size_t)>sizeof(unsigned int) && blocks>(1U<<28)) | ||
217 | blocks = (1U<<28); | ||
218 | /* | ||
219 | * As (*func) operates on 32-bit counter, caller | ||
220 | * has to handle overflow. 'if' below detects the | ||
221 | * overflow, which is then handled by limiting the | ||
222 | * amount of blocks to the exact overflow point... | ||
223 | */ | ||
224 | ctr32 += (u32)blocks; | ||
225 | if (ctr32 < blocks) { | ||
226 | blocks -= ctr32; | ||
227 | ctr32 = 0; | ||
228 | } | ||
229 | (*func)(in,out,blocks,key,ivec); | ||
230 | /* (*ctr) does not update ivec, caller does: */ | ||
231 | PUTU32(ivec+12,ctr32); | ||
232 | /* ... overflow was detected, propogate carry. */ | ||
233 | if (ctr32 == 0) ctr96_inc(ivec); | ||
234 | blocks *= 16; | ||
235 | len -= blocks; | ||
236 | out += blocks; | ||
237 | in += blocks; | ||
238 | } | ||
239 | if (len) { | ||
240 | memset(ecount_buf,0,16); | ||
241 | (*func)(ecount_buf,ecount_buf,1,key,ivec); | ||
242 | ++ctr32; | ||
243 | PUTU32(ivec+12,ctr32); | ||
244 | if (ctr32 == 0) ctr96_inc(ivec); | ||
245 | while (len--) { | ||
246 | out[n] = in[n] ^ ecount_buf[n]; | ||
247 | ++n; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | *num=n; | ||
252 | } | ||