Browse Source

correct chacha20 for multiple messages

pull/1274/head
orignal 6 years ago
parent
commit
ef6db64e9f
  1. 96
      libi2pd/ChaCha20.cpp
  2. 29
      libi2pd/ChaCha20.h
  3. 6
      libi2pd/Crypto.cpp
  4. 2
      tests/test-aeadchacha20poly1305.cpp

96
libi2pd/ChaCha20.cpp

@ -15,9 +15,6 @@ namespace crypto
{ {
namespace chacha namespace chacha
{ {
constexpr int rounds = 20;
constexpr std::size_t blocksize = 64;
void u32t8le(uint32_t v, uint8_t * p) void u32t8le(uint32_t v, uint8_t * p)
{ {
p[0] = v & 0xff; p[0] = v & 0xff;
@ -51,22 +48,14 @@ void quarterround(uint32_t *x, int a, int b, int c, int d)
} }
struct Block_t void Chacha20Block::operator << (const Chacha20State & st)
{ {
Block_t() {}; int i;
Block_t(Block_t &&) = delete; for (i = 0; i < 16; i++)
u32t8le(st.data[i], data + (i << 2));
uint8_t data[blocksize]; }
void 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; int i;
Chacha20State x; Chacha20State x;
@ -84,45 +73,60 @@ void block(const Chacha20State &input, Block_t & block, int rounds)
quarterround(x.data, 3, 4, 9, 14); quarterround(x.data, 3, 4, 9, 14);
} }
x += input; x += input;
block << x; input.block << x;
} }
} // namespace chacha
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter) 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 Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
{
if (state.offset > 0)
{ {
state.data[0] = 0x61707865; // previous block if any
state.data[1] = 0x3320646e; auto s = chacha::blocksize - state.offset;
state.data[2] = 0x79622d32; if (sz < s) s = sz;
state.data[3] = 0x6b206574; for (size_t i = 0; i < s; i++)
for (size_t i = 0; i < 8; i++) buf[i] ^= state.block.data[state.offset + i];
state.data[4 + i] = chacha::u8t32le(key + i * 4); buf += s;
sz -= s;
state.data[12] = counter; state.offset = 0;
for (size_t i = 0; i < 3; i++)
state.data[13 + i] = chacha::u8t32le(nonce + i * 4);
} }
for (size_t i = 0; i < sz; i += chacha::blocksize)
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
{ {
chacha::Block_t block; chacha::block(state, chacha::rounds);
for (size_t i = 0; i < sz; i += chacha::blocksize) state.data[12]++;
{ for (size_t j = i; j < i + chacha::blocksize; j++)
chacha::block(state, block, chacha::rounds); {
state.data[12]++; if (j >= sz)
for (size_t j = i; j < i + chacha::blocksize; j++) {
{ state.offset = j & 0x3F; // % 64
if (j >= sz) break; break;
buf[j] ^= block.data[j - i]; }
} 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) void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
{ {
Chacha20State state; chacha::Chacha20State state;
Chacha20Init (state, nonce, key, counter); chacha::Chacha20Init (state, nonce, key, counter);
Chacha20Encrypt (state, buf, sz); chacha::Chacha20Encrypt (state, buf, sz);
} }
} }
} }

29
libi2pd/ChaCha20.h

@ -18,12 +18,28 @@ namespace i2p
{ {
namespace crypto namespace crypto
{ {
const std::size_t CHACHA20_KEY_BYTES = 32; const std::size_t CHACHA20_KEY_BYTES = 32;
const std::size_t CHACHA20_NOUNCE_BYTES = 12; 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 struct Chacha20State
{ {
Chacha20State () {}; Chacha20State (): offset (0) {};
Chacha20State (Chacha20State &&) = delete; Chacha20State (Chacha20State &&) = delete;
Chacha20State & operator += (const Chacha20State & other) Chacha20State & operator += (const Chacha20State & other)
@ -38,10 +54,13 @@ namespace crypto
memcpy(data, other.data, sizeof(uint32_t) * 16); memcpy(data, other.data, sizeof(uint32_t) * 16);
} }
uint32_t data[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 Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter);
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz);
}
/** encrypt buf in place with chacha20 */ /** 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); void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter=1);

6
libi2pd/Crypto.cpp

@ -1182,12 +1182,12 @@ namespace crypto
chacha20 ((uint8_t *)polyKey, 64, nonce, key, 0); chacha20 ((uint8_t *)polyKey, 64, nonce, key, 0);
Poly1305 polyHash (polyKey); Poly1305 polyHash (polyKey);
// encrypt buffers // encrypt buffers
Chacha20State state; chacha::Chacha20State state;
Chacha20Init (state, nonce, key, 1); chacha::Chacha20Init (state, nonce, key, 1);
size_t size = 0; size_t size = 0;
for (auto& it: bufs) 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 polyHash.Update ((uint8_t *)it.first, it.second); // after encryption
size += it.second; size += it.second;
} }

2
tests/test-aeadchacha20poly1305.cpp

@ -53,7 +53,7 @@ int main ()
assert (memcmp (buf1, text, 114) == 0); assert (memcmp (buf1, text, 114) == 0);
// test encryption of multiple buffers // test encryption of multiple buffers
memcpy (buf, text, 114); 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::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114);
i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false); i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false);
assert (memcmp (buf1, text, 114) == 0); assert (memcmp (buf1, text, 114) == 0);

Loading…
Cancel
Save