diff --git a/BKImage.cpp b/BKImage.cpp index 6b125df..82032fc 100644 --- a/BKImage.cpp +++ b/BKImage.cpp @@ -245,6 +245,16 @@ void CBKImage::PrintCatalogTableTail() std::wcout << std::endl; } +bool CBKImage::PrintImageSHA1() +{ + std::wstring imageSha1 = m_pFloppyImage->CalcImageSHA1(); + if (imageSha1.empty()) + return false; + + std::wcout << L"SHA1: " << imageSha1 << std::endl; + return true; +} + bool CBKImage::PrintImageInfo() { if (!m_pFloppyImage->ReadCurrentDir()) diff --git a/BKImage.h b/BKImage.h index 968842a..b74921e 100644 --- a/BKImage.h +++ b/BKImage.h @@ -119,6 +119,9 @@ class CBKImage } inline void SetListingFormat(LISTING_FORMAT format) { m_nListingFormat = format; } + // Подсчитать и напечатать значение хэша SHA1 для образа диска + bool PrintImageSHA1(); + // Печать общей информации об образе диска bool PrintImageInfo(); diff --git a/BKImgFile.cpp b/BKImgFile.cpp index bf94001..2099a7e 100644 --- a/BKImgFile.cpp +++ b/BKImgFile.cpp @@ -1,5 +1,7 @@ #include "pch.h" #include "BKImgFile.h" +#include "StringUtil.h" +#include "hashes/sha1.hpp" constexpr auto BLOCK_SIZE = 512; @@ -238,3 +240,38 @@ bool CBKImgFile::IsFileOpen() const return false; } + +std::wstring CBKImgFile::CalcImageSHA1() +{ + if (!m_f) + return L""; + + const size_t bufferSizeInBlocks = 16; + const size_t bufferSizeInBytes = BLOCK_SIZE * bufferSizeInBlocks; + + long sizeTotal = GetFileSize(); + if (sizeTotal < 0) + return L""; + + std::vector vec(bufferSizeInBytes); + uint32_t lbano = 0; + SHA1 hash; + long reminder = sizeTotal; + while (reminder > 0) + { + uint32_t blocksToRead = reminder >= bufferSizeInBytes + ? bufferSizeInBlocks + : (reminder + BLOCK_SIZE - 1) / BLOCK_SIZE; + + //TODO: Показать что за ошибка + if (!ReadLBA(vec.data(), lbano, blocksToRead)) + return L""; + + hash.update(vec.data(), blocksToRead * BLOCK_SIZE); + + lbano += blocksToRead; + reminder -= blocksToRead * BLOCK_SIZE; + } + + return strUtil::stringToWstring(hash.final()); +} diff --git a/BKImgFile.h b/BKImgFile.h index 900992e..b3348d2 100644 --- a/BKImgFile.h +++ b/BKImgFile.h @@ -31,6 +31,10 @@ class CBKImgFile bool Open(const fs::path &pathName, const bool bWrite); void Close(); + long GetFileSize() const; + bool SeekTo00() const; + bool IsFileOpen() const; + // установка новых значений CHS // если какое-то значение == 255, то заданное значение не меняется void SetGeometry(const uint8_t c, const uint8_t h, const uint8_t s); @@ -47,7 +51,5 @@ class CBKImgFile bool ReadLBA(void *buffer, const uint32_t lba, const uint32_t numSectors) const; bool WriteLBA(void *buffer, const uint32_t lba, const uint32_t numSectors) const; - long GetFileSize() const; - bool SeekTo00() const; - bool IsFileOpen() const; + std::wstring CalcImageSHA1(); }; diff --git a/bkdecmd.cpp b/bkdecmd.cpp index 2f88e01..b0182bd 100644 --- a/bkdecmd.cpp +++ b/bkdecmd.cpp @@ -258,6 +258,10 @@ int wmain_impl(std::vector& wargs) std::wcout << L"Размер: " << g_BKImage.GetImgSize() << L" "; //std::wcout << L"Свободно: " << g_BKImage.GetImageFreeSpace() << L" "; std::wcout << L"Режим: " << (g_BKImage.GetImageOpenStatus() ? L"RO" : L"RW") << std::endl; + + if (!g_BKImage.PrintImageSHA1()) + return 255; + std::wcout << std::endl; // Main task diff --git a/bkdecmd.vcxproj b/bkdecmd.vcxproj index 222331a..06c62c4 100644 --- a/bkdecmd.vcxproj +++ b/bkdecmd.vcxproj @@ -161,6 +161,7 @@ + diff --git a/bkdecmd.vcxproj.filters b/bkdecmd.vcxproj.filters index c99121d..f8bb6d6 100644 --- a/bkdecmd.vcxproj.filters +++ b/bkdecmd.vcxproj.filters @@ -134,5 +134,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/hashes/sha1.hpp b/hashes/sha1.hpp new file mode 100644 index 0000000..ba67158 --- /dev/null +++ b/hashes/sha1.hpp @@ -0,0 +1,340 @@ +/* + sha1.hpp - source code of + + ============ + SHA-1 in C++ + ============ + + 100% Public Domain. + + Original C Code + -- Steve Reid + Small changes to fit into bglibs + -- Bruce Guenter + Translation to simpler C++ Code + -- Volker Diels-Grabsch + Safety fixes + -- Eugene Hopkinson + Header-only library + -- Zlatko Michailov +*/ + +#ifndef SHA1_HPP +#define SHA1_HPP + + +#include +#include +#include +#include +#include +#include + + +class SHA1 +{ +public: + SHA1(); + void update(const std::string &s); + void update(const uint8_t* buffer, size_t size); + void update(std::istream &is); + std::string final(); + static std::string from_file(const std::string &filename); + +private: + uint32_t digest[5]; + std::string buffer; + uint64_t transforms; +}; + + +static const size_t BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */ +static const size_t BLOCK_BYTES = BLOCK_INTS * 4; + + +inline static void reset(uint32_t digest[], std::string &buffer, uint64_t &transforms) +{ + /* SHA1 initialization constants */ + digest[0] = 0x67452301; + digest[1] = 0xefcdab89; + digest[2] = 0x98badcfe; + digest[3] = 0x10325476; + digest[4] = 0xc3d2e1f0; + + /* Reset counters */ + buffer = ""; + transforms = 0; +} + + +inline static uint32_t rol(const uint32_t value, const size_t bits) +{ + return (value << bits) | (value >> (32 - bits)); +} + + +inline static uint32_t blk(const uint32_t block[BLOCK_INTS], const size_t i) +{ + return rol(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i], 1); +} + + +/* + * (R0+R1), R2, R3, R4 are the different operations used in SHA1 + */ + +inline static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5); + w = rol(w, 30); +} + + +inline static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5); + w = rol(w, 30); +} + + +inline static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5); + w = rol(w, 30); +} + + +inline static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5); + w = rol(w, 30); +} + + +inline static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5); + w = rol(w, 30); +} + + +/* + * Hash a single 512-bit block. This is the core of the algorithm. + */ + +inline static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &transforms) +{ + /* Copy digest[] to working vars */ + uint32_t a = digest[0]; + uint32_t b = digest[1]; + uint32_t c = digest[2]; + uint32_t d = digest[3]; + uint32_t e = digest[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(block, a, b, c, d, e, 0); + R0(block, e, a, b, c, d, 1); + R0(block, d, e, a, b, c, 2); + R0(block, c, d, e, a, b, 3); + R0(block, b, c, d, e, a, 4); + R0(block, a, b, c, d, e, 5); + R0(block, e, a, b, c, d, 6); + R0(block, d, e, a, b, c, 7); + R0(block, c, d, e, a, b, 8); + R0(block, b, c, d, e, a, 9); + R0(block, a, b, c, d, e, 10); + R0(block, e, a, b, c, d, 11); + R0(block, d, e, a, b, c, 12); + R0(block, c, d, e, a, b, 13); + R0(block, b, c, d, e, a, 14); + R0(block, a, b, c, d, e, 15); + R1(block, e, a, b, c, d, 0); + R1(block, d, e, a, b, c, 1); + R1(block, c, d, e, a, b, 2); + R1(block, b, c, d, e, a, 3); + R2(block, a, b, c, d, e, 4); + R2(block, e, a, b, c, d, 5); + R2(block, d, e, a, b, c, 6); + R2(block, c, d, e, a, b, 7); + R2(block, b, c, d, e, a, 8); + R2(block, a, b, c, d, e, 9); + R2(block, e, a, b, c, d, 10); + R2(block, d, e, a, b, c, 11); + R2(block, c, d, e, a, b, 12); + R2(block, b, c, d, e, a, 13); + R2(block, a, b, c, d, e, 14); + R2(block, e, a, b, c, d, 15); + R2(block, d, e, a, b, c, 0); + R2(block, c, d, e, a, b, 1); + R2(block, b, c, d, e, a, 2); + R2(block, a, b, c, d, e, 3); + R2(block, e, a, b, c, d, 4); + R2(block, d, e, a, b, c, 5); + R2(block, c, d, e, a, b, 6); + R2(block, b, c, d, e, a, 7); + R3(block, a, b, c, d, e, 8); + R3(block, e, a, b, c, d, 9); + R3(block, d, e, a, b, c, 10); + R3(block, c, d, e, a, b, 11); + R3(block, b, c, d, e, a, 12); + R3(block, a, b, c, d, e, 13); + R3(block, e, a, b, c, d, 14); + R3(block, d, e, a, b, c, 15); + R3(block, c, d, e, a, b, 0); + R3(block, b, c, d, e, a, 1); + R3(block, a, b, c, d, e, 2); + R3(block, e, a, b, c, d, 3); + R3(block, d, e, a, b, c, 4); + R3(block, c, d, e, a, b, 5); + R3(block, b, c, d, e, a, 6); + R3(block, a, b, c, d, e, 7); + R3(block, e, a, b, c, d, 8); + R3(block, d, e, a, b, c, 9); + R3(block, c, d, e, a, b, 10); + R3(block, b, c, d, e, a, 11); + R4(block, a, b, c, d, e, 12); + R4(block, e, a, b, c, d, 13); + R4(block, d, e, a, b, c, 14); + R4(block, c, d, e, a, b, 15); + R4(block, b, c, d, e, a, 0); + R4(block, a, b, c, d, e, 1); + R4(block, e, a, b, c, d, 2); + R4(block, d, e, a, b, c, 3); + R4(block, c, d, e, a, b, 4); + R4(block, b, c, d, e, a, 5); + R4(block, a, b, c, d, e, 6); + R4(block, e, a, b, c, d, 7); + R4(block, d, e, a, b, c, 8); + R4(block, c, d, e, a, b, 9); + R4(block, b, c, d, e, a, 10); + R4(block, a, b, c, d, e, 11); + R4(block, e, a, b, c, d, 12); + R4(block, d, e, a, b, c, 13); + R4(block, c, d, e, a, b, 14); + R4(block, b, c, d, e, a, 15); + + /* Add the working vars back into digest[] */ + digest[0] += a; + digest[1] += b; + digest[2] += c; + digest[3] += d; + digest[4] += e; + + /* Count the number of transformations */ + transforms++; +} + + +inline static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]) +{ + /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */ + for (size_t i = 0; i < BLOCK_INTS; i++) + { + block[i] = (buffer[4*i+3] & 0xff) + | (buffer[4*i+2] & 0xff)<<8 + | (buffer[4*i+1] & 0xff)<<16 + | (buffer[4*i+0] & 0xff)<<24; + } +} + + +inline SHA1::SHA1() +{ + reset(digest, buffer, transforms); +} + + +inline void SHA1::update(const uint8_t* buffer, size_t size) +{ + std::string s(reinterpret_cast(buffer), size); + update(s); +} + +inline void SHA1::update(const std::string &s) +{ + std::istringstream is(s); + update(is); +} + +inline void SHA1::update(std::istream &is) +{ + while (true) + { + char sbuf[BLOCK_BYTES]; + is.read(sbuf, BLOCK_BYTES - buffer.size()); + buffer.append(sbuf, (std::size_t)is.gcount()); + if (buffer.size() != BLOCK_BYTES) + { + return; + } + uint32_t block[BLOCK_INTS]; + buffer_to_block(buffer, block); + transform(digest, block, transforms); + buffer.clear(); + } +} + + +/* + * Add padding and return the message digest. + */ + +inline std::string SHA1::final() +{ + /* Total number of hashed bits */ + uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; + + /* Padding */ + buffer += (char)0x80; + size_t orig_size = buffer.size(); + while (buffer.size() < BLOCK_BYTES) + { + buffer += (char)0x00; + } + + uint32_t block[BLOCK_INTS]; + buffer_to_block(buffer, block); + + if (orig_size > BLOCK_BYTES - 8) + { + transform(digest, block, transforms); + for (size_t i = 0; i < BLOCK_INTS - 2; i++) + { + block[i] = 0; + } + } + + /* Append total_bits, split this uint64_t into two uint32_t */ + block[BLOCK_INTS - 1] = (uint32_t)total_bits; + block[BLOCK_INTS - 2] = (uint32_t)(total_bits >> 32); + transform(digest, block, transforms); + + /* Hex std::string */ + std::ostringstream result; + for (size_t i = 0; i < sizeof(digest) / sizeof(digest[0]); i++) + { + result << std::hex << std::setfill('0') << std::setw(8); + result << digest[i]; + } + + /* Reset for next run */ + reset(digest, buffer, transforms); + + return result.str(); +} + + +inline std::string SHA1::from_file(const std::string &filename) +{ + std::ifstream stream(filename.c_str(), std::ios::binary); + SHA1 checksum; + checksum.update(stream); + return checksum.final(); +} + + +#endif /* SHA1_HPP */ diff --git a/imgos/BKFloppyImage_Prototype.cpp b/imgos/BKFloppyImage_Prototype.cpp index fd47384..cf594eb 100644 --- a/imgos/BKFloppyImage_Prototype.cpp +++ b/imgos/BKFloppyImage_Prototype.cpp @@ -153,6 +153,11 @@ bool CBKFloppyImage_Prototype::SeektoBlkWriteData(size_t nBlockNumber, void *ptr return false; } +std::wstring CBKFloppyImage_Prototype::CalcImageSHA1() +{ + return m_pFoppyImgFile.CalcImageSHA1(); +} + // виртуальная функция, для каждой ФС - своя реализация. bool CBKFloppyImage_Prototype::ReadCurrentDir() { diff --git a/imgos/BKFloppyImage_Prototype.h b/imgos/BKFloppyImage_Prototype.h index b8aa6fb..500aef7 100644 --- a/imgos/BKFloppyImage_Prototype.h +++ b/imgos/BKFloppyImage_Prototype.h @@ -133,6 +133,8 @@ class CBKFloppyImage_Prototype return EvenSizeByBlock_l(length) / m_nBlockSize; } + std::wstring CalcImageSHA1(); + public: // виртуальные функции // Строка с названием поля для данных, специфических для заданной ОС diff --git a/imgos/ImgUtil.cpp b/imgos/ImgUtil.cpp index 61def3b..cd20124 100644 --- a/imgos/ImgUtil.cpp +++ b/imgos/ImgUtil.cpp @@ -2,6 +2,7 @@ #include "ImgUtil.h" #include "../StringUtil.h" +#include "../hashes/sha1.hpp" const std::wstring g_strDir = L"DIR"; const std::wstring g_strUp = L"UP"; @@ -445,3 +446,12 @@ uint16_t imgUtil::CalcCRC(uint8_t *buffer, size_t len) return static_cast(crc & 0xffff); } + +std::wstring imgUtil::CalcSHA1(uint8_t* buffer, size_t length) +{ + SHA1 sha1; + sha1.update(buffer, length); + std::string result = sha1.final(); + + return strUtil::stringToWstring(result); +} diff --git a/imgos/ImgUtil.h b/imgos/ImgUtil.h index 35bf02e..d0dcdf8 100644 --- a/imgos/ImgUtil.h +++ b/imgos/ImgUtil.h @@ -166,9 +166,9 @@ namespace imgUtil return std::wstring(buf.data(), buf.data() + size); // We don't want the '\0' inside } - // получение строки из ресурсов. платформо- и системозависимая функция - //std::wstring LoadStringFromResource(__in unsigned int stringID, __in_opt HINSTANCE instance = nullptr); - bool AnalyseImportFile(AnalyseFileStruct *a); + uint16_t CalcCRC(uint8_t *buffer, size_t len); + + std::wstring CalcSHA1(uint8_t* buffer, size_t length); }