Browse Source

Cleanup crypto code.

pull/1/head
Daniel Scharrer 15 years ago
parent
commit
af38c3c859
  1. 12
      CMakeLists.txt
  2. 7
      src/InnoExtract.cpp
  3. 36
      src/crypto/Hasher.cpp
  4. 40
      src/crypto/Hasher.hpp
  5. 188
      src/crypto/IteratedHash.hpp
  6. 24
      src/crypto/MD5.hpp
  7. 24
      src/crypto/SHA-1.hpp
  8. 22
      src/crypto/adler32.cpp
  9. 9
      src/crypto/adler32.hpp
  10. 38
      src/crypto/checksum.cpp
  11. 46
      src/crypto/checksum.hpp
  12. 10
      src/crypto/crc32.cpp
  13. 9
      src/crypto/crc32.hpp
  14. 44
      src/crypto/hasher.cpp
  15. 44
      src/crypto/hasher.hpp
  16. 161
      src/crypto/iteratedhash.hpp
  17. 16
      src/crypto/md5.cpp
  18. 30
      src/crypto/md5.hpp
  19. 48
      src/crypto/sha1.cpp
  20. 30
      src/crypto/sha1.hpp
  21. 8
      src/loader/SetupLoader.cpp
  22. 4
      src/loader/SetupLoader.hpp
  23. 8
      src/setup/FileLocationEntry.cpp
  24. 4
      src/setup/FileLocationEntry.hpp
  25. 6
      src/setup/SetupHeader.cpp
  26. 4
      src/setup/SetupHeader.hpp
  27. 6
      src/stream/block.cpp
  28. 6
      src/stream/checksum.hpp
  29. 2
      src/stream/file.cpp
  30. 4
      src/stream/file.hpp
  31. 13
      src/util/types.hpp
  32. 31
      src/util/util.hpp

12
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

7
src/InnoExtract.cpp

@ -20,7 +20,7 @@
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/copy.hpp>
#include <crypto/Hasher.hpp>
#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;

36
src/crypto/Hasher.cpp

@ -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;
};
}

40
src/crypto/Hasher.hpp

