mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-10 00:00:29 +03:00
correct chacha20 for multiple messages
This commit is contained in:
parent
e68f1dbc99
commit
ef6db64e9f
@ -15,9 +15,6 @@ namespace crypto
|
||||
{
|
||||
namespace chacha
|
||||
{
|
||||
constexpr int rounds = 20;
|
||||
constexpr std::size_t blocksize = 64;
|
||||
|
||||
void u32t8le(uint32_t v, uint8_t * p)
|
||||
{
|
||||
p[0] = v & 0xff;
|
||||
@ -51,22 +48,14 @@ void quarterround(uint32_t *x, int a, int b, int c, int d)
|
||||
}
|
||||
|
||||
|
||||
struct Block_t
|
||||
{
|
||||
Block_t() {};
|
||||
Block_t(Block_t &&) = delete;
|
||||
|
||||
uint8_t data[blocksize];
|
||||
|
||||
void operator << (const Chacha20State & st)
|
||||
void Chacha20Block::operator << (const Chacha20State & st)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
u32t8le(st.data[i], data + (i << 2));
|
||||
}
|
||||
};
|
||||
|
||||
void block(const Chacha20State &input, Block_t & block, int rounds)
|
||||
void block (Chacha20State &input, int rounds)
|
||||
{
|
||||
int i;
|
||||
Chacha20State x;
|
||||
@ -84,10 +73,9 @@ void block(const Chacha20State &input, Block_t & block, int rounds)
|
||||
quarterround(x.data, 3, 4, 9, 14);
|
||||
}
|
||||
x += input;
|
||||
block << x;
|
||||
input.block << x;
|
||||
|
||||
}
|
||||
} // namespace chacha
|
||||
|
||||
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
|
||||
{
|
||||
@ -105,24 +93,40 @@ void block(const Chacha20State &input, Block_t & block, int rounds)
|
||||
|
||||
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
|
||||
{
|
||||
chacha::Block_t block;
|
||||
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 = 0;
|
||||
}
|
||||
for (size_t i = 0; i < sz; i += chacha::blocksize)
|
||||
{
|
||||
chacha::block(state, block, chacha::rounds);
|
||||
chacha::block(state, chacha::rounds);
|
||||
state.data[12]++;
|
||||
for (size_t j = i; j < i + chacha::blocksize; j++)
|
||||
{
|
||||
if (j >= sz) break;
|
||||
buf[j] ^= block.data[j - i];
|
||||
if (j >= sz)
|
||||
{
|
||||
state.offset = j & 0x3F; // % 64
|
||||
break;
|
||||
}
|
||||
buf[j] ^= state.block.data[j - i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace chacha
|
||||
|
||||
|
||||
void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
|
||||
{
|
||||
Chacha20State state;
|
||||
Chacha20Init (state, nonce, key, counter);
|
||||
Chacha20Encrypt (state, buf, sz);
|
||||
chacha::Chacha20State state;
|
||||
chacha::Chacha20Init (state, nonce, key, counter);
|
||||
chacha::Chacha20Encrypt (state, buf, sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,25 @@ namespace crypto
|
||||
const std::size_t CHACHA20_KEY_BYTES = 32;
|
||||
const std::size_t CHACHA20_NOUNCE_BYTES = 12;
|
||||
|
||||
namespace chacha
|
||||
{
|
||||
constexpr std::size_t blocksize = 64;
|
||||
constexpr int rounds = 20;
|
||||
|
||||
struct Chacha20State;
|
||||
struct Chacha20Block
|
||||
{
|
||||
Chacha20Block () {};
|
||||
Chacha20Block (Chacha20Block &&) = delete;
|
||||
|
||||
uint8_t data[blocksize];
|
||||
|
||||
void operator << (const Chacha20State & st);
|
||||
};
|
||||
|
||||
struct Chacha20State
|
||||
{
|
||||
Chacha20State () {};
|
||||
Chacha20State (): offset (0) {};
|
||||
Chacha20State (Chacha20State &&) = delete;
|
||||
|
||||
Chacha20State & operator += (const Chacha20State & other)
|
||||
@ -38,10 +54,13 @@ namespace crypto
|
||||
memcpy(data, other.data, sizeof(uint32_t) * 16);
|
||||
}
|
||||
uint32_t data[16];
|
||||
Chacha20Block block;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter);
|
||||
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz);
|
||||
}
|
||||
|
||||
/** encrypt buf in place with chacha20 */
|
||||
void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter=1);
|
||||
|
@ -1182,12 +1182,12 @@ namespace crypto
|
||||
chacha20 ((uint8_t *)polyKey, 64, nonce, key, 0);
|
||||
Poly1305 polyHash (polyKey);
|
||||
// encrypt buffers
|
||||
Chacha20State state;
|
||||
Chacha20Init (state, nonce, key, 1);
|
||||
chacha::Chacha20State state;
|
||||
chacha::Chacha20Init (state, nonce, key, 1);
|
||||
size_t size = 0;
|
||||
for (auto& it: bufs)
|
||||
{
|
||||
Chacha20Encrypt (state, (uint8_t *)it.first, it.second);
|
||||
chacha::Chacha20Encrypt (state, (uint8_t *)it.first, it.second);
|
||||
polyHash.Update ((uint8_t *)it.first, it.second); // after encryption
|
||||
size += it.second;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ int main ()
|
||||
assert (memcmp (buf1, text, 114) == 0);
|
||||
// test encryption of multiple buffers
|
||||
memcpy (buf, text, 114);
|
||||
std::vector<std::pair<void*, std::size_t> > bufs{ std::make_pair (buf, 114) };
|
||||
std::vector<std::pair<void*, std::size_t> > bufs{ std::make_pair (buf, 50), std::make_pair (buf + 50, 50), std::make_pair (buf + 100, 14) };
|
||||
i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114);
|
||||
i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false);
|
||||
assert (memcmp (buf1, text, 114) == 0);
|
||||
|
Loading…
Reference in New Issue
Block a user