Skip to content

Commit

Permalink
Add ChaCha20 encryption option (XOR)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasschnelli committed Mar 3, 2019
1 parent a6d7026 commit b05bb64
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 12 deletions.
28 changes: 27 additions & 1 deletion src/crypto/chacha20.cpp
Expand Up @@ -18,6 +18,8 @@ constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (
a += b; d = rotl32(d ^ a, 8); \
c += d; b = rotl32(b ^ c, 7);

#define XOR(v, w) ((v) ^ (w))

static const unsigned char sigma[] = "expand 32-byte k";
static const unsigned char tau[] = "expand 16-byte k";

Expand Down Expand Up @@ -71,7 +73,7 @@ void ChaCha20::Seek(uint64_t pos)
input[13] = pos >> 32;
}

void ChaCha20::Output(unsigned char* c, size_t bytes)
void ChaCha20::Output(const unsigned char* m, unsigned char* c, size_t bytes)
{
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
Expand Down Expand Up @@ -100,6 +102,10 @@ void ChaCha20::Output(unsigned char* c, size_t bytes)

for (;;) {
if (bytes < 64) {
if (m != nullptr) {
for (i = 0;i < bytes;++i) tmp[i] = m[i];
m = tmp;
}
ctarget = c;
c = tmp;
}
Expand Down Expand Up @@ -146,6 +152,25 @@ void ChaCha20::Output(unsigned char* c, size_t bytes)
x14 += j14;
x15 += j15;

if (m != nullptr) {
x0 = XOR(x0, ReadLE32(m + 0));
x1 = XOR(x1, ReadLE32(m + 4));
x2 = XOR(x2, ReadLE32(m + 8));
x3 = XOR(x3, ReadLE32(m + 12));
x4 = XOR(x4, ReadLE32(m + 16));
x5 = XOR(x5, ReadLE32(m + 20));
x6 = XOR(x6, ReadLE32(m + 24));
x7 = XOR(x7, ReadLE32(m + 28));
x8 = XOR(x8, ReadLE32(m + 32));
x9 = XOR(x9, ReadLE32(m + 36));
x10 = XOR(x10, ReadLE32(m + 40));
x11 = XOR(x11, ReadLE32(m + 44));
x12 = XOR(x12, ReadLE32(m + 48));
x13 = XOR(x13, ReadLE32(m + 52));
x14 = XOR(x14, ReadLE32(m + 56));
x15 = XOR(x15, ReadLE32(m + 60));
}

++j12;
if (!j12) ++j13;

Expand Down Expand Up @@ -176,5 +201,6 @@ void ChaCha20::Output(unsigned char* c, size_t bytes)
}
bytes -= 64;
c += 64;
if (m != nullptr) m += 64;
}
}
4 changes: 3 additions & 1 deletion src/crypto/chacha20.h
Expand Up @@ -20,7 +20,9 @@ class ChaCha20
void SetKey(const unsigned char* key, size_t keylen);
void SetIV(uint64_t iv);
void Seek(uint64_t pos);
void Output(unsigned char* output, size_t bytes);

// if <input> is provided, the ciphertext will be written to <output> otherwise the current keystream
void Output(const unsigned char* input, unsigned char* output, size_t bytes);
};

#endif // BITCOIN_CRYPTO_CHACHA20_H
2 changes: 1 addition & 1 deletion src/random.cpp
Expand Up @@ -652,7 +652,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
if (requires_seed) RandomSeed();
std::vector<unsigned char> ret(len);
if (len > 0) {
rng.Output(&ret[0], len);
rng.Output(nullptr, &ret[0], len);
}
return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion src/random.h
Expand Up @@ -111,7 +111,7 @@ class FastRandomContext {
if (requires_seed) {
RandomSeed();
}
rng.Output(bytebuf, sizeof(bytebuf));
rng.Output(nullptr, bytebuf, sizeof(bytebuf));
bytebuf_size = sizeof(bytebuf);
}

Expand Down
31 changes: 23 additions & 8 deletions src/test/crypto_tests.cpp
Expand Up @@ -187,16 +187,19 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b
}
}

static void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
{
std::vector<unsigned char> key = ParseHex(hexkey);
std::vector<unsigned char> m = ParseHex(hex_message);
ChaCha20 rng(key.data(), key.size());
rng.SetIV(nonce);
rng.Seek(seek);
std::vector<unsigned char> out = ParseHex(hexout);
std::vector<unsigned char> outres;
outres.resize(out.size());
rng.Output(outres.data(), outres.size());

// perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream
rng.Output(hex_message.empty() ? nullptr : m.data(), outres.data(), outres.size());
BOOST_CHECK(out == outres);
}

Expand Down Expand Up @@ -497,25 +500,37 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {
BOOST_AUTO_TEST_CASE(chacha20_testvector)
{
// Test vector from RFC 7539
TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1,

// test encryption
TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756"
"c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e"
"20776f756c642062652069742e",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1,
"6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d"
"624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74"
"a35be6b40b8eedf2785e42874d"
);

// test keystream output
TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1,
"224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb"
"a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a"
"832c89c167eacd901d7e2bf363");

// Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7
TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0, 0,
TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0, 0,
"76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b"
"8f41518a11cc387b669b2ee6586");
TestChaCha20("0000000000000000000000000000000000000000000000000000000000000001", 0, 0,
TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000001", 0, 0,
"4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79"
"2b1c43fea817e9ad275ae546963");
TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0,
TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0,
"de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770"
"62eb7a0433e445f41e3");
TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 1, 0,
TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 1, 0,
"ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4"
"97a0b466e7d6bbdb0041b2f586b");
TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0,
TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0,
"f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b"
"e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1"
"18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5"
Expand Down

0 comments on commit b05bb64

Please sign in to comment.