mirror of https://github.com/PurpleI2P/i2pd
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
4.9 KiB
C++
252 lines
4.9 KiB
C++
#include "Poly1305.h"
|
|
/**
|
|
This code is licensed under the MCGSI Public License
|
|
Copyright 2018 Jeff Becker
|
|
|
|
Kovri go write your own code
|
|
|
|
*/
|
|
namespace i2p
|
|
{
|
|
namespace crypto
|
|
{
|
|
namespace poly1305
|
|
{
|
|
|
|
struct LongBlock
|
|
{
|
|
unsigned long data[17];
|
|
operator unsigned long * ()
|
|
{
|
|
return data;
|
|
}
|
|
};
|
|
|
|
struct Block
|
|
{
|
|
unsigned char data[17];
|
|
|
|
operator uint8_t * ()
|
|
{
|
|
return data;
|
|
}
|
|
|
|
Block & operator += (const Block & other)
|
|
{
|
|
unsigned short u;
|
|
unsigned int i;
|
|
for(u = 0, i = 0; i < 17; i++)
|
|
{
|
|
u += (unsigned short) data[i] + (unsigned short) other.data[i];
|
|
data[i] = (unsigned char) u & 0xff;
|
|
u >>= 8;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
Block & operator %=(const LongBlock & other)
|
|
{
|
|
unsigned long u;
|
|
unsigned int i;
|
|
u = 0;
|
|
for (i = 0; i < 16; i++) {
|
|
u += other.data[i];
|
|
data[i] = (unsigned char)u & 0xff;
|
|
u >>= 8;
|
|
}
|
|
u += other.data[16];
|
|
data[16] = (unsigned char)u & 0x03;
|
|
u >>= 2;
|
|
u += (u << 2);
|
|
for (i = 0; i < 16; i++) {
|
|
u += data[i];
|
|
data[i] = (unsigned char)u & 0xff;
|
|
u >>= 8;
|
|
}
|
|
data[16] += (unsigned char)u;
|
|
return *this;
|
|
}
|
|
|
|
Block & operator = (const Block & other)
|
|
{
|
|
memcpy(data, other.data, sizeof(data));
|
|
return *this;
|
|
}
|
|
|
|
Block & operator ~ ()
|
|
{
|
|
static const Block minusp = {
|
|
0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0xfc
|
|
};
|
|
Block orig;
|
|
unsigned char neg;
|
|
unsigned int i;
|
|
orig = *this;
|
|
*this += minusp;
|
|
neg = -(data[16] >> 7);
|
|
for(i = 0; i < 17; i++)
|
|
data[i] ^= neg & (orig.data[i] ^ data[i]);
|
|
|
|
return *this;
|
|
}
|
|
|
|
void PutKey(const uint8_t * key)
|
|
{
|
|
data[0] = key[0] & 0xff;
|
|
data[1] = key[1] & 0xff;
|
|
data[2] = key[2] & 0xff;
|
|
data[3] = key[3] & 0x0f;
|
|
data[4] = key[4] & 0xfc;
|
|
data[5] = key[5] & 0xff;
|
|
data[6] = key[6] & 0xff;
|
|
data[7] = key[7] & 0x0f;
|
|
data[8] = key[8] & 0xfc;
|
|
data[9] = key[9] & 0xff;
|
|
data[10] = key[10] & 0xff;
|
|
data[11] = key[11] & 0x0f;
|
|
data[12] = key[12] & 0xfc;
|
|
data[13] = key[13] & 0xff;
|
|
data[14] = key[14] & 0xff;
|
|
data[15] = key[15] & 0x0f;
|
|
data[16] = 0;
|
|
}
|
|
|
|
void Put(const uint8_t * d, uint8_t last=0)
|
|
{
|
|
memcpy(data, d, 17);
|
|
data[16] = last;
|
|
}
|
|
};
|
|
|
|
struct Buffer
|
|
{
|
|
uint8_t data[POLY1305_BLOCK_BYTES];
|
|
|
|
operator uint8_t * ()
|
|
{
|
|
return data;
|
|
}
|
|
};
|
|
}
|
|
|
|
struct Poly1305
|
|
{
|
|
#if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) // older than gcc 4.8
|
|
Poly1305(const uint8_t * key) : m_Leftover(0), m_Final(0)
|
|
{
|
|
memset (m_H, 0, sizeof (m_H));
|
|
#else
|
|
Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0)
|
|
{
|
|
#endif
|
|
m_R.PutKey(key);
|
|
m_Pad.Put(key + 16);
|
|
}
|
|
|
|
void Update(const uint8_t * buf, size_t sz)
|
|
{
|
|
// process leftover
|
|
if(m_Leftover)
|
|
{
|
|
size_t want = POLY1305_BLOCK_BYTES - m_Leftover;
|
|
if(want > sz) want = sz;
|
|
memcpy(m_Buffer + m_Leftover, buf, want);
|
|
sz -= want;
|
|
buf += want;
|
|
m_Leftover += want;
|
|
if(m_Leftover < POLY1305_BLOCK_BYTES) return;
|
|
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
|
m_Leftover = 0;
|
|
}
|
|
// process blocks
|
|
if(sz >= POLY1305_BLOCK_BYTES)
|
|
{
|
|
size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1));
|
|
Blocks(buf, want);
|
|
buf += want;
|
|
sz -= want;
|
|
}
|
|
// leftover
|
|
if(sz)
|
|
{
|
|
memcpy(m_Buffer+m_Leftover, buf, sz);
|
|
m_Leftover += sz;
|
|
}
|
|
}
|
|
|
|
void Blocks(const uint8_t * buf, size_t sz)
|
|
{
|
|
const unsigned char hi = m_Final ^ 1;
|
|
while (sz >= POLY1305_BLOCK_BYTES) {
|
|
|
|
unsigned long u;
|
|
|
|
unsigned int i, j;
|
|
m_Msg.Put(buf, hi);
|
|
/* h += m */
|
|
m_H += m_Msg;
|
|
|
|
/* h *= r */
|
|
for (i = 0; i < 17; i++) {
|
|
u = 0;
|
|
for (j = 0; j <= i ; j++) {
|
|
u += (unsigned short)m_H.data[j] * m_R.data[i - j];
|
|
}
|
|
for (j = i + 1; j < 17; j++) {
|
|
unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j];
|
|
v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */
|
|
u += v;
|
|
}
|
|
m_HR[i] = u;
|
|
}
|
|
/* (partial) h %= p */
|
|
m_H %= m_HR;
|
|
buf += POLY1305_BLOCK_BYTES;
|
|
sz -= POLY1305_BLOCK_BYTES;
|
|
}
|
|
}
|
|
|
|
void Finish(uint32_t *& out)
|
|
{
|
|
// process leftovers
|
|
if(m_Leftover)
|
|
{
|
|
size_t idx = m_Leftover;
|
|
m_Buffer[idx++] = 1;
|
|
for(; idx < POLY1305_BLOCK_BYTES; idx++)
|
|
m_Buffer[idx] = 0;
|
|
m_Final = 1;
|
|
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
|
}
|
|
|
|
// freeze H
|
|
~m_H;
|
|
// add pad
|
|
m_H += m_Pad;
|
|
// copy digest
|
|
memcpy(out, m_H, 16);
|
|
}
|
|
|
|
size_t m_Leftover;
|
|
poly1305::Buffer m_Buffer;
|
|
poly1305::Block m_H;
|
|
poly1305::Block m_R;
|
|
poly1305::Block m_Pad;
|
|
poly1305::Block m_Msg;
|
|
poly1305::LongBlock m_HR;
|
|
uint8_t m_Final;
|
|
|
|
};
|
|
|
|
void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz)
|
|
{
|
|
const uint8_t * k = (const uint8_t *) key;
|
|
Poly1305 p(k);
|
|
p.Update(buf, sz);
|
|
p.Finish(out);
|
|
}
|
|
}
|
|
}
|