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.
279 lines
10 KiB
279 lines
10 KiB
// hc128.cpp - written and placed in the public domain by Jeffrey Walton |
|
// based on public domain code by Hongjun Wu. |
|
// |
|
// The reference materials and source files are available at |
|
// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-hc128.html. |
|
|
|
#include "pch.h" |
|
#include "config.h" |
|
|
|
#include "hc128.h" |
|
#include "secblock.h" |
|
#include "misc.h" |
|
|
|
/*h1 function*/ |
|
#define h1(x, y) { \ |
|
byte a,c; \ |
|
a = (byte) (x); \ |
|
c = (byte) ((x) >> 16); \ |
|
y = (m_T[512+a])+(m_T[512+256+c]); \ |
|
} |
|
|
|
/*h2 function*/ |
|
#define h2(x, y) { \ |
|
byte a,c; \ |
|
a = (byte) (x); \ |
|
c = (byte) ((x) >> 16); \ |
|
y = (m_T[a])+(m_T[256+c]); \ |
|
} |
|
|
|
/*one step of HC-128, update P and generate 32 bits keystream*/ |
|
#define step_P(u,v,a,b,c,d,n){ \ |
|
word32 tem0,tem1,tem2,tem3; \ |
|
h1(m_X[(d)],tem3); \ |
|
tem0 = rotrConstant<23>(m_T[(v)]); \ |
|
tem1 = rotrConstant<10>(m_X[(c)]); \ |
|
tem2 = rotrConstant<8>(m_X[(b)]); \ |
|
(m_T[(u)]) += tem2+(tem0 ^ tem1); \ |
|
(m_X[(a)]) = (m_T[(u)]); \ |
|
(n) = tem3 ^ (m_T[(u)]); \ |
|
} |
|
|
|
/*one step of HC-128, update Q and generate 32 bits keystream*/ |
|
#define step_Q(u,v,a,b,c,d,n){ \ |
|
word32 tem0,tem1,tem2,tem3; \ |
|
h2(m_Y[(d)],tem3); \ |
|
tem0 = rotrConstant<(32-23)>(m_T[(v)]); \ |
|
tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \ |
|
tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \ |
|
(m_T[(u)]) += tem2 + (tem0 ^ tem1); \ |
|
(m_Y[(a)]) = (m_T[(u)]); \ |
|
(n) = tem3 ^ (m_T[(u)]) ; \ |
|
} |
|
|
|
/*update table P*/ |
|
#define update_P(u,v,a,b,c,d){ \ |
|
word32 tem0,tem1,tem2,tem3; \ |
|
tem0 = rotrConstant<23>(m_T[(v)]); \ |
|
tem1 = rotrConstant<10>(m_X[(c)]); \ |
|
tem2 = rotrConstant<8>(m_X[(b)]); \ |
|
h1(m_X[(d)],tem3); \ |
|
(m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ |
|
(m_X[(a)]) = (m_T[(u)]); \ |
|
} |
|
|
|
/*update table Q*/ |
|
#define update_Q(u,v,a,b,c,d){ \ |
|
word32 tem0,tem1,tem2,tem3; \ |
|
tem0 = rotrConstant<(32-23)>(m_T[(v)]); \ |
|
tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \ |
|
tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \ |
|
h2(m_Y[(d)],tem3); \ |
|
(m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ |
|
(m_Y[(a)]) = (m_T[(u)]); \ |
|
} |
|
|
|
ANONYMOUS_NAMESPACE_BEGIN |
|
|
|
using CryptoPP::word32; |
|
using CryptoPP::rotrConstant; |
|
|
|
inline word32 f1(word32 x) |
|
{ |
|
return rotrConstant<7>(x) ^ rotrConstant<18>(x) ^ ((x) >> 3); |
|
} |
|
|
|
inline word32 f2(word32 x) |
|
{ |
|
return rotrConstant<17>(x) ^ rotrConstant<19>(x) ^ ((x) >> 10); |
|
} |
|
|
|
ANONYMOUS_NAMESPACE_END |
|
|
|
NAMESPACE_BEGIN(CryptoPP) |
|
|
|
/*16 steps of HC-128, generate 512 bits keystream*/ |
|
void HC128Policy::GenerateKeystream(word32 keystream[16]) |
|
{ |
|
unsigned int cc = m_ctr & 0x1ff; |
|
unsigned int dd = (cc + 16) & 0x1ff; |
|
|
|
if (m_ctr < 512) |
|
{ |
|
m_ctr = (m_ctr + 16) & 0x3ff; |
|
step_P(cc + 0, cc + 1, 0, 6, 13, 4, keystream[0]); |
|
step_P(cc + 1, cc + 2, 1, 7, 14, 5, keystream[1]); |
|
step_P(cc + 2, cc + 3, 2, 8, 15, 6, keystream[2]); |
|
step_P(cc + 3, cc + 4, 3, 9, 0, 7, keystream[3]); |
|
step_P(cc + 4, cc + 5, 4, 10, 1, 8, keystream[4]); |
|
step_P(cc + 5, cc + 6, 5, 11, 2, 9, keystream[5]); |
|
step_P(cc + 6, cc + 7, 6, 12, 3, 10, keystream[6]); |
|
step_P(cc + 7, cc + 8, 7, 13, 4, 11, keystream[7]); |
|
step_P(cc + 8, cc + 9, 8, 14, 5, 12, keystream[8]); |
|
step_P(cc + 9, cc + 10, 9, 15, 6, 13, keystream[9]); |
|
step_P(cc + 10, cc + 11, 10, 0, 7, 14, keystream[10]); |
|
step_P(cc + 11, cc + 12, 11, 1, 8, 15, keystream[11]); |
|
step_P(cc + 12, cc + 13, 12, 2, 9, 0, keystream[12]); |
|
step_P(cc + 13, cc + 14, 13, 3, 10, 1, keystream[13]); |
|
step_P(cc + 14, cc + 15, 14, 4, 11, 2, keystream[14]); |
|
step_P(cc + 15, dd + 0, 15, 5, 12, 3, keystream[15]); |
|
} |
|
else |
|
{ |
|
m_ctr = (m_ctr + 16) & 0x3ff; |
|
step_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4, keystream[0]); |
|
step_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5, keystream[1]); |
|
step_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6, keystream[2]); |
|
step_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7, keystream[3]); |
|
step_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8, keystream[4]); |
|
step_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9, keystream[5]); |
|
step_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10, keystream[6]); |
|
step_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11, keystream[7]); |
|
step_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12, keystream[8]); |
|
step_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13, keystream[9]); |
|
step_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14, keystream[10]); |
|
step_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15, keystream[11]); |
|
step_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0, keystream[12]); |
|
step_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1, keystream[13]); |
|
step_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2, keystream[14]); |
|
step_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3, keystream[15]); |
|
} |
|
} |
|
|
|
/*16 steps of HC-128, without generating keystream, */ |
|
/*but use the outputs to update P and Q*/ |
|
void HC128Policy::SetupUpdate() /*each time 16 steps*/ |
|
{ |
|
unsigned int cc = m_ctr & 0x1ff; |
|
unsigned int dd = (cc + 16) & 0x1ff; |
|
|
|
if (m_ctr < 512) |
|
{ |
|
m_ctr = (m_ctr + 16) & 0x3ff; |
|
update_P(cc + 0, cc + 1, 0, 6, 13, 4); |
|
update_P(cc + 1, cc + 2, 1, 7, 14, 5); |
|
update_P(cc + 2, cc + 3, 2, 8, 15, 6); |
|
update_P(cc + 3, cc + 4, 3, 9, 0, 7); |
|
update_P(cc + 4, cc + 5, 4, 10, 1, 8); |
|
update_P(cc + 5, cc + 6, 5, 11, 2, 9); |
|
update_P(cc + 6, cc + 7, 6, 12, 3, 10); |
|
update_P(cc + 7, cc + 8, 7, 13, 4, 11); |
|
update_P(cc + 8, cc + 9, 8, 14, 5, 12); |
|
update_P(cc + 9, cc + 10, 9, 15, 6, 13); |
|
update_P(cc + 10, cc + 11, 10, 0, 7, 14); |
|
update_P(cc + 11, cc + 12, 11, 1, 8, 15); |
|
update_P(cc + 12, cc + 13, 12, 2, 9, 0); |
|
update_P(cc + 13, cc + 14, 13, 3, 10, 1); |
|
update_P(cc + 14, cc + 15, 14, 4, 11, 2); |
|
update_P(cc + 15, dd + 0, 15, 5, 12, 3); |
|
} |
|
else |
|
{ |
|
m_ctr = (m_ctr + 16) & 0x3ff; |
|
update_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4); |
|
update_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5); |
|
update_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6); |
|
update_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7); |
|
update_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8); |
|
update_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9); |
|
update_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10); |
|
update_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11); |
|
update_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12); |
|
update_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13); |
|
update_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14); |
|
update_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15); |
|
update_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0); |
|
update_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1); |
|
update_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2); |
|
update_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3); |
|
} |
|
} |
|
|
|
void HC128Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *userKey, size_t keylen) |
|
{ |
|
CRYPTOPP_UNUSED(params); |
|
|
|
GetUserKey(LITTLE_ENDIAN_ORDER, m_key.begin(), 4, userKey, keylen); |
|
for (unsigned int i = 4; i < 8; i++) |
|
m_key[i] = m_key[i - 4]; |
|
} |
|
|
|
void HC128Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) |
|
{ |
|
while (iterationCount--) |
|
{ |
|
word32 keystream[16]; |
|
GenerateKeystream(keystream); |
|
|
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 0, keystream[0]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 4, keystream[1]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 8, keystream[2]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 12, keystream[3]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 16, keystream[4]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 20, keystream[5]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 24, keystream[6]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 28, keystream[7]); |
|
|
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 32, keystream[8]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 36, keystream[9]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 40, keystream[10]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 44, keystream[11]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 48, keystream[12]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 52, keystream[13]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 56, keystream[14]); |
|
PutWord(false, LITTLE_ENDIAN_ORDER, output + 60, keystream[15]); |
|
|
|
// If AdditiveCipherTemplate does not have an accumulated keystream |
|
// then it will ask OperateKeystream to generate one. Optionally it |
|
// will ask for an XOR of the input with the keystream while |
|
// writing the result to the output buffer. In all cases the |
|
// keystream is written to the output buffer. The optional part is |
|
// adding the input buffer and keystream. |
|
if ((operation & INPUT_NULL) != INPUT_NULL) |
|
{ |
|
xorbuf(output, input, BYTES_PER_ITERATION); |
|
input += BYTES_PER_ITERATION; |
|
} |
|
|
|
output += BYTES_PER_ITERATION; |
|
} |
|
} |
|
|
|
void HC128Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) |
|
{ |
|
CRYPTOPP_UNUSED(keystreamBuffer); |
|
|
|
GetUserKey(LITTLE_ENDIAN_ORDER, m_iv.begin(), 4, iv, length); |
|
for (unsigned int i = 4; i < 8; i++) |
|
m_iv[i] = m_iv[i - 4]; |
|
|
|
/* expand the key and IV into the table T */ |
|
/* (expand the key and IV into the table P and Q) */ |
|
|
|
for (unsigned int i = 0; i < 8; i++) |
|
m_T[i] = m_key[i]; |
|
for (unsigned int i = 8; i < 16; i++) |
|
m_T[i] = m_iv[i - 8]; |
|
|
|
for (unsigned int i = 16; i < (256 + 16); i++) |
|
m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + i; |
|
|
|
for (unsigned int i = 0; i < 16; i++) |
|
m_T[i] = m_T[256 + i]; |
|
|
|
for (unsigned int i = 16; i < 1024; i++) |
|
m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + 256 + i; |
|
|
|
/* initialize counter1024, X and Y */ |
|
m_ctr = 0; |
|
for (unsigned int i = 0; i < 16; i++) |
|
m_X[i] = m_T[512 - 16 + i]; |
|
for (unsigned int i = 0; i < 16; i++) |
|
m_Y[i] = m_T[512 + 512 - 16 + i]; |
|
|
|
/* run the cipher 1024 steps before generating the output */ |
|
for (unsigned int i = 0; i < 64; i++) |
|
SetupUpdate(); |
|
} |
|
|
|
NAMESPACE_END
|
|
|