i2pd/libi2pd/ChaCha20.cpp
Anatolii Cherednichenko 55534ea002 Reformat code
2022-08-30 02:11:28 +03:00

124 lines
4.2 KiB
C++

/*
* Copyright (c) 2013-2020, 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 "I2PEndian.h"
#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] = htole32 (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] = htole32 (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
} // namespace crypto
} // namespace i2p
#endif