@ -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<Hasher> {
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;

188
src/crypto/IteratedHash.hpp

@ -1,188 +0,0 @@
#ifndef INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP
#define INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP
// Taken from Crypto++ and modified to fit the project.
#include <stdint.h>
#include <cstring>
#include "crypto/Checksum.hpp"
#include "util/endian.hpp"
#include "util/types.hpp"
#include "util/util.hpp"
template <class T>
class IteratedHash : public ChecksumBase< IteratedHash<T> > {
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 <class T>
void IteratedHash<T>::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<uint8_t *>(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<T>(input)) {
size_t leftOver = hash(reinterpret_cast<const HashWord *>(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 <class T>
size_t IteratedHash<T>::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 <class T>
void IteratedHash<T>::pad(unsigned int lastBlockSize, uint8_t padFirst) {
size_t num = mod_power_of_2(countLo, size_t(BlockSize));
uint8_t * d = reinterpret_cast<uint8_t *>(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 <class T> 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>(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>(uint16_t x, unsigned int y) {
return y ? _rotl16(x, y) : x;
}
#endif
#ifdef _MSC_VER
template<> inline uint32_t rotlFixed<uint32_t>(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>(uint64_t x, unsigned int y) {
return y ? _rotl64(x, y) : x;
}
#endif
template <class T>
void IteratedHash<T>::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<HashWord>(digest) && HashSize % sizeof(HashWord) == 0) {
ByteOrder::byteswap_if_alien(state, reinterpret_cast<HashWord *>(digest), HashSize);
} else {
ByteOrder::byteswap_if_alien(state, state, HashSize);
memcpy(digest, state, HashSize);
}
}
#endif // INNOEXTRACT_CRYPTO_ITERATEDHASH_HPP

24
src/crypto/MD5.hpp

@ -1,24 +0,0 @@
#ifndef INNOEXTRACT_CRYPTO_MD5_HPP
#define INNOEXTRACT_CRYPTO_MD5_HPP
#include <stdint.h>
#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<Md5Transform> Md5;
#endif // INNOEXTRACT_CRYPTO_MD5_HPP

24
src/crypto/SHA-1.hpp

@ -1,24 +0,0 @@
#ifndef INNOEXTRACT_CRYPTO_SHA1_HPP
#define INNOEXTRACT_CRYPTO_SHA1_HPP
#include <stdint.h>
#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<Sha1Transform> Sha1;
#endif // INNOEXTRACT_CRYPTO_SHA1_HPP

22
src/crypto/Adler-32.cpp → 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

9
src/crypto/Adler-32.hpp → src/crypto/adler32.hpp

@ -4,10 +4,13 @@
#include <stddef.h>
#include <stdint.h>
#include "crypto/Checksum.hpp"
#include "crypto/checksum.hpp"
namespace crypto {
//! ADLER-32 checksum calculations
struct Adler32 : public ChecksumBase<Adler32> {
struct adler32 : public checksum_base<adler32> {
void init() { s1 = 1, s2 = 0; }
@ -20,4 +23,6 @@ private:
uint16_t s1, s2;
};
} // namespace crypto
#endif // INNOEXTRACT_CRYPTO_ADLER32_HPP

38
src/crypto/Checksum.cpp → src/crypto/checksum.cpp

@ -1,18 +1,13 @@
#include "crypto/Checksum.hpp"
#include "crypto/checksum.hpp"
#include <cstring>
#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;
}

46
src/crypto/Checksum.hpp → 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 Base>
class StaticPolymorphic {
protected:
inline Base & impl() { return *static_cast<Base *>(this); }
inline const Base & impl() const { return *static_cast<const Base *>(this); }
bool operator==(const checksum & other) const;
inline bool operator!=(const checksum & other) const { return !(*this == other); }
};
template <class Base>
class ChecksumBase : public StaticPolymorphic<Base> {
template <class Impl>
class checksum_base : public static_polymorphic<Impl> {
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

10
src/crypto/CRC32.cpp → 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 <boost/detail/endian.hpp>
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

9
src/crypto/CRC32.hpp → src/crypto/crc32.hpp

@ -3,10 +3,13 @@
#define INNOEXTRACT_CRYPTO_CRC32_HPP
#include <stdint.h>
#include "crypto/Checksum.hpp"
#include "crypto/checksum.hpp"
namespace crypto {
//! CRC32 checksum calculation
struct Crc32 : public ChecksumBase<Crc32> {
struct crc32 : public checksum_base<crc32> {
inline void init() { crc = CRC32_NEGL; }
@ -22,4 +25,6 @@ private:
uint32_t crc;
};
} // namespace crypto
#endif // INNOEXTRACT_CRYPTO_CRC32_HPP

44
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

44
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<hasher> {
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;

161
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 <stdint.h>
#include <cstring>
#include "crypto/checksum.hpp"
#include "util/endian.hpp"
#include "util/types.hpp"
#include "util/util.hpp"
namespace crypto {
template <class T>
class iterated_hash : public checksum_base< iterated_hash<T> > {
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 <class T>
void iterated_hash<T>::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<uint8_t *>(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<T>(input)) {
size_t leftOver = hash(reinterpret_cast<const hash_word *>(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 <class T>
size_t iterated_hash<T>::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 <class T>
void iterated_hash<T>::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<uint8_t *>(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 <class T>
void iterated_hash<T>::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<hash_word>(digest) && hash_size % sizeof(hash_word) == 0) {
byte_order::byteswap_if_alien(state, reinterpret_cast<hash_word *>(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

16
src/crypto/MD5.cpp → 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

30
src/crypto/md5.hpp

@ -0,0 +1,30 @@
#ifndef INNOEXTRACT_CRYPTO_MD5_HPP
#define INNOEXTRACT_CRYPTO_MD5_HPP
#include <stdint.h>
#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_transform> md5;
} // namespace crypto
#endif // INNOEXTRACT_CRYPTO_MD5_HPP

48
src/crypto/SHA-1.cpp → 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

30
src/crypto/sha1.hpp

@ -0,0 +1,30 @@
#ifndef INNOEXTRACT_CRYPTO_SHA1_HPP
#define INNOEXTRACT_CRYPTO_SHA1_HPP
#include <stdint.h>
#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_transform> sha1;
} // namespace crypto
#endif // INNOEXTRACT_CRYPTO_SHA1_HPP

8
src/loader/SetupLoader.cpp

@ -6,7 +6,7 @@
#include <boost/static_assert.hpp>
#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<little_endian, uint32_t>(is);
if(version >= INNO_VERSION(4, 0, 3)) {
exeChecksum.type = Checksum::Crc32;
exeChecksum.type = crypto::CRC32;
exeChecksum.crc32 = checksum.load<little_endian, uint32_t>(is);
} else {
exeChecksum.type = Checksum::Adler32;
exeChecksum.type = crypto::Adler32;
exeChecksum.adler32 = checksum.load<little_endian, uint32_t>(is);
}

4
src/loader/SetupLoader.hpp

@ -5,7 +5,7 @@
#include <stddef.h>
#include <iostream>
#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;

8
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<uint32_t>(is), checksum.type = Checksum::Crc32;
checksum.crc32 = load_number<uint32_t>(is), checksum.type = crypto::CRC32;
} else {
checksum.adler32 = load_number<uint32_t>(is), checksum.type = Checksum::Adler32;
checksum.adler32 = load_number<uint32_t>(is), checksum.type = crypto::Adler32;
}
if(version.bits == 16) {

4
src/setup/FileLocationEntry.hpp

@ -6,7 +6,7 @@
#include <ctime>
#include <iosfwd>
#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;

6
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<uint32_t>(is), password.type = Checksum::Crc32;
password.crc32 = load_number<uint32_t>(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));

4
src/setup/SetupHeader.hpp

@ -8,7 +8,7 @@
#include <string>
#include <iosfwd>
#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;

6
src/stream/block.cpp

@ -16,7 +16,7 @@
#include <boost/iostreams/read.hpp>
#include <boost/make_shared.hpp>
#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<uint32_t>(base);
Crc32 actual_checksum;
crypto::crc32 actual_checksum;
actual_checksum.init();
uint32_t stored_size;

6
src/stream/checksum.hpp

@ -5,7 +5,7 @@
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/read.hpp>
#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<typename Source>
@ -37,7 +37,7 @@ public:
private:
Hasher * hasher;
crypto::hasher * hasher;
};

2
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);

4
src/stream/file.hpp

@ -7,7 +7,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/iostreams/chain.hpp>
class Hasher;
namespace crypto { class hasher; }
struct FileLocationEntry;
struct InnoVersion;
@ -23,7 +23,7 @@ public:
typedef boost::shared_ptr<type> pointer;
static pointer get(base_type & base, const FileLocationEntry & location,
const InnoVersion & version, Hasher & hasher);
const InnoVersion & version, crypto::hasher & hasher);
};

13
src/util/types.hpp

@ -51,4 +51,17 @@ inline bool is_aligned(const void * p) {
return is_aligned_on(p, alignment_of<T>());
}
template <class Impl>
class static_polymorphic {
protected:
typedef Impl impl_type;
inline impl_type & impl() { return *static_cast<impl_type *>(this); }
inline const impl_type & impl() const { return *static_cast<const impl_type *>(this); }
};
#endif // INNOEXTRACT_UTIL_TYPES_HPP

31
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 <class T> 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>(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>(uint16_t x, unsigned int y) {
return y ? _rotl16(x, y) : x;
}
#endif
#ifdef _MSC_VER
template<> inline uint32_t rotl_fixed<uint32_t>(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>(uint64_t x, unsigned int y) {
return y ? _rotl64(x, y) : x;
}
#endif
#endif // INNOEXTRACT_UTIL_UTIL_HPP

Loading…
Cancel
Save