137 lines
No EOL
3.9 KiB
C
137 lines
No EOL
3.9 KiB
C
#ifdef _WIN32
|
|
# include <sys/param.h>
|
|
# if BYTE_ORDER == LITTLE_ENDIAN
|
|
# define htole32(x) (x)
|
|
# else
|
|
# define htole32(x) __builtin_bswap32(x)
|
|
# endif
|
|
#else
|
|
# include <endian.h>
|
|
#endif /* _WIN32 */
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include "chacha.h"
|
|
|
|
void
|
|
chacha_init(struct chacha_ctx *ctx, const uint8_t key[CHACHA_KEY_BYTES],
|
|
const uint32_t ctr, const uint8_t nonce[CHACHA_NONCE_BYTES])
|
|
{
|
|
ctx->ctr = ctr;
|
|
ctx->state[0][0] = TO_LE_32(CHACHA_CONST1);
|
|
ctx->state[0][1] = TO_LE_32(CHACHA_CONST2);
|
|
ctx->state[0][2] = TO_LE_32(CHACHA_CONST3);
|
|
ctx->state[0][3] = TO_LE_32(CHACHA_CONST4);
|
|
|
|
ctx->state[1][0] = TO_LE_32(key);
|
|
ctx->state[1][1] = TO_LE_32(key + 4);
|
|
ctx->state[1][2] = TO_LE_32(key + 4 * 2);
|
|
ctx->state[1][3] = TO_LE_32(key + 4 * 3);
|
|
|
|
ctx->state[2][0] = TO_LE_32(key + 16);
|
|
ctx->state[2][1] = TO_LE_32(key + 16 + 4);
|
|
ctx->state[2][2] = TO_LE_32(key + 16 + 4 * 2);
|
|
ctx->state[2][3] = TO_LE_32(key + 16 + 4 * 3);
|
|
|
|
ctx->state[3][0] = htole32(ctx->ctr);
|
|
|
|
ctx->state[3][1] = TO_LE_32(nonce);
|
|
ctx->state[3][2] = TO_LE_32(nonce + 4);
|
|
ctx->state[3][3] = TO_LE_32(nonce + 4 * 2);
|
|
}
|
|
|
|
void
|
|
chacha_block(struct chacha_ctx *ctx, uint8_t *out, int round)
|
|
{
|
|
int idx;
|
|
uint32_t tmp[4][4];
|
|
|
|
for (idx = 0; idx < 4; idx++)
|
|
{
|
|
tmp[idx][0] = ctx->state[idx][0];
|
|
tmp[idx][1] = ctx->state[idx][1];
|
|
tmp[idx][2] = ctx->state[idx][2];
|
|
tmp[idx][3] = ctx->state[idx][3];
|
|
}
|
|
|
|
for (idx = 0; idx < round/2; idx++)
|
|
{
|
|
CHACHA_QUARTERROUND(tmp[0][0], tmp[1][0], tmp[2][0], tmp[3][0]);
|
|
CHACHA_QUARTERROUND(tmp[0][1], tmp[1][1], tmp[2][1], tmp[3][1]);
|
|
CHACHA_QUARTERROUND(tmp[0][2], tmp[1][2], tmp[2][2], tmp[3][2]);
|
|
CHACHA_QUARTERROUND(tmp[0][3], tmp[1][3], tmp[2][3], tmp[3][3]);
|
|
|
|
CHACHA_QUARTERROUND(tmp[0][0], tmp[1][1], tmp[2][2], tmp[3][3]);
|
|
CHACHA_QUARTERROUND(tmp[0][1], tmp[1][2], tmp[2][3], tmp[3][0]);
|
|
CHACHA_QUARTERROUND(tmp[0][2], tmp[1][3], tmp[2][0], tmp[3][1]);
|
|
CHACHA_QUARTERROUND(tmp[0][3], tmp[1][0], tmp[2][1], tmp[3][2]);
|
|
}
|
|
|
|
*(uint32_t *)(out + 0) = htole32(tmp[0][0] + ctx->state[0][0]);
|
|
*(uint32_t *)(out + 4) = htole32(tmp[0][1] + ctx->state[0][1]);
|
|
*(uint32_t *)(out + 8) = htole32(tmp[0][2] + ctx->state[0][2]);
|
|
*(uint32_t *)(out + 12) = htole32(tmp[0][3] + ctx->state[0][3]);
|
|
|
|
*(uint32_t *)(out + 16) = htole32(tmp[1][0] + ctx->state[1][0]);
|
|
*(uint32_t *)(out + 20) = htole32(tmp[1][1] + ctx->state[1][1]);
|
|
*(uint32_t *)(out + 24) = htole32(tmp[1][2] + ctx->state[1][2]);
|
|
*(uint32_t *)(out + 28) = htole32(tmp[1][3] + ctx->state[1][3]);
|
|
|
|
*(uint32_t *)(out + 32) = htole32(tmp[2][0] + ctx->state[2][0]);
|
|
*(uint32_t *)(out + 36) = htole32(tmp[2][1] + ctx->state[2][1]);
|
|
*(uint32_t *)(out + 40) = htole32(tmp[2][2] + ctx->state[2][2]);
|
|
*(uint32_t *)(out + 44) = htole32(tmp[2][3] + ctx->state[2][3]);
|
|
|
|
*(uint32_t *)(out + 48) = htole32(tmp[3][0] + ctx->state[3][0]);
|
|
*(uint32_t *)(out + 52) = htole32(tmp[3][1] + ctx->state[3][1]);
|
|
*(uint32_t *)(out + 56) = htole32(tmp[3][2] + ctx->state[3][2]);
|
|
*(uint32_t *)(out + 60) = htole32(tmp[3][3] + ctx->state[3][3]);
|
|
|
|
ctx->ctr++;
|
|
ctx->state[3][0] = htole32(ctx->ctr);
|
|
}
|
|
|
|
void
|
|
chacha_encrypt(struct chacha_ctx *ctx, uint8_t *out, uint8_t *in, size_t inlen, int round)
|
|
{
|
|
size_t i;
|
|
size_t j;
|
|
uint8_t block[CHACHA_BLOCK_BYTES];
|
|
|
|
chacha_block(ctx, block, round);
|
|
for (i = 0, j = 0; i < inlen; i++, j++)
|
|
{
|
|
if (j >= CHACHA_BLOCK_BYTES)
|
|
{
|
|
j = 0;
|
|
chacha_block(ctx, block, round);
|
|
}
|
|
|
|
out[i] = in[i] ^ block[j];
|
|
}
|
|
}
|
|
|
|
void
|
|
xchacha(uint8_t *out, uint8_t key[CHACHA_KEY_BYTES], uint8_t nonce[24],
|
|
uint8_t *in, size_t inlen, int round)
|
|
{
|
|
uint8_t subkey[CHACHA_KEY_BYTES];
|
|
uint8_t tmp[12];
|
|
struct chacha_ctx ctx;
|
|
|
|
hchacha(subkey, key, nonce, round);
|
|
|
|
memset(tmp, 0, 12);
|
|
memcpy(tmp + 4, nonce + 16, 8);
|
|
|
|
chacha_init(&ctx, subkey, 1, tmp);
|
|
|
|
chacha_encrypt(&ctx, out, in, inlen, round);
|
|
}
|
|
|
|
void
|
|
xchacha12(uint8_t *out, uint8_t key[CHACHA_KEY_BYTES], uint8_t nonce[24],
|
|
uint8_t *in, size_t inlen)
|
|
{
|
|
xchacha(out, key, nonce, in, inlen, 12);
|
|
} |