summaryrefslogtreecommitdiff
path: root/hc128.cpp
diff options
context:
space:
mode:
authorJeffrey Walton <noloader@gmail.com>2018-07-05 00:29:07 -0400
committerJeffrey Walton <noloader@gmail.com>2018-07-05 00:29:07 -0400
commitdd31eb80c001d4571f89eb2be52dbdc022c60ae9 (patch)
tree82eb884f4044984ec8d394316deebc5fe2cbf0ce /hc128.cpp
parent93f46e43025a2ea36ec5c64eeb901e88ad1add38 (diff)
downloadcryptopp-git-dd31eb80c001d4571f89eb2be52dbdc022c60ae9.tar.gz
Add HC-128 stream cipher (GH #679)
Diffstat (limited to 'hc128.cpp')
-rw-r--r--hc128.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/hc128.cpp b/hc128.cpp
new file mode 100644
index 00000000..4d8759a6
--- /dev/null
+++ b/hc128.cpp
@@ -0,0 +1,277 @@
+// 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"
+
+#define u8 byte
+#define u32 word32
+
+/*h1 function*/
+#define h1(x, y) { \
+ u8 a,c; \
+ a = (u8) (x); \
+ c = (u8) ((x) >> 16); \
+ y = (m_T[512+a])+(m_T[512+256+c]); \
+}
+
+/*h2 function*/
+#define h2(x, y) { \
+ u8 a,c; \
+ a = (u8) (x); \
+ c = (u8) ((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 &params, const byte *userKey, size_t keylen)
+{
+ CRYPTOPP_UNUSED(params);
+
+ GetUserKey(LITTLE_ENDIAN_ORDER, m_key, 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)
+{
+ size_t msglen = GetBytesPerIteration() * iterationCount;
+ while (msglen >= 64)
+ {
+ 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 acculated keystream
+ // then it will ask OperateKeystream to XOR the plaintext with
+ // the keystream and write it to the ciphertext buffer.
+ if ((operation & INPUT_NULL) != INPUT_NULL)
+ xorbuf(output, input, 64);
+
+ msglen -= 64; input += 64; output += 64;
+ }
+}
+
+void HC128Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
+{
+ CRYPTOPP_UNUSED(keystreamBuffer);
+
+ GetUserKey(LITTLE_ENDIAN_ORDER, m_iv, 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