Merge pull request #3032 from PastaPastaPasta/backport-chacha-poly1305
Backport chacha-poly1305, prepare for V2 P2P Encrypted Messaging
This commit is contained in:
commit
51c84248ad
@ -368,6 +368,8 @@ crypto_libdash_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PIC_FLAGS)
|
||||
crypto_libdash_crypto_a_SOURCES = \
|
||||
crypto/aes.cpp \
|
||||
crypto/aes.h \
|
||||
crypto/chacha_poly_aead.h \
|
||||
crypto/chacha_poly_aead.cpp \
|
||||
crypto/chacha20.h \
|
||||
crypto/chacha20.cpp \
|
||||
crypto/common.h \
|
||||
@ -375,6 +377,8 @@ crypto_libdash_crypto_a_SOURCES = \
|
||||
crypto/hmac_sha256.h \
|
||||
crypto/hmac_sha512.cpp \
|
||||
crypto/hmac_sha512.h \
|
||||
crypto/poly1305.h \
|
||||
crypto/poly1305.cpp \
|
||||
crypto/ripemd160.cpp \
|
||||
crypto/aes_helper.c \
|
||||
crypto/ripemd160.h \
|
||||
@ -591,7 +595,7 @@ dash_tx_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(CRYPTO_LIBS) $(BLS_LIBS)
|
||||
# dashconsensus library #
|
||||
if BUILD_BITCOIN_LIBS
|
||||
include_HEADERS = script/dashconsensus.h
|
||||
libdashconsensus_la_SOURCES = $(crypto_libdash_crypto_a_SOURCES) $(libdash_consensus_a_SOURCES)
|
||||
libdashconsensus_la_SOURCES = support/cleanse.cpp $(crypto_libdash_crypto_a_SOURCES) $(libdash_consensus_a_SOURCES)
|
||||
|
||||
if GLIBC_BACK_COMPAT
|
||||
libdashconsensus_la_SOURCES += compat/glibc_compat.cpp
|
||||
|
@ -22,11 +22,14 @@ bench_bench_dash_SOURCES = \
|
||||
bench/ecdsa.cpp \
|
||||
bench/Examples.cpp \
|
||||
bench/rollingbloom.cpp \
|
||||
bench/chacha20.cpp \
|
||||
bench/chacha_poly_aead.cpp \
|
||||
bench/crypto_hash.cpp \
|
||||
bench/ccoins_caching.cpp \
|
||||
bench/mempool_eviction.cpp \
|
||||
bench/base58.cpp \
|
||||
bench/lockedpool.cpp \
|
||||
bench/poly1305.cpp \
|
||||
bench/perf.cpp \
|
||||
bench/perf.h \
|
||||
bench/prevector_destructor.cpp \
|
||||
|
51
src/bench/chacha20.cpp
Normal file
51
src/bench/chacha20.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <hash.h>
|
||||
#include <crypto/chacha20.h>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static const uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static const uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static const uint64_t BUFFER_SIZE_LARGE = 1024*1024;
|
||||
|
||||
static void CHACHA20(benchmark::State& state, size_t buffersize)
|
||||
{
|
||||
std::vector<uint8_t> key(32,0);
|
||||
ChaCha20 ctx(key.data(), key.size());
|
||||
ctx.SetIV(0);
|
||||
ctx.Seek(0);
|
||||
std::vector<uint8_t> in(buffersize,0);
|
||||
std::vector<uint8_t> out(buffersize,0);
|
||||
while (state.KeepRunning()) {
|
||||
ctx.Crypt(in.data(), out.data(), in.size());
|
||||
}
|
||||
}
|
||||
|
||||
static void CHACHA20_64BYTES(benchmark::State& state)
|
||||
{
|
||||
CHACHA20(state, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void CHACHA20_256BYTES(benchmark::State& state)
|
||||
{
|
||||
CHACHA20(state, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void CHACHA20_1MB(benchmark::State& state)
|
||||
{
|
||||
CHACHA20(state, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
//TODO add back below once benchmarking backports are done
|
||||
//BENCHMARK(CHACHA20_64BYTES, 500000);
|
||||
//BENCHMARK(CHACHA20_256BYTES, 250000);
|
||||
//BENCHMARK(CHACHA20_1MB, 340);
|
||||
BENCHMARK(CHACHA20_64BYTES);
|
||||
BENCHMARK(CHACHA20_256BYTES);
|
||||
BENCHMARK(CHACHA20_1MB);
|
||||
|
124
src/bench/chacha_poly_aead.cpp
Normal file
124
src/bench/chacha_poly_aead.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/chacha_poly_aead.h>
|
||||
#include <crypto/poly1305.h> // for the POLY1305_TAGLEN constant
|
||||
#include <hash.h>
|
||||
|
||||
#include <limits>
|
||||
#include <assert.h>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static constexpr uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static constexpr uint64_t BUFFER_SIZE_LARGE = 1024 * 1024;
|
||||
|
||||
static const unsigned char k1[32] = {0};
|
||||
static const unsigned char k2[32] = {0};
|
||||
|
||||
static ChaCha20Poly1305AEAD aead(k1, 32, k2, 32);
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD(benchmark::State& state, size_t buffersize, bool include_decryption)
|
||||
{
|
||||
std::vector<unsigned char> in(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
|
||||
std::vector<unsigned char> out(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
|
||||
uint64_t seqnr_payload = 0;
|
||||
uint64_t seqnr_aad = 0;
|
||||
int aad_pos = 0;
|
||||
uint32_t len = 0;
|
||||
while (state.KeepRunning()) {
|
||||
// encrypt or decrypt the buffer with a static key
|
||||
assert(aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true));
|
||||
|
||||
if (include_decryption) {
|
||||
// if we decrypt, include the GetLength
|
||||
assert(aead.GetLength(&len, seqnr_aad, aad_pos, in.data()));
|
||||
assert(aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true));
|
||||
}
|
||||
|
||||
// increase main sequence number
|
||||
seqnr_payload++;
|
||||
// increase aad position (position in AAD keystream)
|
||||
aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
|
||||
if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
|
||||
aad_pos = 0;
|
||||
seqnr_aad++;
|
||||
}
|
||||
if (seqnr_payload + 1 == std::numeric_limits<uint64_t>::max()) {
|
||||
// reuse of nonce+key is okay while benchmarking.
|
||||
seqnr_payload = 0;
|
||||
seqnr_aad = 0;
|
||||
aad_pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT(benchmark::State& state)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_TINY, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT(benchmark::State& state)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_SMALL, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT(benchmark::State& state)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_LARGE, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT(benchmark::State& state)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_TINY, true);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT(benchmark::State& state)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_SMALL, true);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT(benchmark::State& state)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_LARGE, true);
|
||||
}
|
||||
|
||||
// Add Hash() (dbl-sha256) bench for comparison
|
||||
|
||||
static void HASH(benchmark::State& state, size_t buffersize)
|
||||
{
|
||||
uint8_t hash[CHash256::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(buffersize,0);
|
||||
while (state.KeepRunning())
|
||||
CHash256().Write(in.data(), in.size()).Finalize(hash);
|
||||
}
|
||||
|
||||
static void HASH_64BYTES(benchmark::State& state)
|
||||
{
|
||||
HASH(state, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void HASH_256BYTES(benchmark::State& state)
|
||||
{
|
||||
HASH(state, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void HASH_1MB(benchmark::State& state)
|
||||
{
|
||||
HASH(state, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
//TODO add back below once benchmark backports are done
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT/*, 500000*/);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT/*, 250000*/);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT/*, 340*/);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT/*, 500000*/);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT/*, 250000*/);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT/*, 340*/);
|
||||
BENCHMARK(HASH_64BYTES/*, 500000*/);
|
||||
BENCHMARK(HASH_256BYTES/*, 250000*/);
|
||||
BENCHMARK(HASH_1MB/*, 340*/);
|
43
src/bench/poly1305.cpp
Normal file
43
src/bench/poly1305.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/poly1305.h>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static constexpr uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static constexpr uint64_t BUFFER_SIZE_LARGE = 1024*1024;
|
||||
|
||||
static void POLY1305(benchmark::State& state, size_t buffersize)
|
||||
{
|
||||
std::vector<unsigned char> tag(POLY1305_TAGLEN, 0);
|
||||
std::vector<unsigned char> key(POLY1305_KEYLEN, 0);
|
||||
std::vector<unsigned char> in(buffersize, 0);
|
||||
while (state.KeepRunning())
|
||||
poly1305_auth(tag.data(), in.data(), in.size(), key.data());
|
||||
}
|
||||
|
||||
static void POLY1305_64BYTES(benchmark::State& state)
|
||||
{
|
||||
POLY1305(state, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void POLY1305_256BYTES(benchmark::State& state)
|
||||
{
|
||||
POLY1305(state, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void POLY1305_1MB(benchmark::State& state)
|
||||
{
|
||||
POLY1305(state, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
//TODO add back below once benchmarking backports are done
|
||||
BENCHMARK(POLY1305_64BYTES/*, 500000*/);
|
||||
BENCHMARK(POLY1305_256BYTES/*, 250000*/);
|
||||
BENCHMARK(POLY1305_1MB/*, 340*/);
|
@ -71,7 +71,7 @@ void ChaCha20::Seek(uint64_t pos)
|
||||
input[13] = pos >> 32;
|
||||
}
|
||||
|
||||
void ChaCha20::Output(unsigned char* c, size_t bytes)
|
||||
void ChaCha20::Keystream(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;
|
||||
@ -178,3 +178,133 @@ void ChaCha20::Output(unsigned char* c, size_t bytes)
|
||||
c += 64;
|
||||
}
|
||||
}
|
||||
|
||||
void ChaCha20::Crypt(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;
|
||||
unsigned char *ctarget = nullptr;
|
||||
unsigned char tmp[64];
|
||||
unsigned int i;
|
||||
|
||||
if (!bytes) return;
|
||||
|
||||
j0 = input[0];
|
||||
j1 = input[1];
|
||||
j2 = input[2];
|
||||
j3 = input[3];
|
||||
j4 = input[4];
|
||||
j5 = input[5];
|
||||
j6 = input[6];
|
||||
j7 = input[7];
|
||||
j8 = input[8];
|
||||
j9 = input[9];
|
||||
j10 = input[10];
|
||||
j11 = input[11];
|
||||
j12 = input[12];
|
||||
j13 = input[13];
|
||||
j14 = input[14];
|
||||
j15 = input[15];
|
||||
|
||||
for (;;) {
|
||||
if (bytes < 64) {
|
||||
// if m has fewer than 64 bytes available, copy m to tmp and
|
||||
// read from tmp instead
|
||||
for (i = 0;i < bytes;++i) tmp[i] = m[i];
|
||||
m = tmp;
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
}
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
for (i = 20;i > 0;i -= 2) {
|
||||
QUARTERROUND( x0, x4, x8,x12)
|
||||
QUARTERROUND( x1, x5, x9,x13)
|
||||
QUARTERROUND( x2, x6,x10,x14)
|
||||
QUARTERROUND( x3, x7,x11,x15)
|
||||
QUARTERROUND( x0, x5,x10,x15)
|
||||
QUARTERROUND( x1, x6,x11,x12)
|
||||
QUARTERROUND( x2, x7, x8,x13)
|
||||
QUARTERROUND( x3, x4, x9,x14)
|
||||
}
|
||||
x0 += j0;
|
||||
x1 += j1;
|
||||
x2 += j2;
|
||||
x3 += j3;
|
||||
x4 += j4;
|
||||
x5 += j5;
|
||||
x6 += j6;
|
||||
x7 += j7;
|
||||
x8 += j8;
|
||||
x9 += j9;
|
||||
x10 += j10;
|
||||
x11 += j11;
|
||||
x12 += j12;
|
||||
x13 += j13;
|
||||
x14 += j14;
|
||||
x15 += j15;
|
||||
|
||||
x0 ^= ReadLE32(m + 0);
|
||||
x1 ^= ReadLE32(m + 4);
|
||||
x2 ^= ReadLE32(m + 8);
|
||||
x3 ^= ReadLE32(m + 12);
|
||||
x4 ^= ReadLE32(m + 16);
|
||||
x5 ^= ReadLE32(m + 20);
|
||||
x6 ^= ReadLE32(m + 24);
|
||||
x7 ^= ReadLE32(m + 28);
|
||||
x8 ^= ReadLE32(m + 32);
|
||||
x9 ^= ReadLE32(m + 36);
|
||||
x10 ^= ReadLE32(m + 40);
|
||||
x11 ^= ReadLE32(m + 44);
|
||||
x12 ^= ReadLE32(m + 48);
|
||||
x13 ^= ReadLE32(m + 52);
|
||||
x14 ^= ReadLE32(m + 56);
|
||||
x15 ^= ReadLE32(m + 60);
|
||||
|
||||
++j12;
|
||||
if (!j12) ++j13;
|
||||
|
||||
WriteLE32(c + 0, x0);
|
||||
WriteLE32(c + 4, x1);
|
||||
WriteLE32(c + 8, x2);
|
||||
WriteLE32(c + 12, x3);
|
||||
WriteLE32(c + 16, x4);
|
||||
WriteLE32(c + 20, x5);
|
||||
WriteLE32(c + 24, x6);
|
||||
WriteLE32(c + 28, x7);
|
||||
WriteLE32(c + 32, x8);
|
||||
WriteLE32(c + 36, x9);
|
||||
WriteLE32(c + 40, x10);
|
||||
WriteLE32(c + 44, x11);
|
||||
WriteLE32(c + 48, x12);
|
||||
WriteLE32(c + 52, x13);
|
||||
WriteLE32(c + 56, x14);
|
||||
WriteLE32(c + 60, x15);
|
||||
|
||||
if (bytes <= 64) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0;i < bytes;++i) ctarget[i] = c[i];
|
||||
}
|
||||
input[12] = j12;
|
||||
input[13] = j13;
|
||||
return;
|
||||
}
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
m += 64;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** A PRNG class for ChaCha20. */
|
||||
/** A class for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein
|
||||
https://cr.yp.to/chacha/chacha-20080128.pdf */
|
||||
class ChaCha20
|
||||
{
|
||||
private:
|
||||
@ -17,10 +18,17 @@ private:
|
||||
public:
|
||||
ChaCha20();
|
||||
ChaCha20(const unsigned char* key, size_t keylen);
|
||||
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);
|
||||
void SetKey(const unsigned char* key, size_t keylen); //!< set key with flexible keylength; 256bit recommended */
|
||||
void SetIV(uint64_t iv); // set the 64bit nonce
|
||||
void Seek(uint64_t pos); // set the 64bit block counter
|
||||
|
||||
/** outputs the keystream of size <bytes> into <c> */
|
||||
void Keystream(unsigned char* c, size_t bytes);
|
||||
|
||||
/** enciphers the message <input> of length <bytes> and write the enciphered representation into <output>
|
||||
* Used for encryption and decryption (XOR)
|
||||
*/
|
||||
void Crypt(const unsigned char* input, unsigned char* output, size_t bytes);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CRYPTO_CHACHA20_H
|
||||
|
126
src/crypto/chacha_poly_aead.cpp
Normal file
126
src/crypto/chacha_poly_aead.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <crypto/chacha_poly_aead.h>
|
||||
|
||||
#include <crypto/common.h>
|
||||
#include <crypto/poly1305.h>
|
||||
#include <support/cleanse.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
#ifndef HAVE_TIMINGSAFE_BCMP
|
||||
|
||||
int timingsafe_bcmp(const unsigned char* b1, const unsigned char* b2, size_t n)
|
||||
{
|
||||
const unsigned char *p1 = b1, *p2 = b2;
|
||||
int ret = 0;
|
||||
|
||||
for (; n > 0; n--)
|
||||
ret |= *p1++ ^ *p2++;
|
||||
return (ret != 0);
|
||||
}
|
||||
|
||||
#endif // TIMINGSAFE_BCMP
|
||||
|
||||
ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_len, const unsigned char* K_2, size_t K_2_len)
|
||||
{
|
||||
assert(K_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
|
||||
assert(K_2_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
|
||||
m_chacha_main.SetKey(K_1, CHACHA20_POLY1305_AEAD_KEY_LEN);
|
||||
m_chacha_header.SetKey(K_2, CHACHA20_POLY1305_AEAD_KEY_LEN);
|
||||
|
||||
// set the cached sequence number to uint64 max which hints for an unset cache.
|
||||
// we can't hit uint64 max since the rekey rule (which resets the sequence number) is 1GB
|
||||
m_cached_aad_seqnr = std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
|
||||
bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, unsigned char* dest, size_t dest_len /* length of the output buffer for sanity checks */, const unsigned char* src, size_t src_len, bool is_encrypt)
|
||||
{
|
||||
// check buffer boundaries
|
||||
if (
|
||||
// if we encrypt, make sure the source contains at least the expected AAD and the destination has at least space for the source + MAC
|
||||
(is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN || dest_len < src_len + POLY1305_TAGLEN)) ||
|
||||
// if we decrypt, make sure the source contains at least the expected AAD+MAC and the destination has at least space for the source - MAC
|
||||
(!is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN || dest_len < src_len - POLY1305_TAGLEN))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
|
||||
memset(poly_key, 0, sizeof(poly_key));
|
||||
m_chacha_main.SetIV(seqnr_payload);
|
||||
|
||||
// block counter 0 for the poly1305 key
|
||||
// use lower 32bytes for the poly1305 key
|
||||
// (throws away 32 unused bytes (upper 32) from this ChaCha20 round)
|
||||
m_chacha_main.Seek(0);
|
||||
m_chacha_main.Crypt(poly_key, poly_key, sizeof(poly_key));
|
||||
|
||||
// if decrypting, verify the tag prior to decryption
|
||||
if (!is_encrypt) {
|
||||
const unsigned char* tag = src + src_len - POLY1305_TAGLEN;
|
||||
poly1305_auth(expected_tag, src, src_len - POLY1305_TAGLEN, poly_key);
|
||||
|
||||
// constant time compare the calculated MAC with the provided MAC
|
||||
if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
|
||||
memory_cleanse(expected_tag, sizeof(expected_tag));
|
||||
memory_cleanse(poly_key, sizeof(poly_key));
|
||||
return false;
|
||||
}
|
||||
memory_cleanse(expected_tag, sizeof(expected_tag));
|
||||
// MAC has been successfully verified, make sure we don't covert it in decryption
|
||||
src_len -= POLY1305_TAGLEN;
|
||||
}
|
||||
|
||||
// calculate and cache the next 64byte keystream block if requested sequence number is not yet the cache
|
||||
if (m_cached_aad_seqnr != seqnr_aad) {
|
||||
m_cached_aad_seqnr = seqnr_aad;
|
||||
m_chacha_header.SetIV(seqnr_aad);
|
||||
m_chacha_header.Seek(0);
|
||||
m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT);
|
||||
}
|
||||
// crypt the AAD (3 bytes message length) with given position in AAD cipher instance keystream
|
||||
dest[0] = src[0] ^ m_aad_keystream_buffer[aad_pos];
|
||||
dest[1] = src[1] ^ m_aad_keystream_buffer[aad_pos + 1];
|
||||
dest[2] = src[2] ^ m_aad_keystream_buffer[aad_pos + 2];
|
||||
|
||||
// Set the playload ChaCha instance block counter to 1 and crypt the payload
|
||||
m_chacha_main.Seek(1);
|
||||
m_chacha_main.Crypt(src + CHACHA20_POLY1305_AEAD_AAD_LEN, dest + CHACHA20_POLY1305_AEAD_AAD_LEN, src_len - CHACHA20_POLY1305_AEAD_AAD_LEN);
|
||||
|
||||
// If encrypting, calculate and append tag
|
||||
if (is_encrypt) {
|
||||
// the poly1305 tag expands over the AAD (3 bytes length) & encrypted payload
|
||||
poly1305_auth(dest + src_len, dest, src_len, poly_key);
|
||||
}
|
||||
|
||||
// cleanse no longer required MAC and polykey
|
||||
memory_cleanse(poly_key, sizeof(poly_key));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChaCha20Poly1305AEAD::GetLength(uint32_t* len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t* ciphertext)
|
||||
{
|
||||
// enforce valid aad position to avoid accessing outside of the 64byte keystream cache
|
||||
// (there is space for 21 times 3 bytes)
|
||||
assert(aad_pos >= 0 && aad_pos < CHACHA20_ROUND_OUTPUT - CHACHA20_POLY1305_AEAD_AAD_LEN);
|
||||
if (m_cached_aad_seqnr != seqnr_aad) {
|
||||
// we need to calculate the 64 keystream bytes since we reached a new aad sequence number
|
||||
m_cached_aad_seqnr = seqnr_aad;
|
||||
m_chacha_header.SetIV(seqnr_aad); // use LE for the nonce
|
||||
m_chacha_header.Seek(0); // block counter 0
|
||||
m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); // write keystream to the cache
|
||||
}
|
||||
|
||||
// decrypt the ciphertext length by XORing the right position of the 64byte keystream cache with the ciphertext
|
||||
*len24_out = (ciphertext[0] ^ m_aad_keystream_buffer[aad_pos + 0]) |
|
||||
(ciphertext[1] ^ m_aad_keystream_buffer[aad_pos + 1]) << 8 |
|
||||
(ciphertext[2] ^ m_aad_keystream_buffer[aad_pos + 2]) << 16;
|
||||
|
||||
return true;
|
||||
}
|
146
src/crypto/chacha_poly_aead.h
Normal file
146
src/crypto/chacha_poly_aead.h
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
|
||||
#define BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
|
||||
|
||||
#include <crypto/chacha20.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
static constexpr int CHACHA20_POLY1305_AEAD_KEY_LEN = 32;
|
||||
static constexpr int CHACHA20_POLY1305_AEAD_AAD_LEN = 3; /* 3 bytes length */
|
||||
static constexpr int CHACHA20_ROUND_OUTPUT = 64; /* 64 bytes per round */
|
||||
static constexpr int AAD_PACKAGES_PER_ROUND = 21; /* 64 / 3 round down*/
|
||||
|
||||
/* A AEAD class for ChaCha20-Poly1305@bitcoin.
|
||||
*
|
||||
* ChaCha20 is a stream cipher designed by Daniel Bernstein and described in
|
||||
* <ref>[http://cr.yp.to/chacha/chacha-20080128.pdf ChaCha20]</ref>. It operates
|
||||
* by permuting 128 fixed bits, 128 or 256 bits of key, a 64 bit nonce and a 64
|
||||
* bit counter into 64 bytes of output. This output is used as a keystream, with
|
||||
* any unused bytes simply discarded.
|
||||
*
|
||||
* Poly1305 <ref>[http://cr.yp.to/mac/poly1305-20050329.pdf Poly1305]</ref>, also
|
||||
* by Daniel Bernstein, is a one-time Carter-Wegman MAC that computes a 128 bit
|
||||
* integrity tag given a message and a single-use 256 bit secret key.
|
||||
*
|
||||
* The chacha20-poly1305@bitcoin combines these two primitives into an
|
||||
* authenticated encryption mode. The construction used is based on that proposed
|
||||
* for TLS by Adam Langley in
|
||||
* <ref>[http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 "ChaCha20
|
||||
* and Poly1305 based Cipher Suites for TLS", Adam Langley]</ref>, but differs in
|
||||
* the layout of data passed to the MAC and in the addition of encryption of the
|
||||
* packet lengths.
|
||||
*
|
||||
* ==== Detailed Construction ====
|
||||
*
|
||||
* The chacha20-poly1305@bitcoin cipher requires two 256 bits of key material as
|
||||
* output from the key exchange. Each key (K_1 and K_2) are used by two separate
|
||||
* instances of chacha20.
|
||||
*
|
||||
* The instance keyed by K_1 is a stream cipher that is used only to encrypt the 3
|
||||
* byte packet length field and has its own sequence number. The second instance,
|
||||
* keyed by K_2, is used in conjunction with poly1305 to build an AEAD
|
||||
* (Authenticated Encryption with Associated Data) that is used to encrypt and
|
||||
* authenticate the entire packet.
|
||||
*
|
||||
* Two separate cipher instances are used here so as to keep the packet lengths
|
||||
* confidential but not create an oracle for the packet payload cipher by
|
||||
* decrypting and using the packet length prior to checking the MAC. By using an
|
||||
* independently-keyed cipher instance to encrypt the length, an active attacker
|
||||
* seeking to exploit the packet input handling as a decryption oracle can learn
|
||||
* nothing about the payload contents or its MAC (assuming key derivation,
|
||||
* ChaCha20 and Poly1305 are secure).
|
||||
*
|
||||
* The AEAD is constructed as follows: for each packet, generate a Poly1305 key by
|
||||
* taking the first 256 bits of ChaCha20 stream output generated using K_2, an IV
|
||||
* consisting of the packet sequence number encoded as an LE uint64 and a ChaCha20
|
||||
* block counter of zero. The K_2 ChaCha20 block counter is then set to the
|
||||
* little-endian encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance
|
||||
* is used for encryption of the packet payload.
|
||||
*
|
||||
* ==== Packet Handling ====
|
||||
*
|
||||
* When receiving a packet, the length must be decrypted first. When 3 bytes of
|
||||
* ciphertext length have been received, they may be decrypted.
|
||||
*
|
||||
* A ChaCha20 round always calculates 64bytes which is sufficient to crypt 21
|
||||
* times a 3 bytes length field (21*3 = 63). The length field sequence number can
|
||||
* thus be used 21 times (keystream caching).
|
||||
*
|
||||
* The length field must be enc-/decrypted with the ChaCha20 keystream keyed with
|
||||
* K_1 defined by block counter 0, the length field sequence number in little
|
||||
* endian and a keystream position from 0 to 60.
|
||||
*
|
||||
* Once the entire packet has been received, the MAC MUST be checked before
|
||||
* decryption. A per-packet Poly1305 key is generated as described above and the
|
||||
* MAC tag calculated using Poly1305 with this key over the ciphertext of the
|
||||
* packet length and the payload together. The calculated MAC is then compared in
|
||||
* constant time with the one appended to the packet and the packet decrypted
|
||||
* using ChaCha20 as described above (with K_2, the packet sequence number as
|
||||
* nonce and a starting block counter of 1).
|
||||
*
|
||||
* Detection of an invalid MAC MUST lead to immediate connection termination.
|
||||
*
|
||||
* To send a packet, first encode the 3 byte length and encrypt it using K_1 as
|
||||
* described above. Encrypt the packet payload (using K_2) and append it to the
|
||||
* encrypted length. Finally, calculate a MAC tag and append it.
|
||||
*
|
||||
* The initiating peer MUST use <code>K_1_A, K_2_A</code> to encrypt messages on
|
||||
* the send channel, <code>K_1_B, K_2_B</code> MUST be used to decrypt messages on
|
||||
* the receive channel.
|
||||
*
|
||||
* The responding peer MUST use <code>K_1_A, K_2_A</code> to decrypt messages on
|
||||
* the receive channel, <code>K_1_B, K_2_B</code> MUST be used to encrypt messages
|
||||
* on the send channel.
|
||||
*
|
||||
* Optimized implementations of ChaCha20-Poly1305@bitcoin are relatively fast in
|
||||
* general, therefore it is very likely that encrypted messages require not more
|
||||
* CPU cycles per bytes then the current unencrypted p2p message format
|
||||
* (ChaCha20/Poly1305 versus double SHA256).
|
||||
*
|
||||
* The initial packet sequence numbers are 0.
|
||||
*
|
||||
* K_2 ChaCha20 cipher instance (payload) must never reuse a {key, nonce} for
|
||||
* encryption nor may it be used to encrypt more than 2^70 bytes under the same
|
||||
* {key, nonce}.
|
||||
*
|
||||
* K_1 ChaCha20 cipher instance (length field/AAD) must never reuse a {key, nonce,
|
||||
* position-in-keystream} for encryption nor may it be used to encrypt more than
|
||||
* 2^70 bytes under the same {key, nonce}.
|
||||
*
|
||||
* We use message sequence numbers for both communication directions.
|
||||
*/
|
||||
|
||||
class ChaCha20Poly1305AEAD
|
||||
{
|
||||
private:
|
||||
ChaCha20 m_chacha_main; // payload and poly1305 key-derivation cipher instance
|
||||
ChaCha20 m_chacha_header; // AAD cipher instance (encrypted length)
|
||||
unsigned char m_aad_keystream_buffer[CHACHA20_ROUND_OUTPUT]; // aad keystream cache
|
||||
uint64_t m_cached_aad_seqnr; // aad keystream cache hint
|
||||
|
||||
public:
|
||||
ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_len, const unsigned char* K_2, size_t K_2_len);
|
||||
|
||||
explicit ChaCha20Poly1305AEAD(const ChaCha20Poly1305AEAD&) = delete;
|
||||
|
||||
/** Encrypts/decrypts a packet
|
||||
seqnr_payload, the message sequence number
|
||||
seqnr_aad, the messages AAD sequence number which allows reuse of the AAD keystream
|
||||
aad_pos, position to use in the AAD keystream to encrypt the AAD
|
||||
dest, output buffer, must be of a size equal or larger then CHACHA20_POLY1305_AEAD_AAD_LEN + payload (+ POLY1305_TAG_LEN in encryption) bytes
|
||||
destlen, length of the destination buffer
|
||||
src, the AAD+payload to encrypt or the AAD+payload+MAC to decrypt
|
||||
src_len, the length of the source buffer
|
||||
is_encrypt, set to true if we encrypt (creates and appends the MAC instead of verifying it)
|
||||
*/
|
||||
bool Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, unsigned char* dest, size_t dest_len, const unsigned char* src, size_t src_len, bool is_encrypt);
|
||||
|
||||
/** decrypts the 3 bytes AAD data and decodes it into a uint32_t field */
|
||||
bool GetLength(uint32_t* len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t* ciphertext);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
|
141
src/crypto/poly1305.cpp
Normal file
141
src/crypto/poly1305.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
// Based on the public domain implementation by Andrew Moon
|
||||
// poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
||||
|
||||
#include <crypto/common.h>
|
||||
#include <crypto/poly1305.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
|
||||
|
||||
void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
|
||||
uint32_t t0,t1,t2,t3;
|
||||
uint32_t h0,h1,h2,h3,h4;
|
||||
uint32_t r0,r1,r2,r3,r4;
|
||||
uint32_t s1,s2,s3,s4;
|
||||
uint32_t b, nb;
|
||||
size_t j;
|
||||
uint64_t t[5];
|
||||
uint64_t f0,f1,f2,f3;
|
||||
uint64_t g0,g1,g2,g3,g4;
|
||||
uint64_t c;
|
||||
unsigned char mp[16];
|
||||
|
||||
/* clamp key */
|
||||
t0 = ReadLE32(key+0);
|
||||
t1 = ReadLE32(key+4);
|
||||
t2 = ReadLE32(key+8);
|
||||
t3 = ReadLE32(key+12);
|
||||
|
||||
/* precompute multipliers */
|
||||
r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
|
||||
r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
|
||||
r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
|
||||
r3 = t2 & 0x3f03fff; t3 >>= 8;
|
||||
r4 = t3 & 0x00fffff;
|
||||
|
||||
s1 = r1 * 5;
|
||||
s2 = r2 * 5;
|
||||
s3 = r3 * 5;
|
||||
s4 = r4 * 5;
|
||||
|
||||
/* init state */
|
||||
h0 = 0;
|
||||
h1 = 0;
|
||||
h2 = 0;
|
||||
h3 = 0;
|
||||
h4 = 0;
|
||||
|
||||
/* full blocks */
|
||||
if (inlen < 16) goto poly1305_donna_atmost15bytes;
|
||||
poly1305_donna_16bytes:
|
||||
m += 16;
|
||||
inlen -= 16;
|
||||
|
||||
t0 = ReadLE32(m-16);
|
||||
t1 = ReadLE32(m-12);
|
||||
t2 = ReadLE32(m-8);
|
||||
t3 = ReadLE32(m-4);
|
||||
|
||||
h0 += t0 & 0x3ffffff;
|
||||
h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
|
||||
h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
|
||||
h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
|
||||
h4 += (t3 >> 8) | (1 << 24);
|
||||
|
||||
|
||||
poly1305_donna_mul:
|
||||
t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
|
||||
t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
|
||||
t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
|
||||
t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
|
||||
t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
|
||||
|
||||
h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26);
|
||||
t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26);
|
||||
t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26);
|
||||
t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26);
|
||||
t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26);
|
||||
h0 += b * 5;
|
||||
|
||||
if (inlen >= 16) goto poly1305_donna_16bytes;
|
||||
|
||||
/* final bytes */
|
||||
poly1305_donna_atmost15bytes:
|
||||
if (!inlen) goto poly1305_donna_finish;
|
||||
|
||||
for (j = 0; j < inlen; j++) mp[j] = m[j];
|
||||
mp[j++] = 1;
|
||||
for (; j < 16; j++) mp[j] = 0;
|
||||
inlen = 0;
|
||||
|
||||
t0 = ReadLE32(mp+0);
|
||||
t1 = ReadLE32(mp+4);
|
||||
t2 = ReadLE32(mp+8);
|
||||
t3 = ReadLE32(mp+12);
|
||||
|
||||
h0 += t0 & 0x3ffffff;
|
||||
h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
|
||||
h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
|
||||
h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
|
||||
h4 += (t3 >> 8);
|
||||
|
||||
goto poly1305_donna_mul;
|
||||
|
||||
poly1305_donna_finish:
|
||||
b = h0 >> 26; h0 = h0 & 0x3ffffff;
|
||||
h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff;
|
||||
h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff;
|
||||
h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff;
|
||||
h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff;
|
||||
h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff;
|
||||
h1 += b;
|
||||
|
||||
g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
|
||||
g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
|
||||
g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
|
||||
g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff;
|
||||
g4 = h4 + b - (1 << 26);
|
||||
|
||||
b = (g4 >> 31) - 1;
|
||||
nb = ~b;
|
||||
h0 = (h0 & nb) | (g0 & b);
|
||||
h1 = (h1 & nb) | (g1 & b);
|
||||
h2 = (h2 & nb) | (g2 & b);
|
||||
h3 = (h3 & nb) | (g3 & b);
|
||||
h4 = (h4 & nb) | (g4 & b);
|
||||
|
||||
f0 = ((h0 ) | (h1 << 26)) + (uint64_t)ReadLE32(&key[16]);
|
||||
f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)ReadLE32(&key[20]);
|
||||
f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)ReadLE32(&key[24]);
|
||||
f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)ReadLE32(&key[28]);
|
||||
|
||||
WriteLE32(&out[ 0], f0); f1 += (f0 >> 32);
|
||||
WriteLE32(&out[ 4], f1); f2 += (f1 >> 32);
|
||||
WriteLE32(&out[ 8], f2); f3 += (f2 >> 32);
|
||||
WriteLE32(&out[12], f3);
|
||||
}
|
17
src/crypto/poly1305.h
Normal file
17
src/crypto/poly1305.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_POLY1305_H
|
||||
#define BITCOIN_CRYPTO_POLY1305_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define POLY1305_KEYLEN 32
|
||||
#define POLY1305_TAGLEN 16
|
||||
|
||||
void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen,
|
||||
const unsigned char key[POLY1305_KEYLEN]);
|
||||
|
||||
#endif // BITCOIN_CRYPTO_POLY1305_H
|
@ -397,7 +397,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
|
||||
{
|
||||
std::vector<unsigned char> ret(len);
|
||||
if (len > 0) {
|
||||
rng.Output(&ret[0], len);
|
||||
rng.Keystream(&ret[0], len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ private:
|
||||
if (requires_seed) {
|
||||
RandomSeed();
|
||||
}
|
||||
rng.Output(bytebuf, sizeof(bytebuf));
|
||||
rng.Keystream(bytebuf, sizeof(bytebuf));
|
||||
bytebuf_size = sizeof(bytebuf);
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,35 @@
|
||||
|
||||
#include "cleanse.h"
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <cstring>
|
||||
|
||||
/* Compilers have a bad habit of removing "superfluous" memset calls that
|
||||
* are trying to zero memory. For example, when memset()ing a buffer and
|
||||
* then free()ing it, the compiler might decide that the memset is
|
||||
* unobservable and thus can be removed.
|
||||
*
|
||||
* Previously we used OpenSSL which tried to stop this by a) implementing
|
||||
* memset in assembly on x86 and b) putting the function in its own file
|
||||
* for other platforms.
|
||||
*
|
||||
* This change removes those tricks in favour of using asm directives to
|
||||
* scare the compiler away. As best as our compiler folks can tell, this is
|
||||
* sufficient and will continue to be so.
|
||||
*
|
||||
* Adam Langley <agl@google.com>
|
||||
* Commit: ad1907fe73334d6c696c8539646c21b11178f20f
|
||||
* BoringSSL (LICENSE: ISC)
|
||||
*/
|
||||
void memory_cleanse(void *ptr, size_t len)
|
||||
{
|
||||
OPENSSL_cleanse(ptr, len);
|
||||
std::memset(ptr, 0, len);
|
||||
|
||||
/* As best as we can tell, this is sufficient to break any optimisations that
|
||||
might try to eliminate "superfluous" memsets. If there's an easy way to
|
||||
detect memset_s, it would be better to use that. */
|
||||
#if defined(_MSC_VER)
|
||||
__asm;
|
||||
#else
|
||||
__asm__ __volatile__("" : : "r"(ptr) : "memory");
|
||||
#endif
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/chacha20.h"
|
||||
#include "crypto/chacha_poly_aead.h"
|
||||
#include "crypto/poly1305.h"
|
||||
#include "crypto/ripemd160.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
@ -187,17 +189,47 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad
|
||||
}
|
||||
}
|
||||
|
||||
void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
|
||||
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());
|
||||
assert(hex_message.empty() || m.size() == out.size());
|
||||
|
||||
// perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream
|
||||
if (!hex_message.empty()) {
|
||||
rng.Crypt(m.data(), outres.data(), outres.size());
|
||||
} else {
|
||||
rng.Keystream(outres.data(), outres.size());
|
||||
}
|
||||
BOOST_CHECK(out == outres);
|
||||
if (!hex_message.empty()) {
|
||||
// Manually XOR with the keystream and compare the output
|
||||
rng.SetIV(nonce);
|
||||
rng.Seek(seek);
|
||||
std::vector<unsigned char> only_keystream(outres.size());
|
||||
rng.Keystream(only_keystream.data(), only_keystream.size());
|
||||
for (size_t i = 0; i != m.size(); i++) {
|
||||
outres[i] = m[i] ^ only_keystream[i];
|
||||
}
|
||||
BOOST_CHECK(out == outres);
|
||||
}
|
||||
}
|
||||
|
||||
static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag)
|
||||
{
|
||||
std::vector<unsigned char> key = ParseHex(hexkey);
|
||||
std::vector<unsigned char> m = ParseHex(hexmessage);
|
||||
std::vector<unsigned char> tag = ParseHex(hextag);
|
||||
std::vector<unsigned char> tagres;
|
||||
tagres.resize(POLY1305_TAGLEN);
|
||||
poly1305_auth(tagres.data(), m.data(), m.size(), key.data());
|
||||
BOOST_CHECK(tag == tagres);
|
||||
}
|
||||
|
||||
std::string LongTestString(void) {
|
||||
@ -479,25 +511,37 @@ BOOST_AUTO_TEST_CASE(pbkdf2_hmac_sha512_test) {
|
||||
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"
|
||||
@ -506,6 +550,201 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
|
||||
"fab78c9");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(poly1305_testvector)
|
||||
{
|
||||
// RFC 7539, section 2.5.2.
|
||||
TestPoly1305("43727970746f6772617068696320466f72756d2052657365617263682047726f7570",
|
||||
"85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b",
|
||||
"a8061dc1305136c6c22b8baf0c0127a9");
|
||||
|
||||
// RFC 7539, section A.3.
|
||||
TestPoly1305("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"00000000000000000000000000000000");
|
||||
|
||||
TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
|
||||
"5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
|
||||
"726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
|
||||
"520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
|
||||
"4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
|
||||
"56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
|
||||
"6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
|
||||
"768696368206172652061646472657373656420746f",
|
||||
"0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e",
|
||||
"36e5f6b5c5e06070f0efca96227a863e");
|
||||
|
||||
TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
|
||||
"5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
|
||||
"726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
|
||||
"520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
|
||||
"4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
|
||||
"56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
|
||||
"6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
|
||||
"768696368206172652061646472657373656420746f",
|
||||
"36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000",
|
||||
"f3477e7cd95417af89a6b8794c310cf0");
|
||||
|
||||
TestPoly1305("2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e6420676"
|
||||
"96d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e"
|
||||
"6420746865206d6f6d65207261746873206f757467726162652e",
|
||||
"1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
|
||||
"4541669a7eaaee61e708dc7cbcc5eb62");
|
||||
|
||||
TestPoly1305("ffffffffffffffffffffffffffffffff",
|
||||
"0200000000000000000000000000000000000000000000000000000000000000",
|
||||
"03000000000000000000000000000000");
|
||||
|
||||
TestPoly1305("02000000000000000000000000000000",
|
||||
"02000000000000000000000000000000ffffffffffffffffffffffffffffffff",
|
||||
"03000000000000000000000000000000");
|
||||
|
||||
TestPoly1305("fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000",
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"05000000000000000000000000000000");
|
||||
|
||||
TestPoly1305("fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101",
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"00000000000000000000000000000000");
|
||||
|
||||
TestPoly1305("fdffffffffffffffffffffffffffffff",
|
||||
"0200000000000000000000000000000000000000000000000000000000000000",
|
||||
"faffffffffffffffffffffffffffffff");
|
||||
|
||||
TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000",
|
||||
"0100000000000000040000000000000000000000000000000000000000000000",
|
||||
"14000000000000005500000000000000");
|
||||
|
||||
TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000",
|
||||
"0100000000000000040000000000000000000000000000000000000000000000",
|
||||
"13000000000000000000000000000000");
|
||||
}
|
||||
|
||||
static void TestChaCha20Poly1305AEAD(bool must_succeed, unsigned int expected_aad_length, const std::string& hex_m, const std::string& hex_k1, const std::string& hex_k2, const std::string& hex_aad_keystream, const std::string& hex_encrypted_message, const std::string& hex_encrypted_message_seq_999)
|
||||
{
|
||||
// we need two sequence numbers, one for the payload cipher instance...
|
||||
uint32_t seqnr_payload = 0;
|
||||
// ... and one for the AAD (length) cipher instance
|
||||
uint32_t seqnr_aad = 0;
|
||||
// we need to keep track of the position in the AAD cipher instance
|
||||
// keystream since we use the same 64byte output 21 times
|
||||
// (21 times 3 bytes length < 64)
|
||||
int aad_pos = 0;
|
||||
|
||||
std::vector<unsigned char> aead_K_1 = ParseHex(hex_k1);
|
||||
std::vector<unsigned char> aead_K_2 = ParseHex(hex_k2);
|
||||
std::vector<unsigned char> plaintext_buf = ParseHex(hex_m);
|
||||
std::vector<unsigned char> expected_aad_keystream = ParseHex(hex_aad_keystream);
|
||||
std::vector<unsigned char> expected_ciphertext_and_mac = ParseHex(hex_encrypted_message);
|
||||
std::vector<unsigned char> expected_ciphertext_and_mac_sequence999 = ParseHex(hex_encrypted_message_seq_999);
|
||||
|
||||
std::vector<unsigned char> ciphertext_buf(plaintext_buf.size() + POLY1305_TAGLEN, 0);
|
||||
std::vector<unsigned char> plaintext_buf_new(plaintext_buf.size(), 0);
|
||||
std::vector<unsigned char> cmp_ctx_buffer(64);
|
||||
uint32_t out_len = 0;
|
||||
|
||||
// create the AEAD instance
|
||||
ChaCha20Poly1305AEAD aead(aead_K_1.data(), aead_K_1.size(), aead_K_2.data(), aead_K_2.size());
|
||||
|
||||
// create a chacha20 instance to compare against
|
||||
ChaCha20 cmp_ctx(aead_K_2.data(), 32);
|
||||
|
||||
// encipher
|
||||
bool res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);
|
||||
// make sure the operation succeeded if expected to succeed
|
||||
BOOST_CHECK_EQUAL(res, must_succeed);
|
||||
if (!res) return;
|
||||
|
||||
// verify ciphertext & mac against the test vector
|
||||
BOOST_CHECK_EQUAL(expected_ciphertext_and_mac.size(), ciphertext_buf.size());
|
||||
BOOST_CHECK(memcmp(ciphertext_buf.data(), expected_ciphertext_and_mac.data(), ciphertext_buf.size()) == 0);
|
||||
|
||||
// manually construct the AAD keystream
|
||||
cmp_ctx.SetIV(seqnr_aad);
|
||||
cmp_ctx.Seek(0);
|
||||
cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
|
||||
BOOST_CHECK(memcmp(expected_aad_keystream.data(), cmp_ctx_buffer.data(), expected_aad_keystream.size()) == 0);
|
||||
// crypt the 3 length bytes and compare the length
|
||||
uint32_t len_cmp = 0;
|
||||
len_cmp = (ciphertext_buf[0] ^ cmp_ctx_buffer[aad_pos + 0]) |
|
||||
(ciphertext_buf[1] ^ cmp_ctx_buffer[aad_pos + 1]) << 8 |
|
||||
(ciphertext_buf[2] ^ cmp_ctx_buffer[aad_pos + 2]) << 16;
|
||||
BOOST_CHECK_EQUAL(len_cmp, expected_aad_length);
|
||||
|
||||
// encrypt / decrypt 1000 packets
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK(aead.GetLength(&out_len, seqnr_aad, aad_pos, ciphertext_buf.data()));
|
||||
BOOST_CHECK_EQUAL(out_len, expected_aad_length);
|
||||
res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, plaintext_buf_new.data(), plaintext_buf_new.size(), ciphertext_buf.data(), ciphertext_buf.size(), false);
|
||||
BOOST_CHECK(res);
|
||||
|
||||
// make sure we repetitive get the same plaintext
|
||||
BOOST_CHECK(memcmp(plaintext_buf.data(), plaintext_buf_new.data(), plaintext_buf.size()) == 0);
|
||||
|
||||
// compare sequence number 999 against the test vector
|
||||
if (seqnr_payload == 999) {
|
||||
BOOST_CHECK(memcmp(ciphertext_buf.data(), expected_ciphertext_and_mac_sequence999.data(), expected_ciphertext_and_mac_sequence999.size()) == 0);
|
||||
}
|
||||
// set nonce and block counter, output the keystream
|
||||
cmp_ctx.SetIV(seqnr_aad);
|
||||
cmp_ctx.Seek(0);
|
||||
cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
|
||||
|
||||
// crypt the 3 length bytes and compare the length
|
||||
len_cmp = 0;
|
||||
len_cmp = (ciphertext_buf[0] ^ cmp_ctx_buffer[aad_pos + 0]) |
|
||||
(ciphertext_buf[1] ^ cmp_ctx_buffer[aad_pos + 1]) << 8 |
|
||||
(ciphertext_buf[2] ^ cmp_ctx_buffer[aad_pos + 2]) << 16;
|
||||
BOOST_CHECK_EQUAL(len_cmp, expected_aad_length);
|
||||
|
||||
// increment the sequence number(s)
|
||||
// always increment the payload sequence number
|
||||
// increment the AAD keystream position by its size (3)
|
||||
// increment the AAD sequence number if we would hit the 64 byte limit
|
||||
seqnr_payload++;
|
||||
aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
|
||||
if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
|
||||
aad_pos = 0;
|
||||
seqnr_aad++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(chacha20_poly1305_aead_testvector)
|
||||
{
|
||||
/* test chacha20poly1305@bitcoin AEAD */
|
||||
|
||||
// must fail with no message
|
||||
TestChaCha20Poly1305AEAD(false, 0,
|
||||
"",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", "", "", "");
|
||||
|
||||
TestChaCha20Poly1305AEAD(true, 0,
|
||||
/* m */ "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
/* k1 (payload) */ "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
/* k2 (AAD) */ "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
/* AAD keystream */ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
|
||||
/* encrypted message & MAC */ "76b8e09f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32d2fc11829c1b6c1df1f551cd6131ff08",
|
||||
/* encrypted message & MAC at sequence 999 */ "b0a03d5bd2855d60699e7d3a3133fa47be740fe4e4c1f967555e2d9271f31c3aaa7aa16ec62c5e24f040c08bb20c3598");
|
||||
TestChaCha20Poly1305AEAD(true, 1,
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
|
||||
"77b8e09f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32baf0c85b6dff8602b06cf52a6aefc62e",
|
||||
"b1a03d5bd2855d60699e7d3a3133fa47be740fe4e4c1f967555e2d9271f31c3a8bd94d54b5ecabbc41ffbb0c90924080");
|
||||
TestChaCha20Poly1305AEAD(true, 255,
|
||||
"ff0000f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78fab78c9",
|
||||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
|
||||
"ff0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
|
||||
"c640c1711e3ee904ac35c57ab9791c8a1c408603a90b77a83b54f6c844cb4b06d94e7fc6c800e165acd66147e80ec45a567f6ce66d05ec0cae679dceeb890017",
|
||||
"3940c1e92da4582ff6f92a776aeb14d014d384eeb30f660dacf70a14a23fd31e91212701334e2ce1acf5199dc84f4d61ddbe6571bca5af874b4c9226c26e650995d157644e1848b96ed6c2102d5489a050e71d29a5a66ece11de5fb5c9558d54da28fe45b0bc4db4e5b88030bfc4a352b4b7068eccf656bae7ad6a35615315fc7c49d4200388d5eca67c2e822e069336c69b40db67e0f3c81209c50f3216a4b89fb3ae1b984b7851a2ec6f68ab12b101ab120e1ea7313bb93b5a0f71185c7fea017ddb92769861c29dba4fbc432280d5dff21b36d1c4c790128b22699950bb18bf74c448cdfe547d8ed4f657d8005fdc0cd7a050c2d46050a44c4376355858981fbe8b184288276e7a93eabc899c4a",
|
||||
"f039c6689eaeef0456685200feaab9d54bbd9acde4410a3b6f4321296f4a8ca2604b49727d8892c57e005d799b2a38e85e809f20146e08eec75169691c8d4f54a0d51a1e1c7b381e0474eb02f994be9415ef3ffcbd2343f0601e1f3b172a1d494f838824e4df570f8e3b0c04e27966e36c82abd352d07054ef7bd36b84c63f9369afe7ed79b94f953873006b920c3fa251a771de1b63da927058ade119aa898b8c97e42a606b2f6df1e2d957c22f7593c1e2002f4252f4c9ae4bf773499e5cfcfe14dfc1ede26508953f88553bf4a76a802f6a0068d59295b01503fd9a600067624203e880fdf53933b96e1f4d9eb3f4e363dd8165a278ff667a41ee42b9892b077cefff92b93441f7be74cf10e6cd");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(countbits_tests)
|
||||
{
|
||||
FastRandomContext ctx;
|
||||
|
Loading…
Reference in New Issue
Block a user