ext-cryptopp/validat0.cpp
2022-02-12 16:02:41 -05:00

1673 lines
61 KiB
C++

// validat0.cpp - originally written and placed in the public domain by Wei Dai and Jeffrey Walton
// Routines in this source file are only tested in Debug builds.
// Source files split in July 2018 to expedite compiles.
#include "pch.h"
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include "cryptlib.h"
#include "cpu.h"
#include "validate.h"
#include "asn.h"
#include "gf2n.h"
#include "default.h"
#include "integer.h"
#include "polynomi.h"
#include "channels.h"
#include "ida.h"
#include "gzip.h"
#include "zlib.h"
#include <iostream>
#include <iomanip>
#include <sstream>
// Aggressive stack checking with VS2005 SP1 and above.
#if (_MSC_FULL_VER >= 140050727)
# pragma strict_gs_check (on)
#endif
#if CRYPTOPP_MSC_VERSION
# pragma warning(disable: 4505 4355)
#endif
NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)
#if defined(CRYPTOPP_EXTENDED_VALIDATION)
// Issue 64: "PolynomialMod2::operator<<=", http://github.com/weidai11/cryptopp/issues/64
bool TestPolynomialMod2()
{
std::cout << "\nTesting PolynomialMod2 bit operations...\n\n";
bool pass1 = true, pass2 = true, pass3 = true;
const unsigned int start = 0;
const unsigned int stop = 4 * WORD_BITS + 1;
for (unsigned int i = start; i < stop; i++)
{
PolynomialMod2 p(1);
p <<= i;
Integer n(Integer::One());
n <<= i;
std::ostringstream oss1;
oss1 << p;
std::string str1, str2;
// str1 needs the commas removed used for grouping
str1 = oss1.str();
str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end());
// str1 needs the trailing 'b' removed
str1.erase(str1.end() - 1);
// str2 is fine as-is
str2 = IntToString(n, 2);
pass1 &= (str1 == str2);
}
for (unsigned int i = start; i < stop; i++)
{
const word w((word)SIZE_MAX);
PolynomialMod2 p(w);
p <<= i;
Integer n(Integer::POSITIVE, static_cast<lword>(w));
n <<= i;
std::ostringstream oss1;
oss1 << p;
std::string str1, str2;
// str1 needs the commas removed used for grouping
str1 = oss1.str();
str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end());
// str1 needs the trailing 'b' removed
str1.erase(str1.end() - 1);
// str2 is fine as-is
str2 = IntToString(n, 2);
pass2 &= (str1 == str2);
}
RandomNumberGenerator& prng = GlobalRNG();
for (unsigned int i = start; i < stop; i++)
{
word w; // Cast to lword due to Visual Studio
prng.GenerateBlock((byte*)&w, sizeof(w));
PolynomialMod2 p(w);
p <<= i;
Integer n(Integer::POSITIVE, static_cast<lword>(w));
n <<= i;
std::ostringstream oss1;
oss1 << p;
std::string str1, str2;
// str1 needs the commas removed used for grouping
str1 = oss1.str();
str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end());
// str1 needs the trailing 'b' removed
str1.erase(str1.end() - 1);
// str2 is fine as-is
str2 = IntToString(n, 2);
if (str1 != str2)
{
std::cout << " Oops..." << "\n";
std::cout << " random: " << std::hex << n << std::dec << "\n";
std::cout << " str1: " << str1 << "\n";
std::cout << " str2: " << str2 << "\n";
}
pass3 &= (str1 == str2);
}
std::cout << (!pass1 ? "FAILED" : "passed") << ": " << "1 shifted over range [" << std::dec << start << "," << stop << "]" << "\n";
std::cout << (!pass2 ? "FAILED" : "passed") << ": " << "0x" << std::hex << word(SIZE_MAX) << std::dec << " shifted over range [" << start << "," << stop << "]" << "\n";
std::cout << (!pass3 ? "FAILED" : "passed") << ": " << "random values shifted over range [" << std::dec << start << "," << stop << "]" << "\n";
return pass1 && pass2 && pass3;
}
#endif
#if defined(CRYPTOPP_EXTENDED_VALIDATION)
bool TestCompressors()
{
std::cout << "\nTesting Compressors and Decompressors...\n\n";
bool fail1 = false, fail2 = false, fail3 = false;
const unsigned int COMP_COUNT = 64;
try
{
// Gzip uses Adler32 checksums. We expect a failure to happen on occasion.
// If we see more than 2 failures in a run of 128, then we need to investigate.
unsigned int truncatedCount=0;
for (unsigned int i = 0; i<COMP_COUNT; ++i)
{
std::string src, dest, rec;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
StringSource(src, true, new Gzip(new StringSink(dest)));
StringSource(dest, true, new Gunzip(new StringSink(rec)));
if (src != rec)
throw Exception(Exception::OTHER_ERROR, "Gzip failed to decompress stream");
// Tamper
try {
StringSource(dest.substr(0, len - 2), true, new Gunzip(new StringSink(rec)));
if (truncatedCount++ >= 2)
{
std::cout << "FAILED: Gzip failed to detect a truncated stream\n";
fail1 = true;
}
}
catch (const Exception&) {}
}
}
catch (const Exception& ex)
{
std::cout << "FAILED: " << ex.what() << "\n";
fail1 = true;
}
// **************************************************************
// Gzip Filename, Filetime and Comment
try
{
std::string filename = "test.txt";
std::string comment = "This is a test";
word32 filetime = GlobalRNG().GenerateWord32(4, 0xffffff);
AlgorithmParameters params = MakeParameters(Name::FileTime(), (int)filetime)
(Name::FileName(), ConstByteArrayParameter(filename.c_str(), false))
(Name::Comment(), ConstByteArrayParameter(comment.c_str(), false));
std::string src, dest;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
Gunzip unzip(new StringSink(dest));
StringSource(src, true, new Gzip(params, new Redirector(unzip)));
if (filename != unzip.GetFilename())
throw Exception(Exception::OTHER_ERROR, "Failed to retrieve filename");
if (filetime != unzip.GetFiletime())
throw Exception(Exception::OTHER_ERROR, "Failed to retrieve filetime");
if (comment != unzip.GetComment())
throw Exception(Exception::OTHER_ERROR, "Failed to retrieve comment");
std::cout << "passed: filenames, filetimes and comments\n";
}
catch (const Exception& ex)
{
std::cout << "FAILED: " << ex.what() << "\n";
}
// Unzip random data. See if we can induce a crash
for (unsigned int i = 0; i<COMP_COUNT; i++)
{
SecByteBlock src;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
RandomNumberSource(GlobalRNG(), len, true, new ArraySink(src, src.size()));
try {
ArraySource(src.data(), src.size(), true, new Gunzip(new Redirector(TheBitBucket())));
}
catch (const Exception&) {}
}
// Unzip random data. See if we can induce a crash
for (unsigned int i = 0; i<COMP_COUNT; i++)
{
SecByteBlock src;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
src.resize(len);
RandomNumberSource(GlobalRNG(), len, true, new ArraySink(src, src.size()));
src[0] = (byte)0x1f; // magic header
src[1] = (byte)0x8b;
src[2] = 0x00; // extra flags
src[3] = src[3] & (2 | 4 | 8 | 16 | 32); // flags
// Commit d901ecd9a4de added Filenames, Filetimes and Comments. Gzip does
// not specify a length for them; rather, they are NULL terminated. We add
// a couple of NULLs in random places near filenames and comments to ensure
// we are getting coverage in areas beyond the header.
len = GlobalRNG().GenerateWord32(12, 24);
if (len < src.size()) // guard it to ensure in-bounds
src[len] = (byte)0x00;
len = GlobalRNG().GenerateWord32(12+len, 24+len);
if (len < src.size()) // guard it to ensure in-bounds
src[len] = (byte)0x00;
// The remainder are extra headers and the payload
try {
ArraySource(src.data(), src.size(), true, new Gunzip(new Redirector(TheBitBucket())));
}
catch (const Exception&) {}
}
if (!fail1)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " " << COMP_COUNT << " zips and unzips" << std::endl;
// **************************************************************
try
{
for (unsigned int i = 0; i<COMP_COUNT; ++i)
{
std::string src, dest, rec;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
StringSource(src, true, new Deflator(new StringSink(dest)));
StringSource(dest, true, new Inflator(new StringSink(rec)));
if (src != rec)
throw Exception(Exception::OTHER_ERROR, "Inflate failed to decompress stream");
// Tamper
try {
StringSource(dest.substr(0, len - 2), true, new Gunzip(new StringSink(rec)));
std::cout << "FAILED: Inflate failed to detect a truncated stream\n";
fail2 = true;
}
catch (const Exception&) {}
}
}
catch (const Exception& ex)
{
std::cout << "FAILED: " << ex.what() << "\n";
fail2 = true;
}
// **************************************************************
// Inflate random data. See if we can induce a crash
for (unsigned int i = 0; i<COMP_COUNT; i++)
{
SecByteBlock src;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
src.resize(len);
RandomNumberSource(GlobalRNG(), len, true, new ArraySink(src, src.size()));
src[0] = (byte)0x1f; // magic header
src[1] = (byte)0x8b;
src[2] = 0x00; // extra flags
src[3] = src[3] & (2 | 4 | 8 | 16 | 32); // flags
// Don't allow ENCRYPTED|CONTINUED to over-run tests
if (src[3] & (2 | 32)) {
if (i % 3 == 0) { src[3] &= ~2; }
if (i % 3 == 1) { src[3] &= ~32; }
}
// The remainder are extra headers and the payload
try {
ArraySource(src.data(), src.size(), true, new Inflator(new Redirector(TheBitBucket())));
}
catch (const Exception&) {}
}
// Inflate random data. See if we can induce a crash
for (unsigned int i = 0; i<COMP_COUNT; i++)
{
SecByteBlock src;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
RandomNumberSource(GlobalRNG(), len, true, new ArraySink(src, src.size()));
try {
ArraySource(src.data(), src.size(), true, new Inflator(new Redirector(TheBitBucket())));
}
catch (const Exception&) {}
}
if (!fail2)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " " << COMP_COUNT << " deflates and inflates\n";
// **************************************************************
try
{
for (unsigned int i = 0; i<COMP_COUNT; ++i)
{
std::string src, dest, rec;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
StringSource(src, true, new ZlibCompressor(new StringSink(dest)));
StringSource(dest, true, new ZlibDecompressor(new StringSink(rec)));
if (src != rec)
throw Exception(Exception::OTHER_ERROR, "Zlib failed to decompress stream");
// Tamper
try {
StringSource(dest.substr(0, len - 2), true, new Gunzip(new StringSink(rec)));
std::cout << "FAILED: Zlib failed to detect a truncated stream\n";
fail3 = true;
}
catch (const Exception&) {}
}
}
catch (const Exception& ex)
{
std::cout << "FAILED: " << ex.what() << "\n";
fail3 = true;
}
// **************************************************************
// Decompress random data. See if we can induce a crash
for (unsigned int i = 0; i<COMP_COUNT; i++)
{
SecByteBlock src;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff);
src.resize(len);
RandomNumberSource(GlobalRNG(), len, true, new ArraySink(src, src.size()));
// CMF byte
src[0] = (byte)(GlobalRNG().GenerateWord32(0, 14) << 4);
src[0] |= (byte)(GlobalRNG().GenerateWord32(0, 7));
// FLG byte
src[1] = (byte)(GlobalRNG().GenerateWord32(0, 7) << 5);
src[1] |= (byte)(31 - (src[0] * 256 + src[1]) % 31);
// The remainder are the payload, but missing Adler32
try {
ArraySource(src.data(), src.size(), true, new ZlibDecompressor(new Redirector(TheBitBucket())));
}
catch (const Exception&) {}
}
if (!fail3)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " " << COMP_COUNT << " zlib decompress and compress" << std::endl;
// **************************************************************
return !fail1 && !fail2 && !fail3;
}
bool TestEncryptors()
{
std::cout << "\nTesting Default Encryptors and Decryptors...\n\n";
const unsigned int ENCRYPT_COUNT = 64, ENCRYPT_MAC_COUNT = 64;
bool fail0 = false, fail1 = false, fail2 = false, fail3 = false, fail4 = false;
// **************************************************************
try
{
// Common password and message.
std::string password = "super secret password";
std::string recovered, message = "Now is the time for all good men to come to the aide of their country.";
// This data was generated with Crypto++ 5.6.2
//StringSource(message, true, new LegacyEncryptorWithMAC(password.c_str(), new FileSink("TestData/defdmac1.bin")));
FileSource(DataDir("TestData/defdmac1.bin").c_str(), true, new LegacyDecryptorWithMAC(password.c_str(), new StringSink(recovered)));
if (message != recovered)
throw Exception(Exception::OTHER_ERROR, "LegacyDecryptorWithMAC failed a self test");
// Reset sink
recovered.clear();
// This data was generated with Crypto++ 6.0
//StringSource(message, true, new DefaultEncryptorWithMAC(password.c_str(), new FileSink("TestData/defdmac2.bin")));
FileSource(DataDir("TestData/defdmac2.bin").c_str(), true, new DefaultDecryptorWithMAC(password.c_str(), new StringSink(recovered)));
if (message != recovered)
throw Exception(Exception::OTHER_ERROR, "DefaultDecryptorWithMAC failed a self test");
}
catch(const Exception&)
{
fail0 = true;
}
if (!fail0)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " cross-platform decryption with MAC of binary file" << std::endl;
// **************************************************************
try
{
for (unsigned int i=0; i<ENCRYPT_COUNT; ++i)
{
std::string pwd, src, dest, rec;
unsigned int len = GlobalRNG().GenerateWord32(8, 0xfff);
unsigned int plen = GlobalRNG().GenerateWord32(0, 32);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
RandomNumberSource(GlobalRNG(), plen, true, new HexEncoder(new StringSink(pwd)));
StringSource(src, true, new DefaultEncryptor(pwd.c_str(), new StringSink(dest)));
StringSource(dest, true, new DefaultDecryptor(pwd.c_str(), new StringSink(rec)));
if (src != rec)
throw Exception(Exception::OTHER_ERROR, "DefaultEncryptor failed a self test");
}
}
catch(const Exception&)
{
fail1 = true;
}
if (!fail1)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " " << ENCRYPT_COUNT << " default encryptions and decryptions" << std::endl;
// **************************************************************
try
{
for (unsigned int i=0; i<ENCRYPT_MAC_COUNT; ++i)
{
const unsigned int runt = EnumToInt(DefaultEncryptorWithMAC::SALTLENGTH) + EnumToInt(DefaultEncryptorWithMAC::KEYLENGTH);
std::string pwd, src, dest, rec;
unsigned int len = GlobalRNG().GenerateWord32(runt, 0xfff);
unsigned int plen = GlobalRNG().GenerateWord32(0, 32);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
RandomNumberSource(GlobalRNG(), plen, true, new HexEncoder(new StringSink(pwd)));
StringSource(src, true, new DefaultEncryptorWithMAC(pwd.c_str(),new StringSink(dest)));
StringSource(dest, true, new DefaultDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
if (src != rec)
throw Exception(Exception::OTHER_ERROR, "DefaultEncryptorWithMAC failed a self test");
// Tamper with the stream. Data format is [SALT][KEYCHECK][ENCRYPTED DATA].
try {
StringSource(dest.substr(0, len-2), true, new DefaultDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: DefaultDecryptorWithMAC failed to detect a truncated stream\n";
fail2 = true;
} catch(const Exception&) { }
try {
// tamper salt
dest[DefaultDecryptorWithMAC::SALTLENGTH/2] ^= 0x01;
StringSource(dest, true, new DefaultDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: DefaultDecryptorWithMAC failed to detect a tampered salt\n";
fail2 = true;
} catch(const Exception&) { }
try {
// undo previous tamper
dest[DefaultDecryptorWithMAC::SALTLENGTH/2] ^= 0x01;
// tamper keycheck
dest[DefaultDecryptorWithMAC::SALTLENGTH+DefaultDecryptorWithMAC::KEYLENGTH/2] ^= 0x01;
StringSource(dest, true, new DefaultDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: DefaultDecryptorWithMAC failed to detect a tampered keycheck\n";
fail2 = true;
} catch(const Exception&) { }
try {
// undo previous tamper
dest[DefaultDecryptorWithMAC::SALTLENGTH+DefaultDecryptorWithMAC::KEYLENGTH/2] ^= 0x01;
// tamper encrypted data
dest[dest.size()-2] ^= 0x01;
StringSource(dest, true, new DefaultDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: DefaultDecryptorWithMAC failed to detect a tampered data\n";
fail2 = true;
} catch(const Exception&) { }
}
}
catch(const Exception&)
{
fail2 = true;
}
if (!fail2)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " " << ENCRYPT_MAC_COUNT << " default encryptions and decryptions with MAC" << std::endl;
// **************************************************************
try
{
for (unsigned int i=0; i<ENCRYPT_COUNT; ++i)
{
std::string pwd, src, dest, rec;
unsigned int len = GlobalRNG().GenerateWord32(16, 0xfff);
unsigned int plen = GlobalRNG().GenerateWord32(0, 32);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
RandomNumberSource(GlobalRNG(), plen, true, new HexEncoder(new StringSink(pwd)));
StringSource(src, true, new LegacyEncryptor(pwd.c_str(),new StringSink(dest)));
StringSource(dest, true, new LegacyDecryptor(pwd.c_str(),new StringSink(rec)));
if (src != rec)
throw Exception(Exception::OTHER_ERROR, "LegacyEncryptor failed a self test");
}
}
catch(const Exception&)
{
fail3 = true;
}
if (!fail3)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " " << ENCRYPT_COUNT << " legacy encryptions and decryptions" << std::endl;
// **************************************************************
try
{
for (unsigned int i=0; i<ENCRYPT_MAC_COUNT; ++i)
{
const unsigned int runt = EnumToInt(LegacyDecryptorWithMAC::SALTLENGTH) + EnumToInt(LegacyDecryptorWithMAC::KEYLENGTH);
std::string pwd, src, dest, rec;
unsigned int len = GlobalRNG().GenerateWord32(runt, 0xfff);
unsigned int plen = GlobalRNG().GenerateWord32(0, 32);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(src));
RandomNumberSource(GlobalRNG(), plen, true, new HexEncoder(new StringSink(pwd)));
StringSource(src, true, new LegacyEncryptorWithMAC(pwd.c_str(), new StringSink(dest)));
StringSource(dest, true, new LegacyDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
if (src != rec)
throw Exception(Exception::OTHER_ERROR, "LegacyEncryptorWithMAC failed a self test");
// Tamper with the stream. Data format is [SALT][KEYCHECK][ENCRYPTED DATA].
try {
StringSource(dest.substr(0, len-2), true, new LegacyDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: LegacyEncryptorWithMAC failed to detect a truncated stream\n";
fail4 = true;
} catch(const Exception&) { }
try {
// tamper salt
dest[LegacyEncryptorWithMAC::SALTLENGTH/2] ^= 0x01;
StringSource(dest, true, new LegacyDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: LegacyEncryptorWithMAC failed to detect a tampered salt\n";
fail4 = true;
} catch(const Exception&) { }
try {
// undo previous tamper
dest[LegacyEncryptorWithMAC::SALTLENGTH/2] ^= 0x01;
// tamper keycheck
dest[LegacyEncryptorWithMAC::SALTLENGTH+LegacyEncryptorWithMAC::KEYLENGTH/2] ^= 0x01;
StringSource(dest, true, new LegacyDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: LegacyEncryptorWithMAC failed to detect a tampered keycheck\n";
fail4 = true;
} catch(const Exception&) { }
try {
// undo previous tamper
dest[LegacyEncryptorWithMAC::SALTLENGTH+LegacyEncryptorWithMAC::KEYLENGTH/2] ^= 0x01;
// tamper encrypted data
dest[dest.size()-2] ^= 0x01;
StringSource(dest, true, new LegacyDecryptorWithMAC(pwd.c_str(), new StringSink(rec)));
std::cout << "FAILED: LegacyEncryptorWithMAC failed to detect a tampered data\n";
fail4 = true;
} catch(const Exception&) { }
}
}
catch(const Exception&)
{
fail4 = true;
}
if (!fail4)
std::cout << "passed:";
else
std::cout << "FAILED:";
std::cout << " " << ENCRYPT_MAC_COUNT << " legacy encryptions and decryptions with MAC" << std::endl;
return !fail0 && !fail1 && !fail2 && !fail3 && !fail4;
}
// Information Dispesal and Secret Sharing
bool TestSharing()
{
std::cout << "\nInformation Dispersal and Secret Sharing...\n\n";
const unsigned int INFORMATION_SHARES = 64;
const unsigned int SECRET_SHARES = 64;
const unsigned int CHID_LENGTH = 4;
bool pass=true, fail=false;
// ********** Infrmation Dispersal **********//
for (unsigned int shares=3; shares<INFORMATION_SHARES; ++shares)
{
std::string message;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xff);
unsigned int threshold = GlobalRNG().GenerateWord32(2, shares-1);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(message));
ChannelSwitch *channelSwitch = NULLPTR;
StringSource source(message, false, new InformationDispersal(threshold, shares, channelSwitch = new ChannelSwitch));
std::vector<std::string> strShares(shares);
vector_member_ptrs<StringSink> strSinks(shares);
std::string channel;
// ********** Create Shares
for (unsigned int i=0; i<shares; i++)
{
strSinks[i].reset(new StringSink(strShares[i]));
channel = WordToString<word32>(i);
strSinks[i]->Put((const byte *)channel.data(), CHID_LENGTH);
channelSwitch->AddRoute(channel, *strSinks[i], DEFAULT_CHANNEL);
}
source.PumpAll();
// ********** Randomize shares
GlobalRNG().Shuffle(strShares.begin(), strShares.end());
// ********** Recover secret
try
{
std::string recovered;
InformationRecovery recovery(threshold, new StringSink(recovered));
vector_member_ptrs<StringSource> strSources(threshold);
channel.resize(CHID_LENGTH);
for (unsigned int i=0; i<threshold; i++)
{
strSources[i].reset(new StringSource(strShares[i], false));
strSources[i]->Pump(CHID_LENGTH);
strSources[i]->Get((byte*)&channel[0], CHID_LENGTH);
strSources[i]->Attach(new ChannelSwitch(recovery, channel));
}
while (strSources[0]->Pump(256))
{
for (unsigned int i=1; i<threshold; i++)
strSources[i]->Pump(256);
}
for (unsigned int i=0; i<threshold; i++)
strSources[i]->PumpAll();
fail = (message != recovered);
}
catch (const Exception&)
{
fail = true;
}
pass &= !fail;
}
std::cout << (fail ? "FAILED:" : "passed:") << " " << INFORMATION_SHARES << " information dispersals\n";
// ********** Secret Sharing **********//
for (unsigned int shares=3; shares<SECRET_SHARES; ++shares)
{
std::string message;
unsigned int len = GlobalRNG().GenerateWord32(4, 0xff);
unsigned int threshold = GlobalRNG().GenerateWord32(2, shares-1);
RandomNumberSource(GlobalRNG(), len, true, new StringSink(message));
ChannelSwitch *channelSwitch = NULLPTR;
StringSource source(message, false, new SecretSharing(GlobalRNG(), threshold, shares, channelSwitch = new ChannelSwitch));
std::vector<std::string> strShares(shares);
vector_member_ptrs<StringSink> strSinks(shares);
std::string channel;
// ********** Create Shares
for (unsigned int i=0; i<shares; i++)
{
strSinks[i].reset(new StringSink(strShares[i]));
channel = WordToString<word32>(i);
strSinks[i]->Put((const byte *)channel.data(), CHID_LENGTH);
channelSwitch->AddRoute(channel, *strSinks[i], DEFAULT_CHANNEL);
}
source.PumpAll();
// ********** Randomize shares
GlobalRNG().Shuffle(strShares.begin(), strShares.end());
// ********** Recover secret
try
{
std::string recovered;
SecretRecovery recovery(threshold, new StringSink(recovered));
vector_member_ptrs<StringSource> strSources(threshold);
channel.resize(CHID_LENGTH);
for (unsigned int i=0; i<threshold; i++)
{
strSources[i].reset(new StringSource(strShares[i], false));
strSources[i]->Pump(CHID_LENGTH);
strSources[i]->Get((byte*)&channel[0], CHID_LENGTH);
strSources[i]->Attach(new ChannelSwitch(recovery, channel));
}
while (strSources[0]->Pump(256))
{
for (unsigned int i=1; i<threshold; i++)
strSources[i]->Pump(256);
}
for (unsigned int i=0; i<threshold; i++)
strSources[i]->PumpAll();
fail = (message != recovered);
}
catch (const Exception&)
{
fail = true;
}
pass &= !fail;
}
std::cout << (fail ? "FAILED:" : "passed:") << " " << SECRET_SHARES << " secret sharings\n";
return pass;
}
bool TestRounding()
{
std::cout << "\nTesting RoundUpToMultipleOf/RoundDownToMultipleOf...\n\n";
bool pass=true, fail;
// ********** byte **********//
try
{
const byte v=0, b=0x08;
byte r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n";
try
{
const byte v=1, b=0x08;
byte r=RoundUpToMultipleOf(v, b);
fail = (r != b);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n";
try
{
const byte v=0x08, b=0x08;
byte r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n";
try
{
const byte v=0xf7, b=0x08;
byte r=RoundUpToMultipleOf(v, b);
fail = (r != 0xf8);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n";
try
{
const byte v=0xf8, b=0x08;
byte r=RoundUpToMultipleOf(v, b);
fail = (r != 0xf8);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n";
try
{
const byte v=0xf9, b=0x08;
byte r=RoundUpToMultipleOf(v, b);
CRYPTOPP_UNUSED(r);
fail = true;
}
catch(const Exception&)
{
fail = false;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, overflow\n";
// ********** word16 **********//
try
{
const word16 v=0, b=0x08;
word16 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n";
try
{
const word16 v=1, b=0x08;
word16 r=RoundUpToMultipleOf(v, b);
fail = (r != b);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n";
try
{
const word16 v=0x08, b=0x08;
word16 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n";
try
{
const word16 v=0xfff7, b=0x08;
word16 r=RoundUpToMultipleOf(v, b);
fail = (r != 0xfff8);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n";
try
{
const word16 v=0xfff8, b=0x08;
word16 r=RoundUpToMultipleOf(v, b);
fail = (r != 0xfff8);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n";
try
{
const word16 v=0xfff9, b=0x08;
word16 r=RoundUpToMultipleOf(v, b);
CRYPTOPP_UNUSED(r);
fail = true;
}
catch(const Exception&)
{
fail = false;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, overflow\n";
// ********** word32 **********//
try
{
const word32 v=0, b=0x08;
word32 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n";
try
{
const word32 v=1, b=0x08;
word32 r=RoundUpToMultipleOf(v, b);
fail = (r != b);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n";
try
{
const word32 v=0x08, b=0x08;
word32 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n";
try
{
const word32 v=0xfffffff7, b=0x08;
word32 r=RoundUpToMultipleOf(v, b);
fail = (r != 0xfffffff8);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n";
try
{
const word32 v=0xfffffff8, b=0x08;
word32 r=RoundUpToMultipleOf(v, b);
fail = (r != 0xfffffff8);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n";
try
{
const word32 v=0xfffffff9, b=0x08;
word32 r=RoundUpToMultipleOf(v, b);
CRYPTOPP_UNUSED(r);
fail = true;
}
catch(const Exception&)
{
fail = false;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, overflow\n";
// ********** word64 **********//
try
{
const word64 v=0, b=0x08;
word64 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n";
try
{
const word64 v=1, b=0x08;
word64 r=RoundUpToMultipleOf(v, b);
fail = (r != b);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n";
try
{
const word64 v=0x08, b=0x08;
word64 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n";
try
{
const word64 v=W64LIT(0xffffffffffffff7), b=0x08;
word64 r=RoundUpToMultipleOf(v, b);
fail = (r != W64LIT(0xffffffffffffff8));
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n";
try
{
const word64 v=W64LIT(0xffffffffffffff8), b=0x08;
word64 r=RoundUpToMultipleOf(v, b);
fail = (r != W64LIT(0xffffffffffffff8));
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n";
try
{
const word64 v=W64LIT(0xfffffffffffffff9), b=0x08;
word64 r=RoundUpToMultipleOf(v, b);
CRYPTOPP_UNUSED(r);
fail = true;
}
catch(const Exception&)
{
fail = false;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, overflow\n";
#if defined(CRYPTOPP_WORD128_AVAILABLE)
// ********** word128 **********//
try
{
const word128 v=0, b=0x08;
word128 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n";
try
{
const word128 v=1, b=0x08;
word128 r=RoundUpToMultipleOf(v, b);
fail = (r != b);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n";
try
{
const word128 v=0x08, b=0x08;
word128 r=RoundUpToMultipleOf(v, b);
fail = (r != v);
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n";
try
{
// http://stackoverflow.com/q/31461318/608639
const word128 h = ((word128)W64LIT(0xffffffffffffffff)) << 64U;
const word128 v = h | (word128)W64LIT(0xfffffffffffffff7), b=0x08;
word128 r=RoundUpToMultipleOf(v, b);
fail = (r != (h | (word128)W64LIT(0xfffffffffffffff8)));
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n";
try
{
const word128 h = ((word128)W64LIT(0xffffffffffffffff)) << 64U;
const word128 v = h | (word128)W64LIT(0xfffffffffffffff8), b=0x08;
word128 r=RoundUpToMultipleOf(v, b);
fail = (r != (h | (word128)W64LIT(0xfffffffffffffff8)));
}
catch(const Exception&)
{
fail = true;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n";
try
{
const word128 h = ((word128)W64LIT(0xffffffffffffffff)) << 64U;
const word128 v = h | (word128)W64LIT(0xfffffffffffffff9), b=0x08;
word128 r=RoundUpToMultipleOf(v, b);
CRYPTOPP_UNUSED(r);
fail = true;
}
catch(const Exception&)
{
fail = false;
}
pass = !fail && pass;
std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, overflow\n";
#endif
return pass;
}
#endif
#if defined(CRYPTOPP_EXTENDED_VALIDATION)
struct ASN1_TestTuple
{
ASN1_TestTuple(int tag, int result, const char* data, size_t len) {
m_result = result;
m_tag = tag;
m_data = std::string(data, len);
}
std::string Name() const {
return Id2String();
}
const byte* Data() const {
return ConstBytePtr(m_data);
}
size_t Size() const {
return BytePtrSize(m_data);
}
int Tag() const {
return m_tag;
}
int Result() const {
return m_result;
}
std::string Id2String() const
{
switch(m_tag)
{
case BIT_STRING:
return "BIT_STRING";
case OCTET_STRING:
return "OCTET_STRING";
case INTEGER:
return "INTEGER";
case UTF8_STRING:
return "UTF8_STRING";
case PRINTABLE_STRING:
return "PRINTABLE_STRING";
case IA5_STRING:
return "IA5_STRING";
default:
return "Unknown";
}
}
protected:
std::string m_data;
int m_tag, m_result;
};
bool RunASN1TestSet(const ASN1_TestTuple asnTuples[], size_t count)
{
bool pass=true, fail;
// Disposition
enum {REJECT=3, ACCEPT=4};
for(size_t i=0; i<count; i++)
{
const ASN1_TestTuple & thisTest = asnTuples[i];
ArraySource as1(thisTest.Data(), thisTest.Size(), true);
ArraySource as2(thisTest.Data(), thisTest.Size(), true);
SecByteBlock unused1;
std::string unused2;
unsigned int unused3;
word32 unused4;
word64 unused5;
// Reporting
std::string val;
HexEncoder encoder(new StringSink(val));
encoder.Put(thisTest.Data(), thisTest.Size());
encoder.MessageEnd();
try
{
byte tag = (byte)thisTest.Tag();
switch (tag)
{
case BIT_STRING:
BERDecodeBitString(as1, unused1, unused3);
break;
case OCTET_STRING:
BERDecodeOctetString(as1, unused1);
break;
case INTEGER:
BERDecodeUnsigned(as1, unused4);
BERDecodeUnsigned<word64>(as2, unused5, byte(INTEGER), 0, W64LIT(0xffffffffffffffff));
break;
case UTF8_STRING: case PRINTABLE_STRING: case IA5_STRING:
BERDecodeTextString(as1, unused2, tag);
break;
default:
BERGeneralDecoder(as1, tag);
break;
}
fail = thisTest.Result() != ACCEPT;
}
catch(const Exception&)
{
fail = thisTest.Result() != REJECT;
}
std::cout << (fail ? "FAILED:" : "passed:") << (thisTest.Result() == ACCEPT ? " accept " : " reject ");
std::cout << asnTuples[i].Name() << " " << val << "\n";
pass = !fail && pass;
}
return pass;
}
bool TestASN1Parse()
{
std::cout << "\nTesting ASN.1 parser...\n\n";
bool pass = true;
// Disposition
enum {REJECT=3, ACCEPT=4};
// All the types Crypto++ recognizes.
// "C" is one content octet with value 0x43.
const ASN1_TestTuple bitStrings[] =
{
// The first "\x00" content octet is the "initial octet" representing unused bits. In the
// primitive encoding form, there may be zero, one or more contents after the initial octet.
ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x01" "\x00", 3), // definite length, short form, initial octet, zero subsequent octets
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x01" "\x08", 3), // definite length, short form, initial octet, zero subsequent octets
ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x02" "\x00" "C", 4), // definite length, short form, expected subsequent octets
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x02" "\x08" "C", 4), // too many unused bits
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x7F" "\x00" "C", 4), // runt or underrun
ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x81\x01" "\x00", 4), // definite length, long form, initial octet, zero subsequent octets
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x81\x01" "\x08", 4), // definite length, long form, initial octet, zero subsequent octets
ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x81\x02" "\x00" "C", 5), // definite length, long form
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x81\x02" "\x08" "C", 5), // too many unused bits
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x81\xff" "\x00" "C", 5), // runt or underrun
ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x82\x00\x02" "\x00" "C", 6), // definite length, long form
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x82\x00\x02" "\x08" "C", 6), // too many unused bits
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x82\xff\xff" "\x00" "C", 6), // runt or underrun
ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x83\x00\x00\x02" "\x00" "C", 7), // definite length, long form
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x83\x00\x00\x02" "\x08" "C", 7), // too many unused bits
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x83\xff\xff\xff" "\x00" "C", 7), // runt or underrun
ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x84\x00\x00\x00\x02" "\x00" "C", 8), // definite length, long form
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x84\x00\x00\x00\x02" "\x08" "C", 8), // too many unused bits
ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x84\xff\xff\xff\xff" "\x00" "C", 8), // <== Issue 346; requires large allocation
};
pass = RunASN1TestSet(bitStrings, COUNTOF(bitStrings)) && pass;
const ASN1_TestTuple octetStrings[] =
{
// In the primitive encoding form, there may be zero, one or more contents.
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x00", 2), // definite length, short form, zero content octets
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x01" "C", 3), // definite length, short form, expected content octets
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x02" "C", 3), // runt or underrun
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x7F" "C", 3), // runt or underrun
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x81\x00", 3), // definite length, long form, zero content octets
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x81\x01" "C", 4), // definite length, long form, expected content octets
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x81\x02" "C", 4), // runt or underrun
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x81\xff" "C", 4), // runt or underrun
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x82\x00\x00", 4), // definite length, long form, zero content octets
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x82\x00\x01" "C", 5), // definite length, long form, expected content octets
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x82\x00\x02" "C", 5), // runt or underrun
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x82\xff\xff" "C", 5), // runt or underrun
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x83\x00\x00\x00", 5), // definite length, long form, zero content octets
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x83\x00\x00\x02" "C", 6), // runt or underrun
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x83\xff\xff\xff" "C", 6), // runt or underrun
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets
ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x84\x00\x00\x00\x02" "C", 7), // runt or underrun
ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation
};
pass = RunASN1TestSet(octetStrings, COUNTOF(octetStrings)) && pass;
const ASN1_TestTuple utf8Strings[] =
{
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x00", 2), // definite length, short form, zero content octets
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x01" "C", 3), // definite length, short form, expected content octets
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x02" "C", 3), // runt or underrun
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x7F" "C", 3), // runt or underrun
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x81\x00", 3), // definite length, long form, zero content octets
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x81\x01" "C", 4), // definite length, long form, expected content octets
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x81\x02" "C", 4), // runt or underrun
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x81\xff" "C", 4), // runt or underrun
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x82\x00\x00", 4), // definite length, long form, zero content octets
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x82\x00\x01" "C", 5), // definite length, long form, expected content octets
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x82\x00\x02" "C", 5), // runt or underrun
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x82\xff\xff" "C", 5), // runt or underrun
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x83\x00\x00\x00", 5), // definite length, long form, zero content octets
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x83\x00\x00\x02" "C", 6), // runt or underrun
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x83\xff\xff\xff" "C", 6), // runt or underrun
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets
ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x84\x00\x00\x00\x02" "C", 7), // runt or underrun
ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation
};
pass = RunASN1TestSet(utf8Strings, COUNTOF(utf8Strings)) && pass;
const ASN1_TestTuple printableStrings[] =
{
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x00", 2), // definite length, short form, zero content octets
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x01" "C", 3), // definite length, short form, expected content octets
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x02" "C", 3), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x7F" "C", 3), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x81\x00", 3), // definite length, long form, zero content octets
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x81\x01" "C", 4), // definite length, long form, expected content octets
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x81\x02" "C", 4), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x81\xff" "C", 4), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x82\x00\x00", 4), // definite length, long form, zero content octets
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x82\x00\x01" "C", 5), // definite length, long form, expected content octets
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x82\x00\x02" "C", 5), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x82\xff\xff" "C", 5), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x83\x00\x00\x00", 5), // definite length, long form, zero content octets
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x83\x00\x00\x02" "C", 6), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x83\xff\xff\xff" "C", 6), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets
ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x84\x00\x00\x00\x02" "C", 7), // runt or underrun
ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation
};
pass = RunASN1TestSet(printableStrings, COUNTOF(printableStrings)) && pass;
const ASN1_TestTuple ia5Strings[] =
{
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x00", 2), // definite length, short form, zero content octets
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x01" "C", 3), // definite length, short form, expected content octets
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x02" "C", 3), // runt or underrun
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x7F" "C", 3), // runt or underrun
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x81\x00", 3), // definite length, long form, zero content octets
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x81\x01" "C", 4), // definite length, long form, expected content octets
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x81\x02" "C", 4), // runt or underrun
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x81\xff" "C", 4), // runt or underrun
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x82\x00\x00", 4), // definite length, long form, zero content octets
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x82\x00\x01" "C", 5), // definite length, long form, expected content octets
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x82\x00\x02" "C", 5), // runt or underrun
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x82\xff\xff" "C", 5), // runt or underrun
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x83\x00\x00\x00", 5), // definite length, long form, zero content octets
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x83\x00\x00\x02" "C", 6), // runt or underrun
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x83\xff\xff\xff" "C", 6), // runt or underrun
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets
ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x84\x00\x00\x00\x02" "C", 7), // runt or underrun
ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation
};
pass = RunASN1TestSet(ia5Strings, COUNTOF(ia5Strings)) && pass;
const ASN1_TestTuple integerValues[] =
{
// 8.3.1 The encoding of an integer value shall be primitive. The contents octets shall consist of one or more octets.
ASN1_TestTuple(INTEGER, REJECT, "\x02\x00", 2), // definite length, short form, zero content octets
ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x01" "C", 3), // definite length, short form, expected content octets
ASN1_TestTuple(INTEGER, REJECT, "\x02\x02" "C", 3), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x7F" "C", 3), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x81\x00", 3), // definite length, long form, zero content octets
ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x81\x01" "C", 4), // definite length, long form, expected content octets
ASN1_TestTuple(INTEGER, REJECT, "\x02\x81\x02" "C", 4), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x81\xff" "C", 4), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x82\x00\x00", 4), // definite length, long form, zero content octets
ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x82\x00\x01" "C", 5), // definite length, long form, expected content octets
ASN1_TestTuple(INTEGER, REJECT, "\x02\x82\x00\x02" "C", 5), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x82\xff\xff" "C", 5), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x83\x00\x00\x00", 5), // definite length, long form, zero content octets
ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets
ASN1_TestTuple(INTEGER, REJECT, "\x02\x83\x00\x00\x02" "C", 6), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x83\xff\xff\xff" "C", 6), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets
ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets
ASN1_TestTuple(INTEGER, REJECT, "\x02\x84\x00\x00\x00\x02" "C", 7), // runt or underrun
ASN1_TestTuple(INTEGER, REJECT, "\x02\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation
};
pass = RunASN1TestSet(integerValues, COUNTOF(integerValues)) && pass;
return pass;
}
bool TestASN1Functions()
{
std::cout << "\nTesting ASN.1 functions...\n\n";
bool pass = true, fail;
{
const std::string message = "Now is the time for all good men to come to the aide of their country";
ByteQueue encoded, reencoded, decoded;
size_t len = 0, rlen = 0;
len = DEREncodeOctetString(encoded, ConstBytePtr(message), BytePtrSize(message));
DERReencode(encoded, reencoded);
rlen = reencoded.MaxRetrievable();
(void)BERDecodeOctetString(reencoded, decoded);
std::string recovered;
StringSink sink(recovered);
decoded.TransferTo(sink);
fail = (len != rlen || message != recovered);
pass = pass && !fail;
CRYPTOPP_ASSERT(!fail);
std::cout << (fail ? "FAILED" : "passed") << " ";
std::cout << "DEREncodeOctetString" << "\n";
std::cout << (fail ? "FAILED" : "passed") << " ";
std::cout << "BERDecodeOctetString" << "\n";
}
{
const std::string message = "Now is the time for all good men to come to the aide of their country";
const byte asnStringTypes[] = {
UTF8_STRING, PRINTABLE_STRING, T61_STRING, VIDEOTEXT_STRING,IA5_STRING, VISIBLE_STRING
};
unsigned int failed = 0;
size_t len = 0, rlen = 0, i = 0;
for (i = 0; i < COUNTOF(asnStringTypes); ++i)
{
ByteQueue encoded, reencoded, decoded;
std::string recovered;
len = DEREncodeTextString(encoded, ConstBytePtr(message), BytePtrSize(message), asnStringTypes[i]);
DERReencode(encoded, reencoded);
rlen = reencoded.MaxRetrievable();
(void)BERDecodeTextString(reencoded, recovered, asnStringTypes[i]);
fail = (len != rlen || message != recovered);
if (fail) failed++;
CRYPTOPP_ASSERT(!fail);
}
failed ? fail = true : fail = false;
pass = pass && !fail;
std::cout << (fail ? "FAILED" : "passed") << " ";
std::cout << "DEREncodeTextString" << "\n";
std::cout << (fail ? "FAILED" : "passed") << " ";
std::cout << "DEREncodeTextString" << "\n";
}
{
const byte date[] = "Sun, 21 Mar 2021 01:00:00 +0000";
SecByteBlock message; message.Assign(date, sizeof(date)-1);
const byte asnDateTypes[] = {UTC_TIME, GENERALIZED_TIME};
unsigned int failed = 0;
size_t i = 0;
for (i = 0; i < COUNTOF(asnDateTypes); ++i)
{
ByteQueue encoded, decoded;
SecByteBlock recovered;
(void)DEREncodeDate(encoded, message, asnDateTypes[i]);
(void)BERDecodeDate(encoded, recovered, asnDateTypes[i]);
fail = (message != recovered);
if (fail) failed++;
CRYPTOPP_ASSERT(!fail);
}
failed ? fail = true : fail = false;
pass = pass && !fail;
std::cout << (fail ? "FAILED" : "passed") << " ";
std::cout << "DEREncodeDate" << "\n";
std::cout << (fail ? "FAILED" : "passed") << " ";
std::cout << "BERDecodeDate" << "\n";
}
return pass;
}
#endif
#if defined(CRYPTOPP_EXTENDED_VALIDATION)
bool TestStringSink()
{
try
{
std::string in = "The quick brown fox jumps over the lazy dog";
std::string str;
StringSource s1(in, true, new StringSink(str));
std::vector<byte> vec;
StringSource s2(in, true, new VectorSink(vec));
std::vector<byte> vec2;
VectorSource s3(vec, true, new VectorSink(vec2));
return str.size() == vec.size() &&
std::equal(str.begin(), str.end(), vec.begin()) &&
vec.size() == vec2.size() &&
std::equal(vec.begin(), vec.end(), vec2.begin());
}
catch(const std::exception&)
{
}
return false;
}
#endif
NAMESPACE_END // Test
NAMESPACE_END // CryptoPP