mirror of https://github.com/PurpleI2P/i2pd.git
I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
2.9 KiB
137 lines
2.9 KiB
/* |
|
* Copyright (c) 2013-2018, The PurpleI2P Project |
|
* |
|
* This file is part of Purple i2pd project and licensed under BSD3 |
|
* |
|
* See full license text in LICENSE file at top of project tree |
|
* |
|
* Kovri go write your own code |
|
* |
|
*/ |
|
|
|
#include "ChaCha20.h" |
|
|
|
#if !OPENSSL_AEAD_CHACHA20_POLY1305 |
|
namespace i2p |
|
{ |
|
namespace crypto |
|
{ |
|
namespace chacha |
|
{ |
|
void u32t8le(uint32_t v, uint8_t * p) |
|
{ |
|
p[0] = v & 0xff; |
|
p[1] = (v >> 8) & 0xff; |
|
p[2] = (v >> 16) & 0xff; |
|
p[3] = (v >> 24) & 0xff; |
|
} |
|
|
|
uint32_t u8t32le(const uint8_t * p) |
|
{ |
|
uint32_t value = p[3]; |
|
|
|
value = (value << 8) | p[2]; |
|
value = (value << 8) | p[1]; |
|
value = (value << 8) | p[0]; |
|
|
|
return value; |
|
} |
|
|
|
uint32_t rotl32(uint32_t x, int n) |
|
{ |
|
return x << n | (x >> (-n & 31)); |
|
} |
|
|
|
void quarterround(uint32_t *x, int a, int b, int c, int d) |
|
{ |
|
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); |
|
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); |
|
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); |
|
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); |
|
} |
|
|
|
|
|
void Chacha20Block::operator << (const Chacha20State & st) |
|
{ |
|
int i; |
|
for (i = 0; i < 16; i++) |
|
u32t8le(st.data[i], data + (i << 2)); |
|
} |
|
|
|
void block (Chacha20State &input, int rounds) |
|
{ |
|
int i; |
|
Chacha20State x; |
|
x.Copy(input); |
|
|
|
for (i = rounds; i > 0; i -= 2) |
|
{ |
|
quarterround(x.data, 0, 4, 8, 12); |
|
quarterround(x.data, 1, 5, 9, 13); |
|
quarterround(x.data, 2, 6, 10, 14); |
|
quarterround(x.data, 3, 7, 11, 15); |
|
quarterround(x.data, 0, 5, 10, 15); |
|
quarterround(x.data, 1, 6, 11, 12); |
|
quarterround(x.data, 2, 7, 8, 13); |
|
quarterround(x.data, 3, 4, 9, 14); |
|
} |
|
x += input; |
|
input.block << x; |
|
|
|
} |
|
|
|
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter) |
|
{ |
|
state.data[0] = 0x61707865; |
|
state.data[1] = 0x3320646e; |
|
state.data[2] = 0x79622d32; |
|
state.data[3] = 0x6b206574; |
|
for (size_t i = 0; i < 8; i++) |
|
state.data[4 + i] = chacha::u8t32le(key + i * 4); |
|
|
|
state.data[12] = counter; |
|
for (size_t i = 0; i < 3; i++) |
|
state.data[13 + i] = chacha::u8t32le(nonce + i * 4); |
|
} |
|
|
|
void Chacha20SetCounter (Chacha20State& state, uint32_t counter) |
|
{ |
|
state.data[12] = counter; |
|
state.offset = 0; |
|
} |
|
|
|
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz) |
|
{ |
|
if (state.offset > 0) |
|
{ |
|
// previous block if any |
|
auto s = chacha::blocksize - state.offset; |
|
if (sz < s) s = sz; |
|
for (size_t i = 0; i < s; i++) |
|
buf[i] ^= state.block.data[state.offset + i]; |
|
buf += s; |
|
sz -= s; |
|
state.offset += s; |
|
if (state.offset >= chacha::blocksize) state.offset = 0; |
|
} |
|
for (size_t i = 0; i < sz; i += chacha::blocksize) |
|
{ |
|
chacha::block(state, chacha::rounds); |
|
state.data[12]++; |
|
for (size_t j = i; j < i + chacha::blocksize; j++) |
|
{ |
|
if (j >= sz) |
|
{ |
|
state.offset = j & 0x3F; // % 64 |
|
break; |
|
} |
|
buf[j] ^= state.block.data[j - i]; |
|
} |
|
} |
|
} |
|
} // namespace chacha |
|
|
|
} |
|
} |
|
#endif |
|
|
|
|