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
chacha_keysetup(chacha_ctx * ctx,const uint8_t * k)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
chacha_ivsetup(chacha_ctx * ctx,const uint8_t * iv,const uint8_t * counter)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
chacha_ietf_ivsetup(chacha_ctx * ctx,const uint8_t * iv,const uint8_t * counter)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
chacha20_encrypt_bytes(chacha_ctx * ctx,const uint8_t * m,uint8_t * c,unsigned long long bytes)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
stream_ref(unsigned char * c,unsigned long long clen,const unsigned char * n,const unsigned char * k)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
stream_ietf_ref(unsigned char * c,unsigned long long clen,const unsigned char * n,const unsigned char * k)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
stream_ref_xor_ic(unsigned char * c,const unsigned char * m,unsigned long long mlen,const unsigned char * n,uint64_t ic,const unsigned char * k)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
stream_ietf_ref_xor_ic(unsigned char * c,const unsigned char * m,unsigned long long mlen,const unsigned char * n,uint32_t ic,const unsigned char * k)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