You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1576 lines
58 KiB
1576 lines
58 KiB
// 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 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 = DefaultEncryptorWithMAC::SALTLENGTH + 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 = LegacyDecryptorWithMAC::SALTLENGTH + 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; |
|
} |
|
#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
|
|
|