1 
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include "core.h"
7 #include "crypto_stream_chacha20.h"
8 #include "private/common.h"
9 #include "private/sse2_64_32.h"
10 #include "utils.h"
11 
12 #if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H)
13 
14 # ifdef __GNUC__
15 #  pragma GCC target("sse2")
16 #  pragma GCC target("ssse3")
17 # endif
18 
19 # include <emmintrin.h>
20 # include <tmmintrin.h>
21 
22 # include "../stream_chacha20.h"
23 # include "chacha20_dolbeau-ssse3.h"
24 
25 # define ROUNDS 20
26 
27 typedef struct chacha_ctx {
28     uint32_t input[16];
29 } chacha_ctx;
30 
31 static void
32 chacha_keysetup(chacha_ctx *ctx, const uint8_t *k)
33 {
34     ctx->input[0]  = 0x61707865;
35     ctx->input[1]  = 0x3320646e;
36     ctx->input[2]  = 0x79622d32;
37     ctx->input[3]  = 0x6b206574;
38     ctx->input[4]  = LOAD32_LE(k + 0);
39     ctx->input[5]  = LOAD32_LE(k + 4);
40     ctx->input[6]  = LOAD32_LE(k + 8);
41     ctx->input[7]  = LOAD32_LE(k + 12);
42     ctx->input[8]  = LOAD32_LE(k + 16);
43     ctx->input[9]  = LOAD32_LE(k + 20);
44     ctx->input[10] = LOAD32_LE(k + 24);
45     ctx->input[11] = LOAD32_LE(k + 28);
46 }
47 
48 static void
49 chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter)
50 {
51     ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter + 0);
52     ctx->input[13] = counter == NULL ? 0 : LOAD32_LE(counter + 4);
53     ctx->input[14] = LOAD32_LE(iv + 0);
54     ctx->input[15] = LOAD32_LE(iv + 4);
55 }
56 
57 static void
58 chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter)
59 {
60     ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter);
61     ctx->input[13] = LOAD32_LE(iv + 0);
62     ctx->input[14] = LOAD32_LE(iv + 4);
63     ctx->input[15] = LOAD32_LE(iv + 8);
64 }
65 
66 static void
67 chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c,
68                        unsigned long long bytes)
69 {
70     uint32_t * const x = &ctx->input[0];
71 
72     if (!bytes) {
73         return; /* LCOV_EXCL_LINE */
74     }
75     if (bytes > crypto_stream_chacha20_MESSAGEBYTES_MAX) {
76         sodium_misuse();
77     }
78 # include "u4.h"
79 # include "u1.h"
80 # include "u0.h"
81 }
82 
83 static int
84 stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n,
85            const unsigned char *k)
86 {
87     struct chacha_ctx ctx;
88 
89     if (!clen) {
90         return 0;
91     }
92     COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8);
93     chacha_keysetup(&ctx, k);
94     chacha_ivsetup(&ctx, n, NULL);
95     memset(c, 0, clen);
96     chacha20_encrypt_bytes(&ctx, c, c, clen);
97     sodium_memzero(&ctx, sizeof ctx);
98 
99     return 0;
100 }
101 
102 static int
103 stream_ietf_ref(unsigned char *c, unsigned long long clen,
104                 const unsigned char *n, const unsigned char *k)
105 {
106     struct chacha_ctx ctx;
107 
108     if (!clen) {
109         return 0;
110     }
111     COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8);
112     chacha_keysetup(&ctx, k);
113     chacha_ietf_ivsetup(&ctx, n, NULL);
114     memset(c, 0, clen);
115     chacha20_encrypt_bytes(&ctx, c, c, clen);
116     sodium_memzero(&ctx, sizeof ctx);
117 
118     return 0;
119 }
120 
121 static int
122 stream_ref_xor_ic(unsigned char *c, const unsigned char *m,
123                   unsigned long long mlen, const unsigned char *n, uint64_t ic,
124                   const unsigned char *k)
125 {
126     struct chacha_ctx ctx;
127     uint8_t           ic_bytes[8];
128     uint32_t          ic_high;
129     uint32_t          ic_low;
130 
131     if (!mlen) {
132         return 0;
133     }
134     ic_high = (uint32_t) (ic >> 32);
135     ic_low  = (uint32_t) ic;
136     STORE32_LE(&ic_bytes[0], ic_low);
137     STORE32_LE(&ic_bytes[4], ic_high);
138     chacha_keysetup(&ctx, k);
139     chacha_ivsetup(&ctx, n, ic_bytes);
140     chacha20_encrypt_bytes(&ctx, m, c, mlen);
141     sodium_memzero(&ctx, sizeof ctx);
142 
143     return 0;
144 }
145 
146 static int
147 stream_ietf_ref_xor_ic(unsigned char *c, const unsigned char *m,
148                        unsigned long long mlen, const unsigned char *n,
149                        uint32_t ic, const unsigned char *k)
150 {
151     struct chacha_ctx ctx;
152     uint8_t           ic_bytes[4];
153 
154     if (!mlen) {
155         return 0;
156     }
157     STORE32_LE(ic_bytes, ic);
158     chacha_keysetup(&ctx, k);
159     chacha_ietf_ivsetup(&ctx, n, ic_bytes);
160     chacha20_encrypt_bytes(&ctx, m, c, mlen);
161     sodium_memzero(&ctx, sizeof ctx);
162 
163     return 0;
164 }
165 
166 struct crypto_stream_chacha20_implementation
167     crypto_stream_chacha20_dolbeau_ssse3_implementation = {
168         SODIUM_C99(.stream =) stream_ref,
169         SODIUM_C99(.stream_ietf =) stream_ietf_ref,
170         SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic,
171         SODIUM_C99(.stream_ietf_xor_ic =) stream_ietf_ref_xor_ic
172     };
173 
174 #endif
175