#include #include #include #include "core.h" #include "crypto_stream_chacha20.h" #include "private/common.h" #include "private/sse2_64_32.h" #include "utils.h" #if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) # ifdef __GNUC__ # pragma GCC target("sse2") # pragma GCC target("ssse3") # endif # include # include # include "../stream_chacha20.h" # include "chacha20_dolbeau-ssse3.h" # define ROUNDS 20 typedef struct chacha_ctx { uint32_t input[16]; } chacha_ctx; static void chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) { ctx->input[0] = 0x61707865; ctx->input[1] = 0x3320646e; ctx->input[2] = 0x79622d32; ctx->input[3] = 0x6b206574; ctx->input[4] = LOAD32_LE(k + 0); ctx->input[5] = LOAD32_LE(k + 4); ctx->input[6] = LOAD32_LE(k + 8); ctx->input[7] = LOAD32_LE(k + 12); ctx->input[8] = LOAD32_LE(k + 16); ctx->input[9] = LOAD32_LE(k + 20); ctx->input[10] = LOAD32_LE(k + 24); ctx->input[11] = LOAD32_LE(k + 28); } static void chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) { ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter + 0); ctx->input[13] = counter == NULL ? 0 : LOAD32_LE(counter + 4); ctx->input[14] = LOAD32_LE(iv + 0); ctx->input[15] = LOAD32_LE(iv + 4); } static void chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) { ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter); ctx->input[13] = LOAD32_LE(iv + 0); ctx->input[14] = LOAD32_LE(iv + 4); ctx->input[15] = LOAD32_LE(iv + 8); } static void chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, unsigned long long bytes) { uint32_t * const x = &ctx->input[0]; if (!bytes) { return; /* LCOV_EXCL_LINE */ } if (bytes > crypto_stream_chacha20_MESSAGEBYTES_MAX) { sodium_misuse(); } # include "u4.h" # include "u1.h" # include "u0.h" } static int stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n, const unsigned char *k) { struct chacha_ctx ctx; if (!clen) { return 0; } COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); chacha_keysetup(&ctx, k); chacha_ivsetup(&ctx, n, NULL); memset(c, 0, clen); chacha20_encrypt_bytes(&ctx, c, c, clen); sodium_memzero(&ctx, sizeof ctx); return 0; } static int stream_ietf_ref(unsigned char *c, unsigned long long clen, const unsigned char *n, const unsigned char *k) { struct chacha_ctx ctx; if (!clen) { return 0; } COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); chacha_keysetup(&ctx, k); chacha_ietf_ivsetup(&ctx, n, NULL); memset(c, 0, clen); chacha20_encrypt_bytes(&ctx, c, c, clen); sodium_memzero(&ctx, sizeof ctx); return 0; } 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) { struct chacha_ctx ctx; uint8_t ic_bytes[8]; uint32_t ic_high; uint32_t ic_low; if (!mlen) { return 0; } ic_high = (uint32_t) (ic >> 32); ic_low = (uint32_t) ic; STORE32_LE(&ic_bytes[0], ic_low); STORE32_LE(&ic_bytes[4], ic_high); chacha_keysetup(&ctx, k); chacha_ivsetup(&ctx, n, ic_bytes); chacha20_encrypt_bytes(&ctx, m, c, mlen); sodium_memzero(&ctx, sizeof ctx); return 0; } 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) { struct chacha_ctx ctx; uint8_t ic_bytes[4]; if (!mlen) { return 0; } STORE32_LE(ic_bytes, ic); chacha_keysetup(&ctx, k); chacha_ietf_ivsetup(&ctx, n, ic_bytes); chacha20_encrypt_bytes(&ctx, m, c, mlen); sodium_memzero(&ctx, sizeof ctx); return 0; } struct crypto_stream_chacha20_implementation crypto_stream_chacha20_dolbeau_ssse3_implementation = { SODIUM_C99(.stream =) stream_ref, SODIUM_C99(.stream_ietf =) stream_ietf_ref, SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic, SODIUM_C99(.stream_ietf_xor_ic =) stream_ietf_ref_xor_ic }; #endif