Work around Travis "virtual memory exhausted" error
[openssl.git] / crypto / chacha / chacha_enc.c
1 /*
2  * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 /* Adapted from the public domain code by D. Bernstein from SUPERCOP. */
11
12 #include <string.h>
13
14 #include "internal/chacha.h"
15
16 typedef unsigned int u32;
17 typedef unsigned char u8;
18 typedef union {
19     u32 u[16];
20     u8 c[64];
21 } chacha_buf;
22
23 # define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
24
25 # define U32TO8_LITTLE(p, v) do { \
26                                 (p)[0] = (u8)(v >>  0); \
27                                 (p)[1] = (u8)(v >>  8); \
28                                 (p)[2] = (u8)(v >> 16); \
29                                 (p)[3] = (u8)(v >> 24); \
30                                 } while(0)
31
32 /* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
33 # define QUARTERROUND(a,b,c,d) ( \
34                 x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]),16), \
35                 x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]),12), \
36                 x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]), 8), \
37                 x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]), 7)  )
38
39 /* chacha_core performs 20 rounds of ChaCha on the input words in
40  * |input| and writes the 64 output bytes to |output|. */
41 static void chacha20_core(chacha_buf *output, const u32 input[16])
42 {
43     u32 x[16];
44     int i;
45     const union {
46         long one;
47         char little;
48     } is_endian = { 1 };
49
50     memcpy(x, input, sizeof(x));
51
52     for (i = 20; i > 0; i -= 2) {
53         QUARTERROUND(0, 4, 8, 12);
54         QUARTERROUND(1, 5, 9, 13);
55         QUARTERROUND(2, 6, 10, 14);
56         QUARTERROUND(3, 7, 11, 15);
57         QUARTERROUND(0, 5, 10, 15);
58         QUARTERROUND(1, 6, 11, 12);
59         QUARTERROUND(2, 7, 8, 13);
60         QUARTERROUND(3, 4, 9, 14);
61     }
62
63     if (is_endian.little) {
64         for (i = 0; i < 16; ++i)
65             output->u[i] = x[i] + input[i];
66     } else {
67         for (i = 0; i < 16; ++i)
68             U32TO8_LITTLE(output->c + 4 * i, (x[i] + input[i]));
69     }
70 }
71
72 void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
73                     size_t len, const unsigned int key[8],
74                     const unsigned int counter[4])
75 {
76     u32 input[16];
77     chacha_buf buf;
78     size_t todo, i;
79
80     /* sigma constant "expand 32-byte k" in little-endian encoding */
81     input[0] = ((u32)'e') | ((u32)'x'<<8) | ((u32)'p'<<16) | ((u32)'a'<<24);
82     input[1] = ((u32)'n') | ((u32)'d'<<8) | ((u32)' '<<16) | ((u32)'3'<<24);
83     input[2] = ((u32)'2') | ((u32)'-'<<8) | ((u32)'b'<<16) | ((u32)'y'<<24);
84     input[3] = ((u32)'t') | ((u32)'e'<<8) | ((u32)' '<<16) | ((u32)'k'<<24);
85
86     input[4] = key[0];
87     input[5] = key[1];
88     input[6] = key[2];
89     input[7] = key[3];
90     input[8] = key[4];
91     input[9] = key[5];
92     input[10] = key[6];
93     input[11] = key[7];
94
95     input[12] = counter[0];
96     input[13] = counter[1];
97     input[14] = counter[2];
98     input[15] = counter[3];
99
100     while (len > 0) {
101         todo = sizeof(buf);
102         if (len < todo)
103             todo = len;
104
105         chacha20_core(&buf, input);
106
107         for (i = 0; i < todo; i++)
108             out[i] = inp[i] ^ buf.c[i];
109         out += todo;
110         inp += todo;
111         len -= todo;
112
113         /*
114          * Advance 32-bit counter. Note that as subroutine is so to
115          * say nonce-agnostic, this limited counter width doesn't
116          * prevent caller from implementing wider counter. It would
117          * simply take two calls split on counter overflow...
118          */
119         input[12]++;
120     }
121 }