From 78db20d9395f05a2b41774e103011eaca467e31a Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Fri, 12 May 2017 19:52:42 -0400 Subject: [PATCH] Add FileName, FileTime and Comment to argnames.h Add self tests to verify handling of filenames, filetimes and comments --- argnames.h | 3 +++ gzip.cpp | 11 ++++++++++ gzip.h | 10 +++++++-- validat0.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/argnames.h b/argnames.h index e80115b8..a6fbb07a 100644 --- a/argnames.h +++ b/argnames.h @@ -88,6 +88,9 @@ CRYPTOPP_DEFINE_NAME_STRING(Salt) //!< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(Tweak) //!< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(SaltSize) //!< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(TreeMode) //< byte +CRYPTOPP_DEFINE_NAME_STRING(FileName) //!< const char * +CRYPTOPP_DEFINE_NAME_STRING(FileTime) //!< int +CRYPTOPP_DEFINE_NAME_STRING(Comment) //!< const char * DOCUMENTED_NAMESPACE_END NAMESPACE_END diff --git a/gzip.cpp b/gzip.cpp index 4b4869b4..331ce019 100644 --- a/gzip.cpp +++ b/gzip.cpp @@ -2,6 +2,7 @@ #include "pch.h" #include "gzip.h" +#include "argnames.h" NAMESPACE_BEGIN(CryptoPP) @@ -11,6 +12,16 @@ static inline bool Is8859Character(char c) { return (cc >= 32 && cc <= 126) || (cc >= 160 && cc <= 255); } +void Gzip::IsolatedInitialize(const NameValuePairs ¶meters) +{ + ConstByteArrayParameter v; + if (parameters.GetValue(Name::FileName(), v)) + m_filename.assign(reinterpret_cast(v.begin()), v.size()); + if (parameters.GetValue(Name::Comment(), v)) + m_comment.assign(reinterpret_cast(v.begin()), v.size()); + m_filetime = parameters.GetIntValueWithDefault(Name::FileTime(), 0); +} + void Gzip::WritePrestreamHeader() { m_totalLen = 0; diff --git a/gzip.h b/gzip.h index 271ff500..0c3f53df 100644 --- a/gzip.h +++ b/gzip.h @@ -27,13 +27,17 @@ public: //! if a file has both compressible and uncompressible parts, it may fail to compress //! some of the compressible parts. Gzip(BufferedTransformation *attachment=NULLPTR, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true) - : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible), m_totalLen(0) {} + : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible), m_totalLen(0) { } + //! \brief Construct a Gzip compressor //! \param parameters a set of NameValuePairs to initialize this object //! \param attachment an attached transformation //! \details Possible parameter names: Log2WindowSize, DeflateLevel, DetectUncompressible Gzip(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR) - : Deflator(parameters, attachment), m_totalLen(0) {} + : Deflator(parameters, attachment), m_totalLen(0) + { + IsolatedInitialize(parameters); + } //! \param filetime the filetime to set in the header. The application is responsible for setting it. void SetFiletime(word32 filetime) { m_filetime = filetime; } @@ -52,6 +56,8 @@ public: //! is thrown. If throwOnEncodingError is false then the comment is not checked. void SetComment(const std::string& comment, bool throwOnEncodingError = false); + void IsolatedInitialize(const NameValuePairs ¶meters); + protected: enum {MAGIC1=0x1f, MAGIC2=0x8b, // flags for the header DEFLATED=8, FAST=4, SLOW=2}; diff --git a/validat0.cpp b/validat0.cpp index 66547efc..95f84d98 100644 --- a/validat0.cpp +++ b/validat0.cpp @@ -172,7 +172,7 @@ bool TestCompressors() // Tamper try { StringSource(dest.substr(0, len - 2), true, new Gunzip(new StringSink(rec))); - std::cout << "FAILED: Gzip failed to detect a truncated stream\n"; + std::cout << "FAILED: Gzip failed to detect a truncated stream\n"; fail1 = true; } catch (const Exception&) {} @@ -186,6 +186,42 @@ bool TestCompressors() // ************************************************************** + // Gzip Filename, Filetime and Comment + try + { + std::string filename = "test.txt"; + std::string comment = "This is a test"; + word32 filetime = GlobalRNG().GenerateWord32(0, 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(0, 0xfff); + + src.resize(len); + GlobalRNG().GenerateBlock(reinterpret_cast(&src[0]), src.size()); + + 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<128; i++) { @@ -213,11 +249,17 @@ bool TestCompressors() 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; } - } + // 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 { @@ -252,7 +294,7 @@ bool TestCompressors() // 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"; + std::cout << "FAILED: Inflate failed to detect a truncated stream\n"; fail2 = true; } catch (const Exception&) {} @@ -333,7 +375,7 @@ bool TestCompressors() // 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"; + std::cout << "FAILED: Zlib failed to detect a truncated stream\n"; fail3 = true; } catch (const Exception&) {}