• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Chacha stream algorithm.
3  *
4  *  Created on: Jun, 2013
5  *  Author: Elie Bursztein (elieb@google.com)
6  *
7  *  Adapted from the estream code by D. Bernstein.
8  */
9 /* ====================================================================
10  * Copyright (c) 2011-2013 The OpenSSL Project.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  *
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in
21  *    the documentation and/or other materials provided with the
22  *    distribution.
23  *
24  * 3. All advertising materials mentioning features or use of this
25  *    software must display the following acknowledgment:
26  *    "This product includes software developed by the OpenSSL Project
27  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
28  *
29  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
30  *    endorse or promote products derived from this software without
31  *    prior written permission. For written permission, please contact
32  *    licensing@OpenSSL.org.
33  *
34  * 5. Products derived from this software may not be called "OpenSSL"
35  *    nor may "OpenSSL" appear in their names without prior written
36  *    permission of the OpenSSL Project.
37  *
38  * 6. Redistributions of any form whatsoever must retain the following
39  *    acknowledgment:
40  *    "This product includes software developed by the OpenSSL Project
41  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
44  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
47  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
49  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
50  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
52  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
54  * OF THE POSSIBILITY OF SUCH DAMAGE.
55  * ====================================================================
56  */
57 
58 #include <stdint.h>
59 #include <string.h>
60 #include <openssl/opensslconf.h>
61 
62 #if !defined(OPENSSL_NO_CHACHA)
63 
64 #include <openssl/crypto.h>
65 #include <openssl/chacha.h>
66 
67 /* sigma contains the ChaCha constants, which happen to be an ASCII string. */
68 static const char sigma[16] = "expand 32-byte k";
69 
70 #define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
71 #define XOR(v, w) ((v) ^ (w))
72 #define PLUS(x, y) ((x) + (y))
73 #define PLUSONE(v) (PLUS((v), 1))
74 
75 #define U32TO8_LITTLE(p, v) \
76 	{ (p)[0] = (v >>  0) & 0xff; (p)[1] = (v >>  8) & 0xff; \
77 	  (p)[2] = (v >> 16) & 0xff; (p)[3] = (v >> 24) & 0xff; }
78 #define U8TO32_LITTLE(p)   \
79 	(((uint32_t)((p)[0])      ) | ((uint32_t)((p)[1]) <<  8) | \
80 	 ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)   )
81 
82 /* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
83 #define QUARTERROUND(a,b,c,d) \
84   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
85   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
86   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
87   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
88 
89 typedef unsigned int uint32_t;
90 
91 #if __arm__
92 /* Defined in chacha_vec.c */
93 void CRYPTO_chacha_20_neon(unsigned char *out,
94 		           const unsigned char *in, size_t in_len,
95 		           const unsigned char key[32],
96 		           const unsigned char nonce[8],
97 		           size_t counter);
98 #endif
99 
100 /* chacha_core performs |num_rounds| rounds of ChaCha20 on the input words in
101  * |input| and writes the 64 output bytes to |output|. */
chacha_core(unsigned char output[64],const uint32_t input[16],int num_rounds)102 static void chacha_core(unsigned char output[64], const uint32_t input[16],
103 			int num_rounds)
104 	{
105 	uint32_t x[16];
106 	int i;
107 
108 	memcpy(x, input, sizeof(uint32_t) * 16);
109 	for (i = 20; i > 0; i -= 2)
110 		{
111 		QUARTERROUND( 0, 4, 8,12)
112 		QUARTERROUND( 1, 5, 9,13)
113 		QUARTERROUND( 2, 6,10,14)
114 		QUARTERROUND( 3, 7,11,15)
115 		QUARTERROUND( 0, 5,10,15)
116 		QUARTERROUND( 1, 6,11,12)
117 		QUARTERROUND( 2, 7, 8,13)
118 		QUARTERROUND( 3, 4, 9,14)
119 		}
120 
121 	for (i = 0; i < 16; ++i)
122 		x[i] = PLUS(x[i], input[i]);
123 	for (i = 0; i < 16; ++i)
124 		U32TO8_LITTLE(output + 4 * i, x[i]);
125 	}
126 
CRYPTO_chacha_20(unsigned char * out,const unsigned char * in,size_t in_len,const unsigned char key[32],const unsigned char nonce[8],size_t counter)127 void CRYPTO_chacha_20(unsigned char *out,
128 		      const unsigned char *in, size_t in_len,
129 		      const unsigned char key[32],
130 		      const unsigned char nonce[8],
131 		      size_t counter)
132 	{
133 	uint32_t input[16];
134 	unsigned char buf[64];
135 	size_t todo, i;
136 
137 #if __arm__
138 	if (CRYPTO_is_NEON_capable() &&
139 	    ((intptr_t)in & 15) == 0 &&
140 	    ((intptr_t)out & 15) == 0)
141 		{
142 		CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter);
143 		return;
144 		}
145 #endif
146 
147 	input[0] = U8TO32_LITTLE(sigma + 0);
148 	input[1] = U8TO32_LITTLE(sigma + 4);
149 	input[2] = U8TO32_LITTLE(sigma + 8);
150 	input[3] = U8TO32_LITTLE(sigma + 12);
151 
152 	input[4] = U8TO32_LITTLE(key + 0);
153 	input[5] = U8TO32_LITTLE(key + 4);
154 	input[6] = U8TO32_LITTLE(key + 8);
155 	input[7] = U8TO32_LITTLE(key + 12);
156 
157 	input[8] = U8TO32_LITTLE(key + 16);
158 	input[9] = U8TO32_LITTLE(key + 20);
159 	input[10] = U8TO32_LITTLE(key + 24);
160 	input[11] = U8TO32_LITTLE(key + 28);
161 
162 	input[12] = counter;
163 	input[13] = ((uint64_t) counter) >> 32;
164 	input[14] = U8TO32_LITTLE(nonce + 0);
165 	input[15] = U8TO32_LITTLE(nonce + 4);
166 
167 	while (in_len > 0)
168 		{
169 		todo = sizeof(buf);
170 		if (in_len < todo)
171 			todo = in_len;
172 
173 		chacha_core(buf, input, 20);
174 		for (i = 0; i < todo; i++)
175 			out[i] = in[i] ^ buf[i];
176 
177 		out += todo;
178 		in += todo;
179 		in_len -= todo;
180 
181 		input[12]++;
182 		if (input[12] == 0)
183 			input[13]++;
184 		}
185 	}
186 
187 #endif  /* !OPENSSL_NO_CHACHA */
188