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
27typedef struct chacha_ctx {
28    uint32_t input[16];
29} chacha_ctx;
30
31static void
32chacha_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
48static void
49chacha_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
57static void
58chacha_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
66static void
67chacha20_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
83static int
84stream_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
102static int
103stream_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
121static int
122stream_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
146static int
147stream_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
166struct 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