blob: 646ef7a6c1240d88d8ea7e9e687581d3a76deca9 [file] [log] [blame]
Adam Langleyde0b2022014-06-20 12:00:00 -07001/* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
David Benjamin808f8322017-08-18 14:06:02 -040015// Adapted from the public domain, estream code by D. Bernstein.
Adam Langleyde0b2022014-06-20 12:00:00 -070016
17#include <openssl/chacha.h>
18
David Benjamin2446db02016-06-08 18:31:42 -040019#include <assert.h>
Adam Langley2b2d66d2015-01-30 17:08:37 -080020#include <string.h>
21
Adam Langleyde0b2022014-06-20 12:00:00 -070022#include <openssl/cpu.h>
23
David Benjamin2446db02016-06-08 18:31:42 -040024#include "../internal.h"
25
Adam Langley2b2d66d2015-01-30 17:08:37 -080026
David Benjamin35be6882016-02-19 18:47:22 -050027#define U8TO32_LITTLE(p) \
28 (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
29 ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24))
30
31#if !defined(OPENSSL_NO_ASM) && \
David Benjamin762e1d02016-03-24 20:40:22 -040032 (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
33 defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
David Benjamin35be6882016-02-19 18:47:22 -050034
David Benjamin808f8322017-08-18 14:06:02 -040035// ChaCha20_ctr32 is defined in asm/chacha-*.pl.
David Benjamin35be6882016-02-19 18:47:22 -050036void ChaCha20_ctr32(uint8_t *out, const uint8_t *in, size_t in_len,
37 const uint32_t key[8], const uint32_t counter[4]);
38
39void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
40 const uint8_t key[32], const uint8_t nonce[12],
41 uint32_t counter) {
David Benjamin2446db02016-06-08 18:31:42 -040042 assert(!buffers_alias(out, in_len, in, in_len) || in == out);
43
44 uint32_t counter_nonce[4]; counter_nonce[0] = counter;
David Benjamin35be6882016-02-19 18:47:22 -050045 counter_nonce[1] = U8TO32_LITTLE(nonce + 0);
46 counter_nonce[2] = U8TO32_LITTLE(nonce + 4);
47 counter_nonce[3] = U8TO32_LITTLE(nonce + 8);
48
49 const uint32_t *key_ptr = (const uint32_t *)key;
50#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64)
David Benjamin808f8322017-08-18 14:06:02 -040051 // The assembly expects the key to be four-byte aligned.
David Benjamin35be6882016-02-19 18:47:22 -050052 uint32_t key_u32[8];
53 if ((((uintptr_t)key) & 3) != 0) {
54 key_u32[0] = U8TO32_LITTLE(key + 0);
55 key_u32[1] = U8TO32_LITTLE(key + 4);
56 key_u32[2] = U8TO32_LITTLE(key + 8);
57 key_u32[3] = U8TO32_LITTLE(key + 12);
58 key_u32[4] = U8TO32_LITTLE(key + 16);
59 key_u32[5] = U8TO32_LITTLE(key + 20);
60 key_u32[6] = U8TO32_LITTLE(key + 24);
61 key_u32[7] = U8TO32_LITTLE(key + 28);
62
63 key_ptr = key_u32;
64 }
65#endif
66
67 ChaCha20_ctr32(out, in, in_len, key_ptr, counter_nonce);
68}
69
70#else
Adam Langleyde0b2022014-06-20 12:00:00 -070071
David Benjamin808f8322017-08-18 14:06:02 -040072// sigma contains the ChaCha constants, which happen to be an ASCII string.
Brian Smithefed2212015-01-28 16:20:02 -080073static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
74 '2', '-', 'b', 'y', 't', 'e', ' ', 'k' };
Adam Langleyde0b2022014-06-20 12:00:00 -070075
76#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
Adam Langleyde0b2022014-06-20 12:00:00 -070077
78#define U32TO8_LITTLE(p, v) \
79 { \
80 (p)[0] = (v >> 0) & 0xff; \
81 (p)[1] = (v >> 8) & 0xff; \
82 (p)[2] = (v >> 16) & 0xff; \
83 (p)[3] = (v >> 24) & 0xff; \
84 }
85
David Benjamin808f8322017-08-18 14:06:02 -040086// QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round.
David Benjamin3b6fb592016-09-12 20:17:27 -040087#define QUARTERROUND(a, b, c, d) \
88 x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 16); \
89 x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 12); \
90 x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 8); \
91 x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 7);
Adam Langleyde0b2022014-06-20 12:00:00 -070092
David Benjamin808f8322017-08-18 14:06:02 -040093// chacha_core performs 20 rounds of ChaCha on the input words in
94// |input| and writes the 64 output bytes to |output|.
Adam Langleyd031f112014-06-23 13:14:13 -070095static void chacha_core(uint8_t output[64], const uint32_t input[16]) {
Adam Langleyde0b2022014-06-20 12:00:00 -070096 uint32_t x[16];
97 int i;
98
David Benjamin17cf2cb2016-12-13 01:07:13 -050099 OPENSSL_memcpy(x, input, sizeof(uint32_t) * 16);
Adam Langleyde0b2022014-06-20 12:00:00 -0700100 for (i = 20; i > 0; i -= 2) {
101 QUARTERROUND(0, 4, 8, 12)
102 QUARTERROUND(1, 5, 9, 13)
103 QUARTERROUND(2, 6, 10, 14)
104 QUARTERROUND(3, 7, 11, 15)
105 QUARTERROUND(0, 5, 10, 15)
106 QUARTERROUND(1, 6, 11, 12)
107 QUARTERROUND(2, 7, 8, 13)
108 QUARTERROUND(3, 4, 9, 14)
109 }
110
111 for (i = 0; i < 16; ++i) {
David Benjamin3b6fb592016-09-12 20:17:27 -0400112 x[i] += input[i];
Adam Langleyde0b2022014-06-20 12:00:00 -0700113 }
114 for (i = 0; i < 16; ++i) {
115 U32TO8_LITTLE(output + 4 * i, x[i]);
116 }
117}
118
119void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
Brian Smithe80a2ec2015-10-03 08:13:36 -1000120 const uint8_t key[32], const uint8_t nonce[12],
121 uint32_t counter) {
David Benjamin2446db02016-06-08 18:31:42 -0400122 assert(!buffers_alias(out, in_len, in, in_len) || in == out);
123
Adam Langleyde0b2022014-06-20 12:00:00 -0700124 uint32_t input[16];
125 uint8_t buf[64];
126 size_t todo, i;
127
Adam Langleyde0b2022014-06-20 12:00:00 -0700128 input[0] = U8TO32_LITTLE(sigma + 0);
129 input[1] = U8TO32_LITTLE(sigma + 4);
130 input[2] = U8TO32_LITTLE(sigma + 8);
131 input[3] = U8TO32_LITTLE(sigma + 12);
132
133 input[4] = U8TO32_LITTLE(key + 0);
134 input[5] = U8TO32_LITTLE(key + 4);
135 input[6] = U8TO32_LITTLE(key + 8);
136 input[7] = U8TO32_LITTLE(key + 12);
137
138 input[8] = U8TO32_LITTLE(key + 16);
139 input[9] = U8TO32_LITTLE(key + 20);
140 input[10] = U8TO32_LITTLE(key + 24);
141 input[11] = U8TO32_LITTLE(key + 28);
142
143 input[12] = counter;
Brian Smithe80a2ec2015-10-03 08:13:36 -1000144 input[13] = U8TO32_LITTLE(nonce + 0);
145 input[14] = U8TO32_LITTLE(nonce + 4);
146 input[15] = U8TO32_LITTLE(nonce + 8);
Adam Langleyde0b2022014-06-20 12:00:00 -0700147
148 while (in_len > 0) {
149 todo = sizeof(buf);
150 if (in_len < todo) {
151 todo = in_len;
152 }
153
Adam Langleyd031f112014-06-23 13:14:13 -0700154 chacha_core(buf, input);
Adam Langleyde0b2022014-06-20 12:00:00 -0700155 for (i = 0; i < todo; i++) {
156 out[i] = in[i] ^ buf[i];
157 }
158
159 out += todo;
160 in += todo;
161 in_len -= todo;
162
163 input[12]++;
Adam Langleyde0b2022014-06-20 12:00:00 -0700164 }
165}
166
David Benjamin35be6882016-02-19 18:47:22 -0500167#endif