Created
October 22, 2013 23:50
-
-
Save orlp/7110176 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <string.h> | |
#define ROTL32(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) | |
#define LOAD_LE32(x) \ | |
(((x)[0] << 0) | \ | |
((x)[1] << 8) | \ | |
((x)[2] << 16) | \ | |
((x)[3] << 24)) | |
#define STORE_LE32(x, v) \ | |
(x)[0] = (v) >> 0; \ | |
(x)[1] = (v) >> 8; \ | |
(x)[2] = (v) >> 16; \ | |
(x)[3] = (v) >> 24 | |
#define QUARTERROUND(a, b, c, d) \ | |
x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = ROTL32(x[d], 16); \ | |
x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = ROTL32(x[b], 12); \ | |
x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = ROTL32(x[d], 8); \ | |
x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = ROTL32(x[b], 7) | |
static void chacha_core(unsigned char *out, | |
const uint32_t keysetup[16], int rounds) { | |
uint32_t x[16]; | |
int i; | |
for (i = 0; i < 16; ++i) { | |
x[i] = keysetup[i]; | |
} | |
for (i = 0; i < rounds; i += 2) { | |
QUARTERROUND(0, 4, 8, 12); | |
QUARTERROUND(1, 5, 9, 13); | |
QUARTERROUND(2, 6, 10, 14); | |
QUARTERROUND(3, 7, 11, 15); | |
QUARTERROUND(0, 5, 10, 15); | |
QUARTERROUND(1, 6, 11, 12); | |
QUARTERROUND(2, 7, 8, 13); | |
QUARTERROUND(3, 4, 9, 14); | |
} | |
for (i = 0; i < 16; ++i) { | |
STORE_LE32(out + 4*i, x[i] + keysetup[i]); | |
} | |
} | |
static void chacha_keysetup(uint32_t keysetup[16], | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits) { | |
static const unsigned char sigma[16] = "expand 32-byte k"; | |
static const unsigned char tau[16] = "expand 16-byte k"; | |
const unsigned char *constant; | |
int i; | |
for (i = 0; i < 4; ++i) { | |
keysetup[4+i] = LOAD_LE32(key + 4*i); | |
} | |
if (keybits == 256) { | |
key += 16; | |
constant = sigma; | |
} else { | |
constant = tau; | |
} | |
for (i = 0; i < 4; ++i) { | |
keysetup[8+i] = LOAD_LE32(key + 4*i); | |
} | |
for (i = 0; i < 4; ++i) { | |
keysetup[i] = LOAD_LE32(constant + 4*i); | |
} | |
keysetup[12] = 0; | |
keysetup[13] = 0; | |
keysetup[14] = LOAD_LE32(nonce + 0); | |
keysetup[15] = LOAD_LE32(nonce + 4); | |
} | |
static void chacha_stream(unsigned char *out, int outlen, | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits, int rounds) { | |
uint32_t keysetup[16]; | |
chacha_keysetup(keysetup, nonce, key, keybits); | |
while (outlen > 0) { | |
if (outlen >= 64) { | |
chacha_core(out, keysetup, rounds); | |
} else { | |
unsigned char core_output[64]; | |
chacha_core(core_output, keysetup, rounds); | |
memcpy(out, core_output, outlen); | |
} | |
out += 64; | |
outlen -= 64; | |
keysetup[12]++; | |
keysetup[13] += (keysetup[12] == 0); | |
} | |
} | |
void chacha8_stream(unsigned char *out, int outlen, | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits) { | |
chacha_stream(out, outlen, nonce, key, keybits, 8); | |
} | |
void chacha12_stream(unsigned char *out, int outlen, | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits) { | |
chacha_stream(out, outlen, nonce, key, keybits, 12); | |
} | |
void chacha20_stream(unsigned char *out, int outlen, | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits) { | |
chacha_stream(out, outlen, nonce, key, keybits, 20); | |
} | |
void chacha8_encrypt(unsigned char *out, const unsigned char *in, int inlen, | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits) { | |
int i; | |
chacha_stream(out, inlen, nonce, key, keybits, 8); | |
for (i = 0; i < inlen; ++i) out[i] ^= in[i]; | |
} | |
void chacha12_encrypt(unsigned char *out, const unsigned char *in, int inlen, | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits) { | |
int i; | |
chacha_stream(out, inlen, nonce, key, keybits, 12); | |
for (i = 0; i < inlen; ++i) out[i] ^= in[i]; | |
} | |
void chacha20_encrypt(unsigned char *out, const unsigned char *in, int inlen, | |
const unsigned char *nonce, | |
const unsigned char *key, int keybits) { | |
int i; | |
chacha_stream(out, inlen, nonce, key, keybits, 20); | |
for (i = 0; i < inlen; ++i) out[i] ^= in[i]; | |
} | |
#undef ROTL32 | |
#undef LOAD_LE32 | |
#undef STORE_LE32 | |
#undef QUARTERROUND |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CRYPTRAND_H | |
#define CRYPTRAND_H | |
#ifdef _WIN32 | |
#include <windows.h> | |
#include <wincrypt.h> | |
#else | |
#include <stdio.h> | |
#endif | |
inline int cryptrand(unsigned char *out, int outlen) { | |
#ifdef _WIN32 | |
HCRYPTPROV prov; | |
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { | |
return 1; | |
} | |
if (!CryptGenRandom(prov, outlen, seed)) { | |
CryptReleaseContext(prov, 0); | |
return 1; | |
} | |
CryptReleaseContext(prov, 0); | |
#else | |
FILE *f = fopen("/dev/urandom", "rb"); | |
if (f == NULL) { | |
return 1; | |
} | |
fread(seed, 1, outlen, f); | |
fclose(f); | |
#endif | |
return 0; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment