| 
									
										
										
										
											2016-05-18 02:51:04 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2021-04-08 20:04:41 +08:00
										 |  |  |  * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-12-06 20:46:12 +08:00
										 |  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
					
						
							| 
									
										
										
										
											2016-05-18 02:51:04 +08:00
										 |  |  |  * this file except in compliance with the License.  You can obtain a copy | 
					
						
							|  |  |  |  * in the file LICENSE in the source distribution or at | 
					
						
							|  |  |  |  * https://www.openssl.org/source/license.html
 | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2019-07-16 07:46:14 +08:00
										 |  |  | #include <openssl/crypto.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-09 14:37:46 +08:00
										 |  |  | #include "internal/endian.h"
 | 
					
						
							| 
									
										
										
										
											2019-09-28 06:45:33 +08:00
										 |  |  | #include "crypto/modes.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-25 03:10:13 +08:00
										 |  |  | #if defined(__GNUC__) && !defined(STRICT_ALIGNMENT)
 | 
					
						
							|  |  |  | typedef size_t size_t_aX __attribute((__aligned__(1))); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | typedef size_t size_t_aX; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * NOTE: the IV/counter CTR mode is big-endian.  The code itself is | 
					
						
							|  |  |  |  * endian-neutral. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* increment counter (128-bit int) by 1 */ | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | static void ctr128_inc(unsigned char *counter) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |     u32 n = 16, c = 1; | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     do { | 
					
						
							|  |  |  |         --n; | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |         c += counter[n]; | 
					
						
							|  |  |  |         counter[n] = (u8)c; | 
					
						
							|  |  |  |         c >>= 8; | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     } while (n); | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-10 21:46:53 +08:00
										 |  |  | #if !defined(OPENSSL_SMALL_FOOTPRINT)
 | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | static void ctr128_inc_aligned(unsigned char *counter) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |     size_t *data, c, d, n; | 
					
						
							| 
									
										
										
										
											2020-07-09 14:37:46 +08:00
										 |  |  |     DECLARE_IS_ENDIAN; | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 14:37:46 +08:00
										 |  |  |     if (IS_LITTLE_ENDIAN || ((size_t)counter % sizeof(size_t)) != 0) { | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |         ctr128_inc(counter); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data = (size_t *)counter; | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |     c = 1; | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     n = 16 / sizeof(size_t); | 
					
						
							|  |  |  |     do { | 
					
						
							|  |  |  |         --n; | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |         d = data[n] += c; | 
					
						
							|  |  |  |         /* did addition carry? */ | 
					
						
							| 
									
										
										
										
											2016-11-21 06:38:12 +08:00
										 |  |  |         c = ((d - c) & ~d) >> (sizeof(size_t) * 8 - 1); | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     } while (n); | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * The input encrypted as though 128bit counter mode is being used.  The | 
					
						
							|  |  |  |  * extra state information to record how much of the 128bit block we have | 
					
						
							|  |  |  |  * used is contained in *num, and the encrypted counter is kept in | 
					
						
							|  |  |  |  * ecount_buf.  Both *num and ecount_buf must be initialised with zeros | 
					
						
							|  |  |  |  * before the first call to CRYPTO_ctr128_encrypt(). This algorithm assumes | 
					
						
							|  |  |  |  * that the counter is in the x lower bits of the IV (ivec), and that the | 
					
						
							|  |  |  |  * application has full control over overflow and the rest of the IV.  This | 
					
						
							| 
									
										
										
										
											2016-02-06 04:23:54 +08:00
										 |  |  |  * implementation takes NO responsibility for checking that the counter | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |  * doesn't overflow into the rest of the IV when incremented. | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out, | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |                            size_t len, const void *key, | 
					
						
							|  |  |  |                            unsigned char ivec[16], | 
					
						
							|  |  |  |                            unsigned char ecount_buf[16], unsigned int *num, | 
					
						
							|  |  |  |                            block128_f block) | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     unsigned int n; | 
					
						
							|  |  |  |     size_t l = 0; | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     n = *num; | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if !defined(OPENSSL_SMALL_FOOTPRINT)
 | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     if (16 % sizeof(size_t) == 0) { /* always true actually */ | 
					
						
							|  |  |  |         do { | 
					
						
							|  |  |  |             while (n && len) { | 
					
						
							|  |  |  |                 *(out++) = *(in++) ^ ecount_buf[n]; | 
					
						
							|  |  |  |                 --len; | 
					
						
							|  |  |  |                 n = (n + 1) % 16; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # if defined(STRICT_ALIGNMENT)
 | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |             if (((size_t)in | (size_t)out | (size_t)ecount_buf) | 
					
						
							|  |  |  |                 % sizeof(size_t) != 0) | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |                 break; | 
					
						
							|  |  |  | # endif
 | 
					
						
							|  |  |  |             while (len >= 16) { | 
					
						
							|  |  |  |                 (*block) (ivec, ecount_buf, key); | 
					
						
							|  |  |  |                 ctr128_inc_aligned(ivec); | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |                 for (n = 0; n < 16; n += sizeof(size_t)) | 
					
						
							| 
									
										
										
										
											2018-04-25 03:10:13 +08:00
										 |  |  |                     *(size_t_aX *)(out + n) = | 
					
						
							|  |  |  |                         *(size_t_aX *)(in + n) | 
					
						
							|  |  |  |                         ^ *(size_t_aX *)(ecount_buf + n); | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |                 len -= 16; | 
					
						
							|  |  |  |                 out += 16; | 
					
						
							|  |  |  |                 in += 16; | 
					
						
							|  |  |  |                 n = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (len) { | 
					
						
							|  |  |  |                 (*block) (ivec, ecount_buf, key); | 
					
						
							|  |  |  |                 ctr128_inc_aligned(ivec); | 
					
						
							|  |  |  |                 while (len--) { | 
					
						
							|  |  |  |                     out[n] = in[n] ^ ecount_buf[n]; | 
					
						
							|  |  |  |                     ++n; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             *num = n; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } while (0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* the rest would be commonly eliminated by x86* compiler */ | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     while (l < len) { | 
					
						
							|  |  |  |         if (n == 0) { | 
					
						
							|  |  |  |             (*block) (ivec, ecount_buf, key); | 
					
						
							|  |  |  |             ctr128_inc(ivec); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         out[l] = in[l] ^ ecount_buf[n]; | 
					
						
							|  |  |  |         ++l; | 
					
						
							|  |  |  |         n = (n + 1) % 16; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *num = n; | 
					
						
							| 
									
										
										
										
											2008-12-16 16:39:21 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-05 03:23:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* increment upper 96 bits of 128-bit counter by 1 */ | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | static void ctr96_inc(unsigned char *counter) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |     u32 n = 12, c = 1; | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     do { | 
					
						
							|  |  |  |         --n; | 
					
						
							| 
									
										
										
										
											2016-02-12 21:07:27 +08:00
										 |  |  |         c += counter[n]; | 
					
						
							|  |  |  |         counter[n] = (u8)c; | 
					
						
							|  |  |  |         c >>= 8; | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     } while (n); | 
					
						
							| 
									
										
										
										
											2010-05-05 03:23:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out, | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |                                  size_t len, const void *key, | 
					
						
							|  |  |  |                                  unsigned char ivec[16], | 
					
						
							|  |  |  |                                  unsigned char ecount_buf[16], | 
					
						
							|  |  |  |                                  unsigned int *num, ctr128_f func) | 
					
						
							| 
									
										
										
										
											2010-05-05 03:23:02 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |     unsigned int n, ctr32; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												enc: fix coverity 1451499, 1451501, 1451506, 1451507, 1351511, 1451514, 1451517, 1451523, 1451526m 1451528, 1451539, 1451441, 1451549, 1451568 & 1451572: improper use of negative value
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14638)
											
										 
											2021-03-22 10:09:19 +08:00
										 |  |  |    n = *num; | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     while (n && len) { | 
					
						
							|  |  |  |         *(out++) = *(in++) ^ ecount_buf[n]; | 
					
						
							|  |  |  |         --len; | 
					
						
							|  |  |  |         n = (n + 1) % 16; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ctr32 = GETU32(ivec + 12); | 
					
						
							|  |  |  |     while (len >= 16) { | 
					
						
							|  |  |  |         size_t blocks = len / 16; | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * 1<<28 is just a not-so-small yet not-so-large number... | 
					
						
							|  |  |  |          * Below condition is practically never met, but it has to | 
					
						
							|  |  |  |          * be checked for code correctness. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28)) | 
					
						
							|  |  |  |             blocks = (1U << 28); | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * As (*func) operates on 32-bit counter, caller | 
					
						
							|  |  |  |          * has to handle overflow. 'if' below detects the | 
					
						
							|  |  |  |          * overflow, which is then handled by limiting the | 
					
						
							|  |  |  |          * amount of blocks to the exact overflow point... | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         ctr32 += (u32)blocks; | 
					
						
							|  |  |  |         if (ctr32 < blocks) { | 
					
						
							|  |  |  |             blocks -= ctr32; | 
					
						
							|  |  |  |             ctr32 = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         (*func) (in, out, blocks, key, ivec); | 
					
						
							|  |  |  |         /* (*ctr) does not update ivec, caller does: */ | 
					
						
							|  |  |  |         PUTU32(ivec + 12, ctr32); | 
					
						
							| 
									
										
										
										
											2016-02-06 04:23:54 +08:00
										 |  |  |         /* ... overflow was detected, propagate carry. */ | 
					
						
							| 
									
										
										
										
											2015-01-22 11:40:55 +08:00
										 |  |  |         if (ctr32 == 0) | 
					
						
							|  |  |  |             ctr96_inc(ivec); | 
					
						
							|  |  |  |         blocks *= 16; | 
					
						
							|  |  |  |         len -= blocks; | 
					
						
							|  |  |  |         out += blocks; | 
					
						
							|  |  |  |         in += blocks; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (len) { | 
					
						
							|  |  |  |         memset(ecount_buf, 0, 16); | 
					
						
							|  |  |  |         (*func) (ecount_buf, ecount_buf, 1, key, ivec); | 
					
						
							|  |  |  |         ++ctr32; | 
					
						
							|  |  |  |         PUTU32(ivec + 12, ctr32); | 
					
						
							|  |  |  |         if (ctr32 == 0) | 
					
						
							|  |  |  |             ctr96_inc(ivec); | 
					
						
							|  |  |  |         while (len--) { | 
					
						
							|  |  |  |             out[n] = in[n] ^ ecount_buf[n]; | 
					
						
							|  |  |  |             ++n; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *num = n; | 
					
						
							| 
									
										
										
										
											2010-05-05 03:23:02 +08:00
										 |  |  | } |