1de0b2026841c34193cacf5c97646b38439e13200Adam Langley/* Copyright (c) 2014, Google Inc. 2de0b2026841c34193cacf5c97646b38439e13200Adam Langley * 3de0b2026841c34193cacf5c97646b38439e13200Adam Langley * Permission to use, copy, modify, and/or distribute this software for any 4de0b2026841c34193cacf5c97646b38439e13200Adam Langley * purpose with or without fee is hereby granted, provided that the above 5de0b2026841c34193cacf5c97646b38439e13200Adam Langley * copyright notice and this permission notice appear in all copies. 6de0b2026841c34193cacf5c97646b38439e13200Adam Langley * 7de0b2026841c34193cacf5c97646b38439e13200Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8de0b2026841c34193cacf5c97646b38439e13200Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9de0b2026841c34193cacf5c97646b38439e13200Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10de0b2026841c34193cacf5c97646b38439e13200Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11de0b2026841c34193cacf5c97646b38439e13200Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12de0b2026841c34193cacf5c97646b38439e13200Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13de0b2026841c34193cacf5c97646b38439e13200Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14de0b2026841c34193cacf5c97646b38439e13200Adam Langley 15de0b2026841c34193cacf5c97646b38439e13200Adam Langley/* Adapted from the public domain, estream code by D. Bernstein. */ 16de0b2026841c34193cacf5c97646b38439e13200Adam Langley 17de0b2026841c34193cacf5c97646b38439e13200Adam Langley#include <openssl/chacha.h> 18de0b2026841c34193cacf5c97646b38439e13200Adam Langley 19de0b2026841c34193cacf5c97646b38439e13200Adam Langley#include <openssl/cpu.h> 20de0b2026841c34193cacf5c97646b38439e13200Adam Langley 210113a4fb60c3b6e9e93a217d5b4d373eb343a8c6Adam Langley#if defined(OPENSSL_WINDOWS) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || !defined(__SSE2__) 22de0b2026841c34193cacf5c97646b38439e13200Adam Langley 23de0b2026841c34193cacf5c97646b38439e13200Adam Langley/* sigma contains the ChaCha constants, which happen to be an ASCII string. */ 24de0b2026841c34193cacf5c97646b38439e13200Adam Langleystatic const char sigma[16] = "expand 32-byte k"; 25de0b2026841c34193cacf5c97646b38439e13200Adam Langley 26de0b2026841c34193cacf5c97646b38439e13200Adam Langley#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) 27de0b2026841c34193cacf5c97646b38439e13200Adam Langley#define XOR(v, w) ((v) ^ (w)) 28de0b2026841c34193cacf5c97646b38439e13200Adam Langley#define PLUS(x, y) ((x) + (y)) 29de0b2026841c34193cacf5c97646b38439e13200Adam Langley#define PLUSONE(v) (PLUS((v), 1)) 30de0b2026841c34193cacf5c97646b38439e13200Adam Langley 31de0b2026841c34193cacf5c97646b38439e13200Adam Langley#define U32TO8_LITTLE(p, v) \ 32de0b2026841c34193cacf5c97646b38439e13200Adam Langley { \ 33de0b2026841c34193cacf5c97646b38439e13200Adam Langley (p)[0] = (v >> 0) & 0xff; \ 34de0b2026841c34193cacf5c97646b38439e13200Adam Langley (p)[1] = (v >> 8) & 0xff; \ 35de0b2026841c34193cacf5c97646b38439e13200Adam Langley (p)[2] = (v >> 16) & 0xff; \ 36de0b2026841c34193cacf5c97646b38439e13200Adam Langley (p)[3] = (v >> 24) & 0xff; \ 37de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 38de0b2026841c34193cacf5c97646b38439e13200Adam Langley 39de0b2026841c34193cacf5c97646b38439e13200Adam Langley#define U8TO32_LITTLE(p) \ 40de0b2026841c34193cacf5c97646b38439e13200Adam Langley (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ 41de0b2026841c34193cacf5c97646b38439e13200Adam Langley ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) 42de0b2026841c34193cacf5c97646b38439e13200Adam Langley 43de0b2026841c34193cacf5c97646b38439e13200Adam Langley/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */ 44de0b2026841c34193cacf5c97646b38439e13200Adam Langley#define QUARTERROUND(a,b,c,d) \ 45de0b2026841c34193cacf5c97646b38439e13200Adam Langley x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \ 46de0b2026841c34193cacf5c97646b38439e13200Adam Langley x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \ 47de0b2026841c34193cacf5c97646b38439e13200Adam Langley x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \ 48de0b2026841c34193cacf5c97646b38439e13200Adam Langley x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7); 49de0b2026841c34193cacf5c97646b38439e13200Adam Langley 5060d612fdcf7052008fcc17a503854eac1653c739Adam Langley#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) 51de0b2026841c34193cacf5c97646b38439e13200Adam Langley/* Defined in chacha_vec.c */ 52de0b2026841c34193cacf5c97646b38439e13200Adam Langleyvoid CRYPTO_chacha_20_neon(uint8_t *out, const uint8_t *in, size_t in_len, 53de0b2026841c34193cacf5c97646b38439e13200Adam Langley const uint8_t key[32], const uint8_t nonce[8], 54de0b2026841c34193cacf5c97646b38439e13200Adam Langley size_t counter); 55de0b2026841c34193cacf5c97646b38439e13200Adam Langley#endif 56de0b2026841c34193cacf5c97646b38439e13200Adam Langley 57de0b2026841c34193cacf5c97646b38439e13200Adam Langley/* chacha_core performs |num_rounds| rounds of ChaCha20 on the input words in 58de0b2026841c34193cacf5c97646b38439e13200Adam Langley * |input| and writes the 64 output bytes to |output|. */ 59d031f11596fd0bdfeb6333050a06be28dc64de41Adam Langleystatic void chacha_core(uint8_t output[64], const uint32_t input[16]) { 60de0b2026841c34193cacf5c97646b38439e13200Adam Langley uint32_t x[16]; 61de0b2026841c34193cacf5c97646b38439e13200Adam Langley int i; 62de0b2026841c34193cacf5c97646b38439e13200Adam Langley 63de0b2026841c34193cacf5c97646b38439e13200Adam Langley memcpy(x, input, sizeof(uint32_t) * 16); 64de0b2026841c34193cacf5c97646b38439e13200Adam Langley for (i = 20; i > 0; i -= 2) { 65de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(0, 4, 8, 12) 66de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(1, 5, 9, 13) 67de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(2, 6, 10, 14) 68de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(3, 7, 11, 15) 69de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(0, 5, 10, 15) 70de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(1, 6, 11, 12) 71de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(2, 7, 8, 13) 72de0b2026841c34193cacf5c97646b38439e13200Adam Langley QUARTERROUND(3, 4, 9, 14) 73de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 74de0b2026841c34193cacf5c97646b38439e13200Adam Langley 75de0b2026841c34193cacf5c97646b38439e13200Adam Langley for (i = 0; i < 16; ++i) { 76de0b2026841c34193cacf5c97646b38439e13200Adam Langley x[i] = PLUS(x[i], input[i]); 77de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 78de0b2026841c34193cacf5c97646b38439e13200Adam Langley for (i = 0; i < 16; ++i) { 79de0b2026841c34193cacf5c97646b38439e13200Adam Langley U32TO8_LITTLE(output + 4 * i, x[i]); 80de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 81de0b2026841c34193cacf5c97646b38439e13200Adam Langley} 82de0b2026841c34193cacf5c97646b38439e13200Adam Langley 83de0b2026841c34193cacf5c97646b38439e13200Adam Langleyvoid CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len, 84de0b2026841c34193cacf5c97646b38439e13200Adam Langley const uint8_t key[32], const uint8_t nonce[8], 85de0b2026841c34193cacf5c97646b38439e13200Adam Langley size_t counter) { 86de0b2026841c34193cacf5c97646b38439e13200Adam Langley uint32_t input[16]; 87de0b2026841c34193cacf5c97646b38439e13200Adam Langley uint8_t buf[64]; 88de0b2026841c34193cacf5c97646b38439e13200Adam Langley size_t todo, i; 89de0b2026841c34193cacf5c97646b38439e13200Adam Langley 9060d612fdcf7052008fcc17a503854eac1653c739Adam Langley#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) 91de0b2026841c34193cacf5c97646b38439e13200Adam Langley if (CRYPTO_is_NEON_capable() && ((intptr_t)in & 15) == 0 && 92de0b2026841c34193cacf5c97646b38439e13200Adam Langley ((intptr_t)out & 15) == 0) { 93de0b2026841c34193cacf5c97646b38439e13200Adam Langley CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter); 94de0b2026841c34193cacf5c97646b38439e13200Adam Langley return; 95de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 96de0b2026841c34193cacf5c97646b38439e13200Adam Langley#endif 97de0b2026841c34193cacf5c97646b38439e13200Adam Langley 98de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[0] = U8TO32_LITTLE(sigma + 0); 99de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[1] = U8TO32_LITTLE(sigma + 4); 100de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[2] = U8TO32_LITTLE(sigma + 8); 101de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[3] = U8TO32_LITTLE(sigma + 12); 102de0b2026841c34193cacf5c97646b38439e13200Adam Langley 103de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[4] = U8TO32_LITTLE(key + 0); 104de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[5] = U8TO32_LITTLE(key + 4); 105de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[6] = U8TO32_LITTLE(key + 8); 106de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[7] = U8TO32_LITTLE(key + 12); 107de0b2026841c34193cacf5c97646b38439e13200Adam Langley 108de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[8] = U8TO32_LITTLE(key + 16); 109de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[9] = U8TO32_LITTLE(key + 20); 110de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[10] = U8TO32_LITTLE(key + 24); 111de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[11] = U8TO32_LITTLE(key + 28); 112de0b2026841c34193cacf5c97646b38439e13200Adam Langley 113de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[12] = counter; 114de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[13] = ((uint64_t)counter) >> 32; 115de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[14] = U8TO32_LITTLE(nonce + 0); 116de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[15] = U8TO32_LITTLE(nonce + 4); 117de0b2026841c34193cacf5c97646b38439e13200Adam Langley 118de0b2026841c34193cacf5c97646b38439e13200Adam Langley while (in_len > 0) { 119de0b2026841c34193cacf5c97646b38439e13200Adam Langley todo = sizeof(buf); 120de0b2026841c34193cacf5c97646b38439e13200Adam Langley if (in_len < todo) { 121de0b2026841c34193cacf5c97646b38439e13200Adam Langley todo = in_len; 122de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 123de0b2026841c34193cacf5c97646b38439e13200Adam Langley 124d031f11596fd0bdfeb6333050a06be28dc64de41Adam Langley chacha_core(buf, input); 125de0b2026841c34193cacf5c97646b38439e13200Adam Langley for (i = 0; i < todo; i++) { 126de0b2026841c34193cacf5c97646b38439e13200Adam Langley out[i] = in[i] ^ buf[i]; 127de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 128de0b2026841c34193cacf5c97646b38439e13200Adam Langley 129de0b2026841c34193cacf5c97646b38439e13200Adam Langley out += todo; 130de0b2026841c34193cacf5c97646b38439e13200Adam Langley in += todo; 131de0b2026841c34193cacf5c97646b38439e13200Adam Langley in_len -= todo; 132de0b2026841c34193cacf5c97646b38439e13200Adam Langley 133de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[12]++; 134de0b2026841c34193cacf5c97646b38439e13200Adam Langley if (input[12] == 0) { 135de0b2026841c34193cacf5c97646b38439e13200Adam Langley input[13]++; 136de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 137de0b2026841c34193cacf5c97646b38439e13200Adam Langley } 138de0b2026841c34193cacf5c97646b38439e13200Adam Langley} 139de0b2026841c34193cacf5c97646b38439e13200Adam Langley 1400113a4fb60c3b6e9e93a217d5b4d373eb343a8c6Adam Langley#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 && !OPENSSL_X86 || !__SSE2__ */ 141