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