From af38c3c85921403533f6d105b17357f680403221 Mon Sep 17 00:00:00 2001 From: Daniel Scharrer Date: Thu, 24 Nov 2011 21:28:29 +0100 Subject: [PATCH] Cleanup crypto code. --- CMakeLists.txt | 12 +- src/InnoExtract.cpp | 7 +- src/crypto/Hasher.cpp | 36 ----- src/crypto/Hasher.hpp | 40 ----- src/crypto/IteratedHash.hpp | 188 ---------------------- src/crypto/MD5.hpp | 24 --- src/crypto/SHA-1.hpp | 24 --- src/crypto/{Adler-32.cpp => adler32.cpp} | 22 +-- src/crypto/{Adler-32.hpp => adler32.hpp} | 9 +- src/crypto/{Checksum.cpp => checksum.cpp} | 38 +++-- src/crypto/{Checksum.hpp => checksum.hpp} | 46 +++--- src/crypto/{CRC32.cpp => crc32.cpp} | 10 +- src/crypto/{CRC32.hpp => crc32.hpp} | 9 +- src/crypto/hasher.cpp | 44 +++++ src/crypto/hasher.hpp | 44 +++++ src/crypto/iteratedhash.hpp | 161 ++++++++++++++++++ src/crypto/{MD5.cpp => md5.cpp} | 16 +- src/crypto/md5.hpp | 30 ++++ src/crypto/{SHA-1.cpp => sha1.cpp} | 48 +++--- src/crypto/sha1.hpp | 30 ++++ src/loader/SetupLoader.cpp | 8 +- src/loader/SetupLoader.hpp | 4 +- src/setup/FileLocationEntry.cpp | 8 +- src/setup/FileLocationEntry.hpp | 4 +- src/setup/SetupHeader.cpp | 6 +- src/setup/SetupHeader.hpp | 4 +- src/stream/block.cpp | 6 +- src/stream/checksum.hpp | 6 +- src/stream/file.cpp | 2 +- src/stream/file.hpp | 4 +- src/util/types.hpp | 13 ++ src/util/util.hpp | 31 ++++ 32 files changed, 501 insertions(+), 433 deletions(-) delete mode 100644 src/crypto/Hasher.cpp delete mode 100644 src/crypto/Hasher.hpp delete mode 100644 src/crypto/IteratedHash.hpp delete mode 100644 src/crypto/MD5.hpp delete mode 100644 src/crypto/SHA-1.hpp rename src/crypto/{Adler-32.cpp => adler32.cpp} (74%) rename src/crypto/{Adler-32.hpp => adler32.hpp} (75%) rename src/crypto/{Checksum.cpp => checksum.cpp} (58%) rename src/crypto/{Checksum.hpp => checksum.hpp} (64%) rename src/crypto/{CRC32.cpp => crc32.cpp} (98%) rename src/crypto/{CRC32.hpp => crc32.hpp} (78%) create mode 100644 src/crypto/hasher.cpp create mode 100644 src/crypto/hasher.hpp create mode 100644 src/crypto/iteratedhash.hpp rename src/crypto/{MD5.cpp => md5.cpp} (93%) create mode 100644 src/crypto/md5.hpp rename src/crypto/{SHA-1.cpp => sha1.cpp} (79%) create mode 100644 src/crypto/sha1.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c221c15..24ea0b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,12 +77,12 @@ check_symbol_exists(ioctl "sys/ioctl.h" HAVE_IOCTL) set(INNOEXTRACT_SOURCES - src/crypto/Adler-32.cpp - src/crypto/Checksum.cpp - src/crypto/CRC32.cpp - src/crypto/Hasher.cpp - src/crypto/MD5.cpp - src/crypto/SHA-1.cpp + src/crypto/adler32.cpp + src/crypto/checksum.cpp + src/crypto/crc32.cpp + src/crypto/hasher.cpp + src/crypto/md5.cpp + src/crypto/sha1.cpp src/loader/ExeReader.cpp src/loader/SetupLoader.cpp diff --git a/src/InnoExtract.cpp b/src/InnoExtract.cpp index 0ad04d9..0874a1f 100644 --- a/src/InnoExtract.cpp +++ b/src/InnoExtract.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include "crypto/hasher.hpp" #include "loader/SetupLoader.hpp" @@ -914,7 +914,7 @@ int main(int argc, char * argv[]) { std::cout << " @ " << print_hex(location.fileOffset) << " (" << print_bytes(location.file_size) << ')' << std::endl; - Hasher hasher; + crypto::hasher hasher; stream::file_reader::pointer file_source; file_source = stream::file_reader::get(*chunk_source, location, version, hasher); @@ -977,8 +977,7 @@ int main(int argc, char * argv[]) { progress::clear(); - Checksum actual; - hasher.finalize(actual); + crypto::checksum actual = hasher.finalize(); if(actual != location.checksum) { log_warning << "checksum mismatch:"; log_warning << "actual: " << actual; diff --git a/src/crypto/Hasher.cpp b/src/crypto/Hasher.cpp deleted file mode 100644 index ea13443..0000000 --- a/src/crypto/Hasher.cpp +++ /dev/null @@ -1,36 +0,0 @@ - -#include "crypto/Hasher.hpp" - -void Hasher::init(Checksum::Type newType) { - - type = newType; - - switch(type) { - case Checksum::Adler32: adler32.init(); break; - case Checksum::Crc32: crc32.init(); break; - case Checksum::MD5: md5.init(); break; - case Checksum::Sha1: sha1.init(); break; - }; -} - -void Hasher::update(const char * data, size_t size) { - - switch(type) { - case Checksum::Adler32: adler32.update(data, size); break; - case Checksum::Crc32: crc32.update(data, size); break; - case Checksum::MD5: md5.update(data, size); break; - case Checksum::Sha1: sha1.update(data, size); break; - }; -} - -void Hasher::finalize(Checksum & result) { - - result.type = type; - - switch(type) { - case Checksum::Adler32: result.adler32 = adler32.finalize(); break; - case Checksum::Crc32: result.crc32 = crc32.finalize(); break; - case Checksum::MD5: md5.finalize(result.md5); break; - case Checksum::Sha1: sha1.finalize(result.sha1); break; - }; -} diff --git a/src/crypto/Hasher.hpp b/src/crypto/Hasher.hpp deleted file mode 100644 index 4784217..0000000 --- a/src/crypto/Hasher.hpp +++ /dev/null @@ -1,40 +0,0 @@ - -#ifndef INNOEXTRACT_CRYPTO_HASHER_HPP -#define INNOEXTRACT_CRYPTO_HASHER_HPP - -#include "crypto/Adler-32.hpp" -#include "crypto/Checksum.hpp" -#include "crypto/CRC32.hpp" -#include "crypto/MD5.hpp" -#include "crypto/SHA-1.hpp" -#include "util/enum.hpp" - -struct checksum_uninitialized_error { }; - -class Hasher : ChecksumBase { - -public: - - inline Hasher() { } - inline Hasher(Checksum::Type type) { init(type); } - - void init(Checksum::Type type); - - void update(const char * data, size_t size); - - void finalize(Checksum & result); - -private: - - Checksum::Type type; - - union { - Adler32 adler32; - Crc32 crc32; - Md5 md5; - Sha1 sha1; - }; - -}; - -#endif // INNOEXTRACT_CRYPTO_HASHER_HPP; diff --git a/src/crypto/IteratedHash.hpp b/src/crypto/IteratedHash.hpp deleted file mode 100644 index 39f792f..0000000 --- a/src/crypto/IteratedHash.hpp +++ /dev/null @@ -1,188 +0,0 @@ - -#ifndef INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP -#define INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP - -// Taken from Crypto++ and modified to fit the project. - -#include -#include -#include "crypto/Checksum.hpp" -#include "util/endian.hpp" -#include "util/types.hpp" -#include "util/util.hpp" - -template -class IteratedHash : public ChecksumBase< IteratedHash > { - -public: - - typedef T Transform; - typedef typename Transform::HashWord HashWord; - typedef typename Transform::ByteOrder ByteOrder; - static const size_t BlockSize = Transform::BlockSize; - static const size_t HashSize = Transform::HashSize; - - inline void init() { countLo = countHi = 0; Transform::init(state); } - - void update(const char * data, size_t length); - - void finalize(char * result); - -private: - - size_t hash(const HashWord * input, size_t length); - void pad(unsigned int lastBlockSize, uint8_t padFirst = 0x80); - - inline HashWord getBitCountHi() const { - return (countLo >> (8 * sizeof(HashWord) - 3)) + (countHi << 3); - } - inline HashWord getBitCountLo() const { return countLo << 3; } - - HashWord data[BlockSize / sizeof(HashWord)]; - HashWord state[HashSize / sizeof(HashWord)]; - - HashWord countLo, countHi; - -}; - -template -void IteratedHash::update(const char * input, size_t len) { - - HashWord oldCountLo = countLo; - - if((countLo = oldCountLo + HashWord(len)) < oldCountLo) { - countHi++; // carry from low to high - } - - countHi += HashWord(safe_right_shift<8 * sizeof(HashWord)>(len)); - - size_t num = mod_power_of_2(oldCountLo, size_t(BlockSize)); - uint8_t * d = reinterpret_cast(data); - - if(num != 0) { // process left over data - if(num + len >= BlockSize) { - std::memcpy(d + num, input, BlockSize-num); - hash(data, BlockSize); - input += (BlockSize - num); - len -= (BlockSize - num); - num = 0; - // drop through and do the rest - } else { - std::memcpy(d + num, input, len); - return; - } - } - - // now process the input data in blocks of BlockSize bytes and save the leftovers to m_data - if(len >= BlockSize) { - - if(is_aligned(input)) { - size_t leftOver = hash(reinterpret_cast(input), len); - input += (len - leftOver); - len = leftOver; - - } else { - do { // copy input first if it's not aligned correctly - std::memcpy(d, input, BlockSize); - hash(data, BlockSize); - input += BlockSize; - len -= BlockSize; - } while(len >= BlockSize); - } - } - - if(len) { - memcpy(d, input, len); - } -} - -template -size_t IteratedHash::hash(const HashWord * input, size_t length) { - - do { - - if(ByteOrder::native) { - Transform::transform(state, input); - } else { - byteswap(data, input, BlockSize); - Transform::transform(state, data); - } - - input += BlockSize / sizeof(HashWord); - length -= BlockSize; - - } while(length >= BlockSize); - - return length; -} - -template -void IteratedHash::pad(unsigned int lastBlockSize, uint8_t padFirst) { - - size_t num = mod_power_of_2(countLo, size_t(BlockSize)); - - uint8_t * d = reinterpret_cast(data); - - d[num++] = padFirst; - - if(num <= lastBlockSize) { - memset(d + num, 0, lastBlockSize - num); - } else { - memset(d + num, 0, BlockSize - num); - hash(data, BlockSize); - memset(d, 0, lastBlockSize); - } -} - -template inline T rotlFixed(T x, unsigned int y) { - return T((x << y) | (x >> (sizeof(T) * 8 - y))); -} - -#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) - -template<> inline uint8_t rotlFixed(uint8_t x, unsigned int y) { - return y ? _rotl8(x, y) : x; -} - -// Intel C++ Compiler 10.0 gives undefined externals with these -template<> inline uint16_t rotlFixed(uint16_t x, unsigned int y) { - return y ? _rotl16(x, y) : x; -} - -#endif - -#ifdef _MSC_VER -template<> inline uint32_t rotlFixed(uint32_t x, unsigned int y) { - return y ? _lrotl(x, y) : x; -} -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(__INTEL_COMPILER) -// Intel C++ Compiler 10.0 calls a function instead of using the rotate instruction when -// using these instructions -template<> inline uint64_t rotlFixed(uint64_t x, unsigned int y) { - return y ? _rotl64(x, y) : x; -} -#endif - -template -void IteratedHash::finalize(char * digest) { - - size_t order = ByteOrder::offset; - - pad(BlockSize - 2 * sizeof(HashWord)); - data[BlockSize / sizeof(HashWord) - 2 + order] = ByteOrder::byteswap_if_alien(getBitCountLo()); - data[BlockSize / sizeof(HashWord) - 1 - order] = ByteOrder::byteswap_if_alien(getBitCountHi()); - - hash(data, BlockSize); - - if(is_aligned(digest) && HashSize % sizeof(HashWord) == 0) { - ByteOrder::byteswap_if_alien(state, reinterpret_cast(digest), HashSize); - } else { - ByteOrder::byteswap_if_alien(state, state, HashSize); - memcpy(digest, state, HashSize); - } - -} - -#endif // INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP diff --git a/src/crypto/MD5.hpp b/src/crypto/MD5.hpp deleted file mode 100644 index 41264fc..0000000 --- a/src/crypto/MD5.hpp +++ /dev/null @@ -1,24 +0,0 @@ - -#ifndef INNOEXTRACT_CRYPTO_MD5_HPP -#define INNOEXTRACT_CRYPTO_MD5_HPP - -#include -#include "crypto/IteratedHash.hpp" - -class Md5Transform { - -public: - - typedef uint32_t HashWord; - typedef little_endian ByteOrder; - static const size_t BlockSize = 64; - static const size_t HashSize = 16; - - static void init(HashWord * state); - - static void transform(HashWord * digest, const HashWord * data); -}; - -typedef IteratedHash Md5; - -#endif // INNOEXTRACT_CRYPTO_MD5_HPP diff --git a/src/crypto/SHA-1.hpp b/src/crypto/SHA-1.hpp deleted file mode 100644 index 54bad57..0000000 --- a/src/crypto/SHA-1.hpp +++ /dev/null @@ -1,24 +0,0 @@ - -#ifndef INNOEXTRACT_CRYPTO_SHA1_HPP -#define INNOEXTRACT_CRYPTO_SHA1_HPP - -#include -#include "crypto/IteratedHash.hpp" - -class Sha1Transform { - -public: - - typedef uint32_t HashWord; - typedef big_endian ByteOrder; - static const size_t BlockSize = 64; - static const size_t HashSize = 20; - - static void init(HashWord * state); - - static void transform(HashWord * digest, const HashWord * data); -}; - -typedef IteratedHash Sha1; - -#endif // INNOEXTRACT_CRYPTO_SHA1_HPP diff --git a/src/crypto/Adler-32.cpp b/src/crypto/adler32.cpp similarity index 74% rename from src/crypto/Adler-32.cpp rename to src/crypto/adler32.cpp index e75e2d3..daa5c4b 100644 --- a/src/crypto/Adler-32.cpp +++ b/src/crypto/adler32.cpp @@ -2,11 +2,13 @@ // Taken from Crypto++ and modified to fit the project. // adler32.cpp - written and placed in the public domain by Wei Dai -#include "crypto/Adler-32.hpp" +#include "crypto/adler32.hpp" -void Adler32::update(const char * input, size_t length) { +namespace crypto { + +void adler32::update(const char * input, size_t length) { - const uint_fast32_t BASE = 65521; + const uint_fast32_t base = 65521; uint_fast32_t s1 = this->s1; uint_fast32_t s2 = this->s2; @@ -19,11 +21,11 @@ void Adler32::update(const char * input, size_t length) { length--; } while(length % 8 != 0); - if(s1 >= BASE) { - s1 -= BASE; + if(s1 >= base) { + s1 -= base; } - s2 %= BASE; + s2 %= base; } while(length > 0) { @@ -40,15 +42,17 @@ void Adler32::update(const char * input, size_t length) { length -= 8; input += 8; - if(s1 >= BASE) { - s1 -= BASE; + if(s1 >= base) { + s1 -= base; } if(length % 0x8000 == 0) { - s2 %= BASE; + s2 %= base; } } this->s1 = uint16_t(s1); this->s2 = uint16_t(s2); } + +} // namespace crypto diff --git a/src/crypto/Adler-32.hpp b/src/crypto/adler32.hpp similarity index 75% rename from src/crypto/Adler-32.hpp rename to src/crypto/adler32.hpp index 4733576..e3aad66 100644 --- a/src/crypto/Adler-32.hpp +++ b/src/crypto/adler32.hpp @@ -4,10 +4,13 @@ #include #include -#include "crypto/Checksum.hpp" + +#include "crypto/checksum.hpp" + +namespace crypto { //! ADLER-32 checksum calculations -struct Adler32 : public ChecksumBase { +struct adler32 : public checksum_base { void init() { s1 = 1, s2 = 0; } @@ -20,4 +23,6 @@ private: uint16_t s1, s2; }; +} // namespace crypto + #endif // INNOEXTRACT_CRYPTO_ADLER32_HPP diff --git a/src/crypto/Checksum.cpp b/src/crypto/checksum.cpp similarity index 58% rename from src/crypto/Checksum.cpp rename to src/crypto/checksum.cpp index d4c9636..73e2e35 100644 --- a/src/crypto/Checksum.cpp +++ b/src/crypto/checksum.cpp @@ -1,18 +1,13 @@ -#include "crypto/Checksum.hpp" +#include "crypto/checksum.hpp" #include #include "util/output.hpp" -ENUM_NAMES(Checksum::Type, "Checksum Type", - "Adler32", - "CRC32", - "MD5", - "Sha1", -) +namespace crypto { -bool Checksum::operator==(const Checksum & o) const { +bool checksum::operator==(const checksum & o) const { if(o.type != type) { return false; @@ -20,34 +15,43 @@ bool Checksum::operator==(const Checksum & o) const { switch(type) { case Adler32: return (adler32 == o.adler32); - case Crc32: return (crc32 == o.crc32); + case CRC32: return (crc32 == o.crc32); case MD5: return !memcmp(md5, o.md5, ARRAY_SIZE(md5)); - case Sha1: return !memcmp(sha1, o.sha1, ARRAY_SIZE(sha1)); + case SHA1: return !memcmp(sha1, o.sha1, ARRAY_SIZE(sha1)); }; } -std::ostream & operator<<(std::ostream & os, const Checksum & checksum) { +} // namespace crypto + +ENUM_NAMES(crypto::checksum_type, "Checksum Type", + "Adler32", + "CRC32", + "MD5", + "Sha1", +) + +std::ostream & operator<<(std::ostream & os, const crypto::checksum & checksum) { - std::ios_base::fmtflags old = os.flags(); + std::ios_base::fmtflags old_fmtflags = os.flags(); os << checksum.type << ' '; switch(checksum.type) { - case Checksum::Adler32: { + case crypto::Adler32: { os << print_hex(checksum.adler32); break; } - case Checksum::Crc32: { + case crypto::CRC32: { os << print_hex(checksum.crc32); break; } - case Checksum::MD5: { + case crypto::MD5: { for(size_t i = 0; i < ARRAY_SIZE(checksum.md5); i++) { os << std::setfill('0') << std::hex << std::setw(2) << int(uint8_t(checksum.md5[i])); } break; } - case Checksum::Sha1: { + case crypto::SHA1: { for(size_t i = 0; i < ARRAY_SIZE(checksum.sha1); i++) { os << std::setfill('0') << std::hex << std::setw(2) << int(uint8_t(checksum.sha1[i])); } @@ -55,7 +59,7 @@ std::ostream & operator<<(std::ostream & os, const Checksum & checksum) { } } - os.setf(old, std::ios_base::basefield); + os.setf(old_fmtflags, std::ios_base::basefield); return os; } diff --git a/src/crypto/Checksum.hpp b/src/crypto/checksum.hpp similarity index 64% rename from src/crypto/Checksum.hpp rename to src/crypto/checksum.hpp index 270e1c2..d0b6b4c 100644 --- a/src/crypto/Checksum.hpp +++ b/src/crypto/checksum.hpp @@ -9,15 +9,18 @@ #include "util/endian.hpp" #include "util/enum.hpp" +#include "util/types.hpp" -struct Checksum { - - enum Type { - Adler32, - Crc32, - MD5, - Sha1, - }; +namespace crypto { + +enum checksum_type { + Adler32, + CRC32, + MD5, + SHA1, +}; + +struct checksum { union { uint32_t adler32; @@ -26,26 +29,15 @@ struct Checksum { char sha1[20]; }; - Type type; - - bool operator==(const Checksum & other) const; - inline bool operator!=(const Checksum & other) const { return !(*this == other); } + checksum_type type; -}; - -template -class StaticPolymorphic { - -protected: - - inline Base & impl() { return *static_cast(this); } - - inline const Base & impl() const { return *static_cast(this); } + bool operator==(const checksum & other) const; + inline bool operator!=(const checksum & other) const { return !(*this == other); } }; -template -class ChecksumBase : public StaticPolymorphic { +template +class checksum_base : public static_polymorphic { public: @@ -74,8 +66,10 @@ public: }; -NAMED_ENUM(Checksum::Type) +} // namespace crypto + +NAMED_ENUM(crypto::checksum_type) -std::ostream & operator<<(std::ostream & os, const Checksum & checksum); +std::ostream & operator<<(std::ostream & os, const crypto::checksum & checksum); #endif // INNOEXTRACT_CRYPTO_CHECKSUM_HPP diff --git a/src/crypto/CRC32.cpp b/src/crypto/crc32.cpp similarity index 98% rename from src/crypto/CRC32.cpp rename to src/crypto/crc32.cpp index 8521f8e..223e9dc 100644 --- a/src/crypto/CRC32.cpp +++ b/src/crypto/crc32.cpp @@ -2,10 +2,12 @@ // Taken from Crypto++ and modified to fit the project. // crc.cpp - written and placed in the public domain by Wei Dai -#include "crypto/CRC32.hpp" +#include "crypto/crc32.hpp" #include +namespace crypto { + #ifdef BOOST_LITTLE_ENDIAN #define CRC32_INDEX(c) (c & 0xff) #define CRC32_SHIFTED(c) (c >> 8) @@ -15,7 +17,7 @@ #endif /* Table of CRC-32's of all single byte values (made by makecrc.c) */ -const uint32_t Crc32::table[] = { +const uint32_t crc32::table[] = { #ifdef BOOST_LITTLE_ENDIAN 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, @@ -125,7 +127,7 @@ const uint32_t Crc32::table[] = { #endif }; -void Crc32::update(const char * s, size_t n) { +void crc32::update(const char * s, size_t n) { for(; (size_t(s) % 4 != 0) && n > 0; n--) { crc = table[CRC32_INDEX(crc) ^ uint8_t(*s++)] ^ CRC32_SHIFTED(crc); @@ -148,3 +150,5 @@ void Crc32::update(const char * s, size_t n) { #undef CRC32_INDEX #undef CRC32_SHIFTED + +} // namespace crypto diff --git a/src/crypto/CRC32.hpp b/src/crypto/crc32.hpp similarity index 78% rename from src/crypto/CRC32.hpp rename to src/crypto/crc32.hpp index 63b786d..7cccce7 100644 --- a/src/crypto/CRC32.hpp +++ b/src/crypto/crc32.hpp @@ -3,10 +3,13 @@ #define INNOEXTRACT_CRYPTO_CRC32_HPP #include -#include "crypto/Checksum.hpp" + +#include "crypto/checksum.hpp" + +namespace crypto { //! CRC32 checksum calculation -struct Crc32 : public ChecksumBase { +struct crc32 : public checksum_base { inline void init() { crc = CRC32_NEGL; } @@ -22,4 +25,6 @@ private: uint32_t crc; }; +} // namespace crypto + #endif // INNOEXTRACT_CRYPTO_CRC32_HPP diff --git a/src/crypto/hasher.cpp b/src/crypto/hasher.cpp new file mode 100644 index 0000000..720b125 --- /dev/null +++ b/src/crypto/hasher.cpp @@ -0,0 +1,44 @@ + +#include "crypto/hasher.hpp" + +namespace crypto { + +void hasher::init(checksum_type newType) { + + type = newType; + + switch(type) { + case crypto::Adler32: adler32.init(); break; + case crypto::CRC32: crc32.init(); break; + case crypto::MD5: md5.init(); break; + case crypto::SHA1: sha1.init(); break; + }; +} + +void hasher::update(const char * data, size_t size) { + + switch(type) { + case crypto::Adler32: adler32.update(data, size); break; + case crypto::CRC32: crc32.update(data, size); break; + case crypto::MD5: md5.update(data, size); break; + case crypto::SHA1: sha1.update(data, size); break; + }; +} + +checksum hasher::finalize() { + + checksum result; + + result.type = type; + + switch(type) { + case crypto::Adler32: result.adler32 = adler32.finalize(); break; + case crypto::CRC32: result.crc32 = crc32.finalize(); break; + case crypto::MD5: md5.finalize(result.md5); break; + case crypto::SHA1: sha1.finalize(result.sha1); break; + }; + + return result; +} + +} // namespace crypto diff --git a/src/crypto/hasher.hpp b/src/crypto/hasher.hpp new file mode 100644 index 0000000..0f5ff9c --- /dev/null +++ b/src/crypto/hasher.hpp @@ -0,0 +1,44 @@ + +#ifndef INNOEXTRACT_CRYPTO_HASHER_HPP +#define INNOEXTRACT_CRYPTO_HASHER_HPP + +#include "crypto/adler32.hpp" +#include "crypto/checksum.hpp" +#include "crypto/crc32.hpp" +#include "crypto/md5.hpp" +#include "crypto/sha1.hpp" +#include "util/enum.hpp" + +struct checksum_uninitialized_error { }; + +namespace crypto { + +class hasher : checksum_base { + +public: + + inline hasher() { } + inline hasher(checksum_type type) { init(type); } + + void init(checksum_type type); + + void update(const char * data, size_t size); + + checksum finalize(); + +private: + + checksum_type type; + + union { + crypto::adler32 adler32; + crypto::crc32 crc32; + crypto::md5 md5; + crypto::sha1 sha1; + }; + +}; + +} // namespace crypto + +#endif // INNOEXTRACT_CRYPTO_HASHER_HPP; diff --git a/src/crypto/iteratedhash.hpp b/src/crypto/iteratedhash.hpp new file mode 100644 index 0000000..38fc847 --- /dev/null +++ b/src/crypto/iteratedhash.hpp @@ -0,0 +1,161 @@ + +#ifndef INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP +#define INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP + +// Taken from Crypto++ and modified to fit the project. + +#include +#include +#include "crypto/checksum.hpp" +#include "util/endian.hpp" +#include "util/types.hpp" +#include "util/util.hpp" + +namespace crypto { + +template +class iterated_hash : public checksum_base< iterated_hash > { + +public: + + typedef T transform; + typedef typename transform::hash_word hash_word; + typedef typename transform::byte_order byte_order; + static const size_t block_size = transform::block_size; + static const size_t hash_size = transform::hash_size; + + inline void init() { count_lo = count_hi = 0; transform::init(state); } + + void update(const char * data, size_t length); + + void finalize(char * result); + +private: + + size_t hash(const hash_word * input, size_t length); + void pad(unsigned int last_block_size, uint8_t pad_first = 0x80); + + inline hash_word bit_count_hi() const { + return (count_lo >> (8 * sizeof(hash_word) - 3)) + (count_hi << 3); + } + inline hash_word bit_count_lo() const { return count_lo << 3; } + + hash_word data[block_size / sizeof(hash_word)]; + hash_word state[hash_size / sizeof(hash_word)]; + + hash_word count_lo, count_hi; + +}; + +template +void iterated_hash::update(const char * input, size_t len) { + + hash_word old_count_lo = count_lo; + + if((count_lo = old_count_lo + hash_word(len)) < old_count_lo) { + count_hi++; // carry from low to high + } + + count_hi += hash_word(safe_right_shift<8 * sizeof(hash_word)>(len)); + + size_t num = mod_power_of_2(old_count_lo, size_t(block_size)); + uint8_t * d = reinterpret_cast(data); + + if(num != 0) { // process left over data + if(num + len >= block_size) { + std::memcpy(d + num, input, block_size-num); + hash(data, block_size); + input += (block_size - num); + len -= (block_size - num); + num = 0; + // drop through and do the rest + } else { + std::memcpy(d + num, input, len); + return; + } + } + + // now process the input data in blocks of BlockSize bytes and save the leftovers to m_data + if(len >= block_size) { + + if(is_aligned(input)) { + size_t leftOver = hash(reinterpret_cast(input), len); + input += (len - leftOver); + len = leftOver; + + } else { + do { // copy input first if it's not aligned correctly + std::memcpy(d, input, block_size); + hash(data, block_size); + input += block_size; + len -= block_size; + } while(len >= block_size); + } + } + + if(len) { + memcpy(d, input, len); + } +} + +template +size_t iterated_hash::hash(const hash_word * input, size_t length) { + + do { + + if(byte_order::native) { + transform::transform(state, input); + } else { + byteswap(data, input, block_size); + transform::transform(state, data); + } + + input += block_size / sizeof(hash_word); + length -= block_size; + + } while(length >= block_size); + + return length; +} + +template +void iterated_hash::pad(unsigned int last_block_size, uint8_t pad_first) { + + size_t num = mod_power_of_2(count_lo, size_t(block_size)); + + uint8_t * d = reinterpret_cast(data); + + d[num++] = pad_first; + + if(num <= last_block_size) { + memset(d + num, 0, last_block_size - num); + } else { + memset(d + num, 0, block_size - num); + hash(data, block_size); + memset(d, 0, last_block_size); + } +} + +template +void iterated_hash::finalize(char * digest) { + + size_t order = byte_order::offset; + + pad(block_size - 2 * sizeof(hash_word)); + data[block_size / sizeof(hash_word) - 2 + order] = byte_order::byteswap_if_alien(bit_count_lo()); + data[block_size / sizeof(hash_word) - 1 - order] = byte_order::byteswap_if_alien(bit_count_hi()); + + hash(data, block_size); + + if(is_aligned(digest) && hash_size % sizeof(hash_word) == 0) { + byte_order::byteswap_if_alien(state, reinterpret_cast(digest), hash_size); + } else { + byte_order::byteswap_if_alien(state, state, hash_size); + memcpy(digest, state, hash_size); + } + +} + +} // namespace crypto + +#endif // INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP diff --git a/src/crypto/MD5.cpp b/src/crypto/md5.cpp similarity index 93% rename from src/crypto/MD5.cpp rename to src/crypto/md5.cpp index 32ebb18..d2c06b3 100644 --- a/src/crypto/MD5.cpp +++ b/src/crypto/md5.cpp @@ -3,16 +3,20 @@ // md5.cpp - modified by Wei Dai from Colin Plumb's public domain md5.c // any modifications are placed in the public domain -#include "crypto/MD5.hpp" +#include "crypto/md5.hpp" -void Md5Transform::init(HashWord * state) { +#include "util/util.hpp" + +namespace crypto { + +void md5_transform::init(hash_word * state) { state[0] = 0x67452301L; state[1] = 0xefcdab89L; state[2] = 0x98badcfeL; state[3] = 0x10325476L; } -void Md5Transform::transform(HashWord * digest, const HashWord * in) { +void md5_transform::transform(hash_word * digest, const hash_word * in) { #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) @@ -20,9 +24,9 @@ void Md5Transform::transform(HashWord * digest, const HashWord * in) { #define F4(x, y, z) (y ^ (x | ~z)) #define MD5STEP(f, w, x, y, z, data, s) \ - w = rotlFixed(w + f(x, y, z) + data, s) + x + w = rotl_fixed(w + f(x, y, z) + data, s) + x - HashWord a, b, c, d; + hash_word a, b, c, d; a = digest[0]; b = digest[1]; @@ -109,3 +113,5 @@ void Md5Transform::transform(HashWord * digest, const HashWord * in) { #undef F1 } + +} // namespace crypto diff --git a/src/crypto/md5.hpp b/src/crypto/md5.hpp new file mode 100644 index 0000000..32df315 --- /dev/null +++ b/src/crypto/md5.hpp @@ -0,0 +1,30 @@ + +#ifndef INNOEXTRACT_CRYPTO_MD5_HPP +#define INNOEXTRACT_CRYPTO_MD5_HPP + +#include + +#include "crypto/iteratedhash.hpp" +#include "util/endian.hpp" + +namespace crypto { + +class md5_transform { + +public: + + typedef uint32_t hash_word; + typedef little_endian byte_order; + static const size_t block_size = 64; + static const size_t hash_size = 16; + + static void init(hash_word * state); + + static void transform(hash_word * digest, const hash_word * data); +}; + +typedef iterated_hash md5; + +} // namespace crypto + +#endif // INNOEXTRACT_CRYPTO_MD5_HPP diff --git a/src/crypto/SHA-1.cpp b/src/crypto/sha1.cpp similarity index 79% rename from src/crypto/SHA-1.cpp rename to src/crypto/sha1.cpp index d727bfb..3467044 100644 --- a/src/crypto/SHA-1.cpp +++ b/src/crypto/sha1.cpp @@ -2,9 +2,13 @@ // Taken from Crypto++ and modified to fit the project. // sha.cpp - modified by Wei Dai from Steve Reid's public domain sha1.c -#include "crypto/SHA-1.hpp" +#include "crypto/sha1.hpp" -void Sha1Transform::init(HashWord * state) { +#include "util/util.hpp" + +namespace crypto { + +void sha1_transform::init(hash_word * state) { state[0] = 0x67452301L; state[1] = 0xEFCDAB89L; state[2] = 0x98BADCFEL; @@ -12,10 +16,10 @@ void Sha1Transform::init(HashWord * state) { state[4] = 0xC3D2E1F0L; } -void Sha1Transform::transform(HashWord * state, const HashWord * data) { +void sha1_transform::transform(hash_word * state, const hash_word * data) { #define blk0(i) (W[i] = data[i]) -#define blk1(i) (W[i & 15] = rotlFixed(W[(i + 13) & 15] ^ W[(i + 8) & 15] \ +#define blk1(i) (W[i & 15] = rotl_fixed(W[(i + 13) & 15] ^ W[(i + 8) & 15] \ ^ W[(i + 2) & 15] ^ W[i & 15], 1)) #define f1(x, y, z) (z ^ (x & (y ^ z))) @@ -24,25 +28,25 @@ void Sha1Transform::transform(HashWord * state, const HashWord * data) { #define f4(x, y, z) (x ^ y ^ z) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v, w, x, y, z, i) z += f1(w, x, y) + blk0(i) + 0x5A827999 + rotlFixed(v, 5); \ - w = rotlFixed(w, 30); -#define R1(v, w, x, y, z, i) z += f1(w, x, y) + blk1(i) + 0x5A827999 + rotlFixed(v, 5); \ - w = rotlFixed(w, 30); -#define R2(v, w, x, y, z, i) z += f2(w, x, y) + blk1(i) + 0x6ED9EBA1 + rotlFixed(v, 5); \ - w = rotlFixed(w, 30); -#define R3(v, w, x, y, z, i) z += f3(w, x, y) + blk1(i) + 0x8F1BBCDC + rotlFixed(v, 5); \ - w = rotlFixed(w, 30); -#define R4(v, w, x, y, z, i) z += f4(w, x, y) + blk1(i) + 0xCA62C1D6 + rotlFixed(v, 5); \ - w = rotlFixed(w, 30); - - HashWord W[16]; +#define R0(v, w, x, y, z, i) z += f1(w, x, y) + blk0(i) + 0x5A827999 + rotl_fixed(v, 5); \ + w = rotl_fixed(w, 30); +#define R1(v, w, x, y, z, i) z += f1(w, x, y) + blk1(i) + 0x5A827999 + rotl_fixed(v, 5); \ + w = rotl_fixed(w, 30); +#define R2(v, w, x, y, z, i) z += f2(w, x, y) + blk1(i) + 0x6ED9EBA1 + rotl_fixed(v, 5); \ + w = rotl_fixed(w, 30); +#define R3(v, w, x, y, z, i) z += f3(w, x, y) + blk1(i) + 0x8F1BBCDC + rotl_fixed(v, 5); \ + w = rotl_fixed(w, 30); +#define R4(v, w, x, y, z, i) z += f4(w, x, y) + blk1(i) + 0xCA62C1D6 + rotl_fixed(v, 5); \ + w = rotl_fixed(w, 30); + + hash_word W[16]; /* Copy context->state[] to working vars */ - HashWord a = state[0]; - HashWord b = state[1]; - HashWord c = state[2]; - HashWord d = state[3]; - HashWord e = state[4]; + hash_word a = state[0]; + hash_word b = state[1]; + hash_word c = state[2]; + hash_word d = state[3]; + hash_word e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ @@ -168,3 +172,5 @@ void Sha1Transform::transform(HashWord * state, const HashWord * data) { #undef blk0 } + +} // namespace crypto diff --git a/src/crypto/sha1.hpp b/src/crypto/sha1.hpp new file mode 100644 index 0000000..3c4494f --- /dev/null +++ b/src/crypto/sha1.hpp @@ -0,0 +1,30 @@ + +#ifndef INNOEXTRACT_CRYPTO_SHA1_HPP +#define INNOEXTRACT_CRYPTO_SHA1_HPP + +#include + +#include "crypto/iteratedhash.hpp" +#include "util/endian.hpp" + +namespace crypto { + +class sha1_transform { + +public: + + typedef uint32_t hash_word; + typedef big_endian byte_order; + static const size_t block_size = 64; + static const size_t hash_size = 20; + + static void init(hash_word * state); + + static void transform(hash_word * digest, const hash_word * data); +}; + +typedef iterated_hash sha1; + +} // namespace crypto + +#endif // INNOEXTRACT_CRYPTO_SHA1_HPP diff --git a/src/loader/SetupLoader.cpp b/src/loader/SetupLoader.cpp index fe80975..ac6012e 100644 --- a/src/loader/SetupLoader.cpp +++ b/src/loader/SetupLoader.cpp @@ -6,7 +6,7 @@ #include -#include "crypto/CRC32.hpp" +#include "crypto/crc32.hpp" #include "loader/ExeReader.hpp" #include "setup/Version.hpp" #include "util/load.hpp" @@ -95,7 +95,7 @@ bool SetupLoader::loadOffsetsAt(std::istream & is, uint32_t pos) { return false; } - Crc32 checksum; + crypto::crc32 checksum; checksum.init(); checksum.update(magic, ARRAY_SIZE(magic)); @@ -119,10 +119,10 @@ bool SetupLoader::loadOffsetsAt(std::istream & is, uint32_t pos) { exeUncompressedSize = checksum.load(is); if(version >= INNO_VERSION(4, 0, 3)) { - exeChecksum.type = Checksum::Crc32; + exeChecksum.type = crypto::CRC32; exeChecksum.crc32 = checksum.load(is); } else { - exeChecksum.type = Checksum::Adler32; + exeChecksum.type = crypto::Adler32; exeChecksum.adler32 = checksum.load(is); } diff --git a/src/loader/SetupLoader.hpp b/src/loader/SetupLoader.hpp index 4928ed5..2fe5347 100644 --- a/src/loader/SetupLoader.hpp +++ b/src/loader/SetupLoader.hpp @@ -5,7 +5,7 @@ #include #include -#include "crypto/Checksum.hpp" +#include "crypto/checksum.hpp" struct SetupLoader { @@ -13,7 +13,7 @@ struct SetupLoader { uint32_t exeCompressedSize; //!< Size of setup.e32 after compression (0 = unknown) uint32_t exeUncompressedSize; //!< Size of setup.e32 before compression - Checksum exeChecksum; //!< Checksum of setup.e32 before compression + crypto::checksum exeChecksum; //!< Checksum of setup.e32 before compression uint32_t messageOffset; diff --git a/src/setup/FileLocationEntry.cpp b/src/setup/FileLocationEntry.cpp index c577bc8..04ce98a 100644 --- a/src/setup/FileLocationEntry.cpp +++ b/src/setup/FileLocationEntry.cpp @@ -35,13 +35,13 @@ void FileLocationEntry::load(std::istream & is, const InnoVersion & version) { } if(version >= INNO_VERSION(5, 3, 9)) { - is.read(checksum.sha1, sizeof(checksum.sha1)), checksum.type = Checksum::Sha1; + is.read(checksum.sha1, sizeof(checksum.sha1)), checksum.type = crypto::SHA1; } else if(version >= INNO_VERSION(4, 2, 0)) { - is.read(checksum.md5, sizeof(checksum.md5)), checksum.type = Checksum::MD5; + is.read(checksum.md5, sizeof(checksum.md5)), checksum.type = crypto::MD5; } else if(version >= INNO_VERSION(4, 0, 1)) { - checksum.crc32 = load_number(is), checksum.type = Checksum::Crc32; + checksum.crc32 = load_number(is), checksum.type = crypto::CRC32; } else { - checksum.adler32 = load_number(is), checksum.type = Checksum::Adler32; + checksum.adler32 = load_number(is), checksum.type = crypto::Adler32; } if(version.bits == 16) { diff --git a/src/setup/FileLocationEntry.hpp b/src/setup/FileLocationEntry.hpp index 10f8a52..1341318 100644 --- a/src/setup/FileLocationEntry.hpp +++ b/src/setup/FileLocationEntry.hpp @@ -6,7 +6,7 @@ #include #include -#include "crypto/Checksum.hpp" +#include "crypto/checksum.hpp" #include "setup/SetupItem.hpp" #include "setup/Version.hpp" #include "util/enum.hpp" @@ -39,7 +39,7 @@ struct FileLocationEntry : public SetupItem { uint64_t fileOffset; //!< offset of this file within the decompressed chunk uint64_t file_size; //!< decompressed size of this file - Checksum checksum; + crypto::checksum checksum; timespec timestamp; diff --git a/src/setup/SetupHeader.cpp b/src/setup/SetupHeader.cpp index 35f2543..da2ccb0 100644 --- a/src/setup/SetupHeader.cpp +++ b/src/setup/SetupHeader.cpp @@ -286,11 +286,11 @@ void SetupHeader::load(std::istream & is, const InnoVersion & version) { } if(version < INNO_VERSION(4, 2, 0)) { - password.crc32 = load_number(is), password.type = Checksum::Crc32; + password.crc32 = load_number(is), password.type = crypto::CRC32; } else if(version < INNO_VERSION(5, 3, 9)) { - is.read(password.md5, sizeof(password.md5)), password.type = Checksum::MD5; + is.read(password.md5, sizeof(password.md5)), password.type = crypto::MD5; } else { - is.read(password.sha1, sizeof(password.sha1)), password.type = Checksum::Sha1; + is.read(password.sha1, sizeof(password.sha1)), password.type = crypto::SHA1; } if(version >= INNO_VERSION(4, 2, 2)) { is.read(passwordSalt, sizeof(passwordSalt)); diff --git a/src/setup/SetupHeader.hpp b/src/setup/SetupHeader.hpp index d2c5828..a304927 100644 --- a/src/setup/SetupHeader.hpp +++ b/src/setup/SetupHeader.hpp @@ -8,7 +8,7 @@ #include #include -#include "crypto/Checksum.hpp" +#include "crypto/checksum.hpp" #include "setup/Version.hpp" #include "setup/WindowsVersion.hpp" #include "stream/chunk.hpp" @@ -152,7 +152,7 @@ struct SetupHeader { Color wizardImageBackColor; Color wizardSmallImageBackColor; - Checksum password; + crypto::checksum password; SetupSalt passwordSalt; int64_t extraDiskSpaceRequired; diff --git a/src/stream/block.cpp b/src/stream/block.cpp index 418be46..648c44d 100644 --- a/src/stream/block.cpp +++ b/src/stream/block.cpp @@ -16,7 +16,7 @@ #include #include -#include "crypto/CRC32.hpp" +#include "crypto/crc32.hpp" #include "setup/Version.hpp" #include "stream/lzma.hpp" #include "util/endian.hpp" @@ -78,7 +78,7 @@ public: throw block_error("unexpected block end"); } - Crc32 actual; + crypto::crc32 actual; actual.init(); actual.update(buffer, length); if(actual.finalize() != block_crc32) { @@ -131,7 +131,7 @@ namespace stream { block_reader::pointer block_reader::get(std::istream & base, const InnoVersion & version) { uint32_t expected_checksum = load_number(base); - Crc32 actual_checksum; + crypto::crc32 actual_checksum; actual_checksum.init(); uint32_t stored_size; diff --git a/src/stream/checksum.hpp b/src/stream/checksum.hpp index 498cf57..3331963 100644 --- a/src/stream/checksum.hpp +++ b/src/stream/checksum.hpp @@ -5,7 +5,7 @@ #include #include -#include "crypto/Hasher.hpp" +#include "crypto/hasher.hpp" namespace stream { @@ -20,7 +20,7 @@ public: typedef base_type::char_type char_type; typedef base_type::category category; - inline checksum_filter(Hasher * _hasher) : hasher(_hasher) { } + inline checksum_filter(crypto::hasher * _hasher) : hasher(_hasher) { } inline checksum_filter(const checksum_filter & o) : hasher(o.hasher) { } template @@ -37,7 +37,7 @@ public: private: - Hasher * hasher; + crypto::hasher * hasher; }; diff --git a/src/stream/file.cpp b/src/stream/file.cpp index 5002f9e..7ed2dca 100644 --- a/src/stream/file.cpp +++ b/src/stream/file.cpp @@ -228,7 +228,7 @@ std::streamsize inno_exe_decoder_5200::read(Source & src, char * dest, std::stre } // anonymous namespace file_reader::pointer file_reader::get(base_type & base, const FileLocationEntry & location, - const InnoVersion & version, Hasher & hasher) { + const InnoVersion & version, crypto::hasher & hasher) { hasher.init(location.checksum.type); diff --git a/src/stream/file.hpp b/src/stream/file.hpp index 80925c6..bc73d37 100644 --- a/src/stream/file.hpp +++ b/src/stream/file.hpp @@ -7,7 +7,7 @@ #include #include -class Hasher; +namespace crypto { class hasher; } struct FileLocationEntry; struct InnoVersion; @@ -23,7 +23,7 @@ public: typedef boost::shared_ptr pointer; static pointer get(base_type & base, const FileLocationEntry & location, - const InnoVersion & version, Hasher & hasher); + const InnoVersion & version, crypto::hasher & hasher); }; diff --git a/src/util/types.hpp b/src/util/types.hpp index db14741..3bff4e1 100644 --- a/src/util/types.hpp +++ b/src/util/types.hpp @@ -51,4 +51,17 @@ inline bool is_aligned(const void * p) { return is_aligned_on(p, alignment_of()); } +template +class static_polymorphic { + +protected: + + typedef Impl impl_type; + + inline impl_type & impl() { return *static_cast(this); } + + inline const impl_type & impl() const { return *static_cast(this); } + +}; + #endif // INNOEXTRACT_UTIL_TYPES_HPP diff --git a/src/util/util.hpp b/src/util/util.hpp index 7dd9d95..a3a2697 100644 --- a/src/util/util.hpp +++ b/src/util/util.hpp @@ -63,4 +63,35 @@ inline T safe_left_shift(T value) { return detail::safe_shifter<(bits >= (8 * sizeof(T)))>::left_shift(value, bits); } +template inline T rotl_fixed(T x, unsigned int y) { + return T((x << y) | (x >> (sizeof(T) * 8 - y))); +} + +#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) + +template<> inline uint8_t rotl_fixed(uint8_t x, unsigned int y) { + return y ? _rotl8(x, y) : x; +} + +// Intel C++ Compiler 10.0 gives undefined externals with these +template<> inline uint16_t rotl_fixed(uint16_t x, unsigned int y) { + return y ? _rotl16(x, y) : x; +} + +#endif + +#ifdef _MSC_VER +template<> inline uint32_t rotl_fixed(uint32_t x, unsigned int y) { + return y ? _lrotl(x, y) : x; +} +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(__INTEL_COMPILER) +// Intel C++ Compiler 10.0 calls a function instead of using the rotate instruction when +// using these instructions +template<> inline uint64_t rotl_fixed(uint64_t x, unsigned int y) { + return y ? _rotl64(x, y) : x; +} +#endif + #endif // INNOEXTRACT_UTIL_UTIL_HPP