diff --git a/include/Arguments.hpp b/include/Arguments.hpp index 22f5215..76251e0 100644 --- a/include/Arguments.hpp +++ b/include/Arguments.hpp @@ -18,7 +18,7 @@ class Arguments { public: /// Constructor - Error(const std::string& description); + explicit Error(const std::string& description); }; /// \brief Constructor parsing command line arguments @@ -29,7 +29,7 @@ class Arguments /// \exception FileError if a file cannot be opened /// \exception ZipError if a zip entry cannot be opened /// \exception Data::Error if the loaded data cannot be used to carry out an attack - Data loadData() const; + auto loadData() const -> Data; std::optional cipherFile; ///< File containing the ciphertext std::optional cipherIndex; ///< Index of the zip entry containing ciphertext @@ -50,7 +50,7 @@ class Arguments /// Additional bytes of plaintext with their offset relative to ciphertext without encryption header (may be /// negative) - std::map extraPlaintext; + std::map extraPlaintext; /// Tell not to use the check byte derived from ciphertext entry metadata as known plaintext bool ignoreCheckByte = false; @@ -92,7 +92,7 @@ class Arguments std::optional changeKeys; /// Characters to generate password candidates - std::optional bruteforce; + std::optional> bruteforce; /// Range of password lengths to try during password recovery struct LengthInterval @@ -104,7 +104,7 @@ class Arguments std::size_t maxLength{std::numeric_limits::max()}; /// Compute the intersection between this interval and the given \a other interval - LengthInterval operator&(const LengthInterval& other) const; + auto operator&(const LengthInterval& other) const -> LengthInterval; }; /// \copydoc LengthInterval std::optional length; @@ -131,7 +131,7 @@ class Arguments const char** m_current; const char** const m_end; - bool finished() const; + auto finished() const -> bool; void parseArgument(); @@ -165,13 +165,13 @@ class Arguments help }; - std::string readString(const std::string& description); - Option readOption(const std::string& description); - int readInt(const std::string& description); - std::size_t readSize(const std::string& description); - bytevec readHex(const std::string& description); - uint32 readKey(const std::string& description); - bytevec readCharset(); + auto readString(const std::string& description) -> std::string; + auto readOption(const std::string& description) -> Option; + auto readInt(const std::string& description) -> int; + auto readSize(const std::string& description) -> std::size_t; + auto readHex(const std::string& description) -> std::vector; + auto readKey(const std::string& description) -> std::uint32_t; + auto readCharset() -> std::vector; }; #endif // BKCRACK_ARGUMENTS_HPP diff --git a/include/Attack.hpp b/include/Attack.hpp index fb6ad0b..651f8d1 100644 --- a/include/Attack.hpp +++ b/include/Attack.hpp @@ -26,16 +26,13 @@ class Attack bool exhaustive, Progress& progress); /// Carry out the attack for the given Z[2,32) value - void carryout(uint32 z7_2_32); + void carryout(std::uint32_t z7_2_32); - enum : std::size_t - { - /// Number of contiguous known plaintext bytes required by the attack - CONTIGUOUS_SIZE = 8, + /// Number of contiguous known plaintext bytes required by the attack + static constexpr std::size_t contiguousSize = 8; - /// Total number of known plaintext bytes required by the attack - ATTACK_SIZE = 12 - }; + /// Total number of known plaintext bytes required by the attack + static constexpr std::size_t attackSize = 12; private: // iterate recursively over Z-lists @@ -56,9 +53,9 @@ class Attack const bool exhaustive; Progress& progress; - u32arr zlist; - u32arr ylist; // the first two elements are not used - u32arr xlist; // the first four elements are not used + std::array zlist; + std::array ylist; // the first two elements are not used + std::array xlist; // the first four elements are not used }; /// \brief Iterate on Zi[2,32) candidates to try and find complete internal keys @@ -71,7 +68,7 @@ class Attack /// \param exhaustive True to try and find all valid keys, /// false to stop searching after the first one is found /// \param progress Object to report progress -std::vector attack(const Data& data, const u32vec& zi_2_32_vector, int& start, std::size_t index, int jobs, - bool exhaustive, Progress& progress); +auto attack(const Data& data, const std::vector& zi_2_32_vector, int& start, std::size_t index, int jobs, + bool exhaustive, Progress& progress) -> std::vector; #endif // BKCRACK_ATTACK_HPP diff --git a/include/ConsoleProgress.hpp b/include/ConsoleProgress.hpp index 6109731..ca42304 100644 --- a/include/ConsoleProgress.hpp +++ b/include/ConsoleProgress.hpp @@ -12,7 +12,8 @@ class ConsoleProgress : public Progress { public: /// Start a thread to print progress - ConsoleProgress(std::ostream& os, const std::chrono::milliseconds& interval = std::chrono::milliseconds(200)); + explicit ConsoleProgress(std::ostream& os, + const std::chrono::milliseconds& interval = std::chrono::milliseconds{200}); /// Notify and stop the printing thread ~ConsoleProgress(); diff --git a/include/Crc32Tab.hpp b/include/Crc32Tab.hpp index 226b295..3cd2407 100644 --- a/include/Crc32Tab.hpp +++ b/include/Crc32Tab.hpp @@ -8,27 +8,27 @@ class Crc32Tab { public: /// \return CRC32 using a lookup table - static inline uint32 crc32(uint32 pval, byte b) + static auto crc32(std::uint32_t pval, std::uint8_t b) -> std::uint32_t { return pval >> 8 ^ instance.crctab[lsb(pval) ^ b]; } /// \return CRC32^-1 using a lookup table - static inline uint32 crc32inv(uint32 crc, byte b) + static auto crc32inv(std::uint32_t crc, std::uint8_t b) -> std::uint32_t { return crc << 8 ^ instance.crcinvtab[msb(crc)] ^ b; } /// \return Yi[24,32) from Zi and Z{i-1} using CRC32^-1 - static inline uint32 getYi_24_32(uint32 zi, uint32 zim1) + static auto getYi_24_32(std::uint32_t zi, std::uint32_t zim1) -> std::uint32_t { return (crc32inv(zi, 0) ^ zim1) << 24; } /// \return Z{i-1}[10,32) from Zi[2,32) using CRC32^-1 - static inline uint32 getZim1_10_32(uint32 zi_2_32) + static auto getZim1_10_32(std::uint32_t zi_2_32) -> std::uint32_t { - return crc32inv(zi_2_32, 0) & MASK_10_32; // discard 10 least significant bits + return crc32inv(zi_2_32, 0) & mask<10, 32>; // discard 10 least significant bits } private: @@ -36,14 +36,8 @@ class Crc32Tab Crc32Tab(); // lookup tables - u32arr<256> crctab; - u32arr<256> crcinvtab; - - // CRC32 polynomial representation - enum : uint32 - { - CRCPOL = 0xedb88320 - }; + std::array crctab; + std::array crcinvtab; static const Crc32Tab instance; }; diff --git a/include/Data.hpp b/include/Data.hpp index 7819cdc..3c50584 100644 --- a/include/Data.hpp +++ b/include/Data.hpp @@ -8,17 +8,15 @@ /// Structure to hold the data needed for an attack struct Data { - enum : std::size_t - { - ENCRYPTION_HEADER_SIZE = 12 - }; + /// Size of the traditional PKWARE encryption header + static constexpr std::size_t encryptionHeaderSize = 12; /// Exception thrown if data cannot be used to carry out an attack class Error : public BaseError { public: /// Constructor - Error(const std::string& description); + explicit Error(const std::string& description); }; /// \brief Construct data and check it can be used to carry out an attack @@ -28,17 +26,18 @@ struct Data /// \param extraPlaintext Additional bytes of plaintext with their offset relative to ciphertext without encryption /// header (may be negative) /// \exception Error if the given data cannot be used to carry out an attack - Data(bytevec ciphertext, bytevec plaintext, int offset, const std::map& extraPlaintext); + Data(std::vector ciphertext, std::vector plaintext, int offset, + const std::map& extraPlaintext); - bytevec ciphertext; ///< ciphertext bytes including encryption header - bytevec plaintext; ///< plaintext bytes - bytevec keystream; ///< keystream bytes + std::vector ciphertext; ///< ciphertext bytes including encryption header + std::vector plaintext; ///< plaintext bytes + std::vector keystream; ///< keystream bytes /// plaintext and keystream offset relative to ciphertext with encryption header std::size_t offset; /// additional bytes of plaintext with their offset relative to ciphertext with encryption header - std::vector> extraPlaintext; + std::vector> extraPlaintext; }; #endif // BKCRACK_DATA_HPP diff --git a/include/Keys.hpp b/include/Keys.hpp index 95e9359..7b0fb5e 100644 --- a/include/Keys.hpp +++ b/include/Keys.hpp @@ -9,68 +9,73 @@ class Keys { public: - /// Constructor - Keys(uint32 x = 0x12345678, uint32 y = 0x23456789, uint32 z = 0x34567890); + /// Construct default state + Keys() = default; + + /// Construct keys from given components + Keys(std::uint32_t x, std::uint32_t y, std::uint32_t z); /// Construct keys associated to the given password - Keys(const std::string& password); + explicit Keys(const std::string& password); /// Update the state with a plaintext byte - inline void update(byte p) + void update(std::uint8_t p) { x = Crc32Tab::crc32(x, p); - y = (y + lsb(x)) * MultTab::MULT + 1; + y = (y + lsb(x)) * MultTab::mult + 1; z = Crc32Tab::crc32(z, msb(y)); } /// Update the state forward to a target offset - void update(const bytevec& ciphertext, std::size_t current, std::size_t target); + void update(const std::vector& ciphertext, std::size_t current, std::size_t target); /// Update the state backward with a ciphertext byte - inline void updateBackward(byte c) + void updateBackward(std::uint8_t c) { z = Crc32Tab::crc32inv(z, msb(y)); - y = (y - 1) * MultTab::MULTINV - lsb(x); + y = (y - 1) * MultTab::multInv - lsb(x); x = Crc32Tab::crc32inv(x, c ^ getK()); } /// Update the state backward with a plaintext byte - inline void updateBackwardPlaintext(byte p) + void updateBackwardPlaintext(std::uint8_t p) { z = Crc32Tab::crc32inv(z, msb(y)); - y = (y - 1) * MultTab::MULTINV - lsb(x); + y = (y - 1) * MultTab::multInv - lsb(x); x = Crc32Tab::crc32inv(x, p); } /// Update the state backward to a target offset - void updateBackward(const bytevec& ciphertext, std::size_t current, std::size_t target); + void updateBackward(const std::vector& ciphertext, std::size_t current, std::size_t target); /// \return X value - uint32 getX() const + auto getX() const -> std::uint32_t { return x; } /// \return Y value - uint32 getY() const + auto getY() const -> std::uint32_t { return y; } /// \return Z value - uint32 getZ() const + auto getZ() const -> std::uint32_t { return z; } /// \return the keystream byte derived from the keys - byte getK() const + auto getK() const -> std::uint8_t { return KeystreamTab::getByte(z); } private: - uint32 x, y, z; + std::uint32_t x = 0x12345678; + std::uint32_t y = 0x23456789; + std::uint32_t z = 0x34567890; }; #endif // BKCRACK_KEYS_HPP diff --git a/include/KeystreamTab.hpp b/include/KeystreamTab.hpp index a2de6d3..9eaf80a 100644 --- a/include/KeystreamTab.hpp +++ b/include/KeystreamTab.hpp @@ -11,24 +11,24 @@ class KeystreamTab public: /// \return the keystream byte ki associated to a Zi value /// \note Only Zi[2,16) is used - static inline byte getByte(uint32 zi) + static auto getByte(std::uint32_t zi) -> std::uint8_t { - return instance.keystreamtab[(zi & MASK_0_16) >> 2]; + return instance.keystreamtab[(zi & mask<0, 16>) >> 2]; } /// \return a vector of Zi[2,16) values having given [10,16) bits /// such that getByte(zi) is equal to ki /// \note the vector contains one element on average - static inline const u32vec& getZi_2_16_vector(byte ki, uint32 zi_10_16) + static auto getZi_2_16_vector(std::uint8_t ki, std::uint32_t zi_10_16) -> const std::vector& { - return instance.keystreaminvfiltertab[ki][(zi_10_16 & MASK_0_16) >> 10]; + return instance.keystreaminvfiltertab[ki][(zi_10_16 & mask<0, 16>) >> 10]; } /// \return true if the vector returned by getZi_2_16_vector is not empty, /// false otherwise - static inline bool hasZi_2_16(byte ki, uint32 zi_10_16) + static auto hasZi_2_16(std::uint8_t ki, std::uint32_t zi_10_16) -> bool { - return instance.keystreaminvexists[ki][(zi_10_16 & MASK_0_16) >> 10]; + return instance.keystreaminvexists[ki][(zi_10_16 & mask<0, 16>) >> 10]; } private: @@ -36,9 +36,9 @@ class KeystreamTab KeystreamTab(); // lookup tables - bytearr<1 << 14> keystreamtab; - std::array, 256> keystreaminvfiltertab; - std::array, 256> keystreaminvexists; + std::array keystreamtab; + std::array, 64>, 256> keystreaminvfiltertab; + std::array, 256> keystreaminvexists; static const KeystreamTab instance; }; diff --git a/include/MultTab.hpp b/include/MultTab.hpp index 55a1305..c9a0380 100644 --- a/include/MultTab.hpp +++ b/include/MultTab.hpp @@ -7,47 +7,48 @@ class MultTab { public: - /// \return MULT * x using a lookup table - static inline uint32 getMult(byte x) + /// \return mult * x using a lookup table + static auto getMult(std::uint8_t x) -> std::uint32_t { return instance.multtab[x]; } - /// \return MULT^-1 * x using a lookup table - static inline uint32 getMultinv(byte x) + /// \return mult^-1 * x using a lookup table + static auto getMultinv(std::uint8_t x) -> std::uint32_t { return instance.multinvtab[x]; } /// \return a vector of bytes x such that - /// msb(x*MULT^-1) is equal to msbprod or msbprod-1 - static inline const bytevec& getMsbProdFiber2(byte msbprodinv) + /// msb(x*mult^-1) is equal to msbprod or msbprod-1 + static auto getMsbProdFiber2(std::uint8_t msbprodinv) -> const std::vector& { return instance.msbprodfiber2[msbprodinv]; } /// \return a vector of bytes x such that - /// msb(x*MULT^-1) is equal to msbprod, msbprod-1 or msbprod+1 - static inline const bytevec& getMsbProdFiber3(byte msbprodinv) + /// msb(x*mult^-1) is equal to msbprod, msbprod-1 or msbprod+1 + static auto getMsbProdFiber3(std::uint8_t msbprodinv) -> const std::vector& { return instance.msbprodfiber3[msbprodinv]; } - enum : uint32 - { - MULT = 0x08088405, - MULTINV = 0xd94fa8cd - }; + /// Multiplicative constant used in traditional PKWARE encryption + static constexpr std::uint32_t mult = 0x08088405; + + /// Multiplicative inverse of mult modulo 2^32 + static constexpr std::uint32_t multInv = 0xd94fa8cd; + static_assert(mult * multInv == 1); private: // initialize lookup tables MultTab(); // lookup tables - u32arr<256> multtab; - u32arr<256> multinvtab; - std::array msbprodfiber2; - std::array msbprodfiber3; + std::array multtab; + std::array multinvtab; + std::array, 256> msbprodfiber2; + std::array, 256> msbprodfiber3; static const MultTab instance; }; diff --git a/include/Progress.hpp b/include/Progress.hpp index 055fdb3..6cd6d42 100644 --- a/include/Progress.hpp +++ b/include/Progress.hpp @@ -18,14 +18,14 @@ class Progress }; /// Constructor - Progress(std::ostream& os); + explicit Progress(std::ostream& os); /// Get exclusive access to the shared output stream and output progress /// information with the given function template void log(F f) { - std::scoped_lock lock{m_os_mutex}; + const auto lock = std::scoped_lock{m_os_mutex}; f(m_os); } diff --git a/include/SigintHandler.hpp b/include/SigintHandler.hpp index 071f17a..64d2d54 100644 --- a/include/SigintHandler.hpp +++ b/include/SigintHandler.hpp @@ -10,7 +10,7 @@ class SigintHandler { public: /// Enable the signal handler - SigintHandler(std::atomic& destination); + explicit SigintHandler(std::atomic& destination); /// Disable the signal handler ~SigintHandler(); @@ -19,7 +19,7 @@ class SigintHandler SigintHandler(const SigintHandler& other) = delete; /// Deleted assignment operator - SigintHandler& operator=(const SigintHandler& other) = delete; + auto operator=(const SigintHandler& other) -> SigintHandler& = delete; }; #endif // BKCRACK_SIGINTHANDLER_HPP diff --git a/include/Zip.hpp b/include/Zip.hpp index 17c7eb4..861c2b2 100644 --- a/include/Zip.hpp +++ b/include/Zip.hpp @@ -25,7 +25,7 @@ class Zip { public: /// Constructor - Error(const std::string& description); + explicit Error(const std::string& description); }; /// Encryption algorithm @@ -57,14 +57,14 @@ class Zip /// Information about a zip entry struct Entry { - std::string name; ///< File name - Encryption encryption; ///< Encryption method - Compression compression; ///< Compression method. \note It may take a value not listed in Compression - uint32 crc32; ///< CRC-32 checksum - uint64 offset; ///< Offset of local file header - uint64 packedSize; ///< Packed data size - uint64 uncompressedSize; ///< Uncompressed data size - byte checkByte; ///< Last byte of the encryption header after decryption + std::string name; ///< File name + Encryption encryption; ///< Encryption method + Compression compression; ///< Compression method. \note It may take a value not listed in Compression + std::uint32_t crc32; ///< CRC-32 checksum + std::uint64_t offset; ///< Offset of local file header + std::uint64_t packedSize; ///< Packed data size + std::uint64_t uncompressedSize; ///< Uncompressed data size + std::uint8_t checkByte; ///< Last byte of the encryption header after decryption }; /// Single-pass input iterator that reads successive Entry objects @@ -89,33 +89,33 @@ class Zip /// \brief Get the current entry /// \pre The iterator must be valid - const Entry& operator*() const + auto operator*() const -> const Entry& { return *m_entry; } /// \brief Access a member of the current entry /// \pre The iterator must be valid - const Entry* operator->() const + auto operator->() const -> const Entry* { return &(*m_entry); } /// \brief Read the next central directory record if any or assign end-of-stream iterator /// \pre The iterator must be valid - Iterator& operator++(); + auto operator++() -> Iterator&; /// \copydoc operator++ - Iterator operator++(int); + auto operator++(int) -> Iterator; /// Test if iterators are equivalent, i.e. both are end-of-stream or both are valid - bool operator==(const Zip::Iterator& other) const + auto operator==(const Zip::Iterator& other) const -> bool { return (m_is == nullptr) == (other.m_is == nullptr); } /// Test if iterators are not equivalent - bool operator!=(const Zip::Iterator& other) const + auto operator!=(const Zip::Iterator& other) const -> bool { return !(*this == other); } @@ -135,24 +135,24 @@ class Zip explicit Zip(const std::string& filename); /// Get an iterator pointing to the first entry - Iterator begin() const + auto begin() const -> Iterator { return Iterator{*this}; } /// Get an end-of-stream iterator - Iterator end() const + auto end() const -> Iterator { return Iterator{}; } /// \brief Get the first entry having the given name /// \exception Error if the archive does not contain an entry with the given name - Entry operator[](const std::string& name) const; + auto operator[](const std::string& name) const -> Entry; /// \brief Get the entry at the given index /// \exception Error if the index is out of bounds - Entry operator[](std::size_t index) const; + auto operator[](std::size_t index) const -> Entry; /// \brief Check that the given entry uses the expected encryption algorithm /// \exception Error if the given entry does not use the expected encryption algorithm @@ -160,11 +160,12 @@ class Zip /// \brief Set the underlying stream's input position indicator at the beginning the given entry's raw data /// \exception Error if the given entry's data is not at the expected offset - std::istream& seek(const Entry& entry) const; + auto seek(const Entry& entry) const -> std::istream&; /// \brief Load at most \a count bytes of the given entry's raw data /// \exception Error if the given entry's data is not at the expected offset - bytevec load(const Entry& entry, std::size_t count = std::numeric_limits::max()) const; + auto load(const Entry& entry, std::size_t count = std::numeric_limits::max()) const + -> std::vector; /// \brief Copy the zip file into \a os changing the encrypted data using the given keys /// \exception Error if the archive is not a valid zip archive @@ -173,7 +174,7 @@ class Zip private: std::optional m_file; // optionally own the stream std::istream& m_is; - const uint64 m_centralDirectoryOffset; + const std::uint64_t m_centralDirectoryOffset; }; #endif // BKCRACK_ZIP_HPP diff --git a/include/Zreduction.hpp b/include/Zreduction.hpp index 0674fd8..19ab1f9 100644 --- a/include/Zreduction.hpp +++ b/include/Zreduction.hpp @@ -9,7 +9,7 @@ class Zreduction { public: /// Constructor generating Zi[10,32) values from the last keystream byte - Zreduction(const bytevec& keystream); + explicit Zreduction(const std::vector& keystream); /// Reduce Zi[10,32) number using extra contiguous keystream void reduce(Progress& progress); @@ -18,23 +18,17 @@ class Zreduction void generate(); /// \return the generated Zi[2,32) values - const u32vec& getCandidates() const; + auto getCandidates() const -> const std::vector&; /// \return the index of the Zi[2,32) values relative to keystream - std::size_t getIndex() const; + auto getIndex() const -> std::size_t; private: - enum : std::size_t - { - WAIT_SIZE = 1 << 8, - TRACK_SIZE = 1 << 16 - }; - - const bytevec& keystream; + const std::vector& keystream; // After constructor or reduce(), contains Z[10,32) values. // After generate(), contains Zi[2,32) values. - u32vec zi_vector; - std::size_t index; + std::vector zi_vector; + std::size_t index; }; #endif // BKCRACK_ZREDUCTION_HPP diff --git a/include/file.hpp b/include/file.hpp index ce8874b..a2cb0ad 100644 --- a/include/file.hpp +++ b/include/file.hpp @@ -12,11 +12,11 @@ /// /// input [ label="filename" ]; /// output [ label="filename" ]; -/// bytevec [ URL="\ref bytevec" ]; +/// buffer [ label="std::vector" ]; /// /// input -> "std::ifstream" [ label="openInput", URL="\ref openInput"]; -/// "std::ifstream" -> bytevec [ label="loadStream", URL="\ref loadStream"]; -/// input -> bytevec [ label="loadFile", URL="\ref loadFile"]; +/// "std::ifstream" -> buffer [ label="loadStream", URL="\ref loadStream"]; +/// input -> buffer [ label="loadFile", URL="\ref loadFile"]; /// /// output -> "std::ofstream" [ label="openOutput", URL="\ref openOutput"]; /// } @@ -31,22 +31,22 @@ class FileError : public BaseError { public: /// Constructor - FileError(const std::string& description); + explicit FileError(const std::string& description); }; /// \brief Open an input file stream /// \exception FileError if the file cannot be opened -std::ifstream openInput(const std::string& filename); +auto openInput(const std::string& filename) -> std::ifstream; /// Load at most \a size bytes from an input stream -bytevec loadStream(std::istream& is, std::size_t size); +auto loadStream(std::istream& is, std::size_t size) -> std::vector; /// \brief Load at most \a size bytes from a file /// \exception FileError if the file cannot be opened -bytevec loadFile(const std::string& filename, std::size_t size); +auto loadFile(const std::string& filename, std::size_t size) -> std::vector; /// \brief Open an output file stream /// \exception FileError if the file cannot be opened -std::ofstream openOutput(const std::string& filename); +auto openOutput(const std::string& filename) -> std::ofstream; #endif // BKCRACK_FILE_HPP diff --git a/include/log.hpp b/include/log.hpp index bdaea9d..f6351b3 100644 --- a/include/log.hpp +++ b/include/log.hpp @@ -7,12 +7,12 @@ /// \brief Output stream manipulators /// Insert the current local time into the output stream -std::ostream& put_time(std::ostream& os); +auto put_time(std::ostream& os) -> std::ostream&; class Keys; // forward declaration /// \brief Insert a representation of keys into the stream \a os /// \relates Keys -std::ostream& operator<<(std::ostream& os, const Keys& keys); +auto operator<<(std::ostream& os, const Keys& keys) -> std::ostream&; #endif // BKCRACK_LOG_HPP diff --git a/include/password.hpp b/include/password.hpp index 40c8445..cd56d63 100644 --- a/include/password.hpp +++ b/include/password.hpp @@ -14,8 +14,8 @@ class Recovery { public: /// Constructor - Recovery(const Keys& keys, const bytevec& charset, std::vector& solutions, std::mutex& solutionsMutex, - bool exhaustive, Progress& progress); + Recovery(const Keys& keys, const std::vector& charset, std::vector& solutions, + std::mutex& solutionsMutex, bool exhaustive, Progress& progress); /// \brief Look for a password of length 6 or less /// @@ -46,7 +46,7 @@ class Recovery std::string prefix; /// Set of characters to generate password candidates - const bytevec& charset; + const std::vector& charset; private: // iterate recursively on possible Y values @@ -60,10 +60,10 @@ class Recovery // cipher state (X,Y,Z)_i for index i in [0, 6] where the last state (X,Y,Z)_6 is // the representation of the password to recover - u32arr<7> x, y, z; - uint32 x0; // backup of candidate X value for convenience + std::array x, y, z; + std::uint32_t candidateX0; // backup of candidate X value for convenience - bytearr<6> p; // password last 6 bytes + std::array p; // password last 6 bytes std::vector& solutions; // shared output vector of valid passwords std::mutex& solutionsMutex; @@ -85,8 +85,8 @@ class Recovery /// \return A vector of passwords associated with the given keys. /// A vector is needed instead of a single string because there can be /// collisions (i.e. several passwords for the same keys). -std::vector recoverPassword(const Keys& keys, const bytevec& charset, std::size_t minLength, - std::size_t maxLength, std::string& start, int jobs, bool exhaustive, - Progress& progress); +auto recoverPassword(const Keys& keys, const std::vector& charset, std::size_t minLength, + std::size_t maxLength, std::string& start, int jobs, bool exhaustive, Progress& progress) + -> std::vector; #endif // BKCRACK_PASSWORD_HPP diff --git a/include/types.hpp b/include/types.hpp index d7b9658..439f114 100644 --- a/include/types.hpp +++ b/include/types.hpp @@ -2,7 +2,7 @@ #define BKCRACK_TYPES_HPP /// \file types.hpp -/// \brief Typedefs, useful constants and utility functions +/// \brief Useful types, constants and utility functions #include #include @@ -15,62 +15,28 @@ class BaseError : public std::runtime_error { public: /// Constructor - BaseError(const std::string& type, const std::string& description); + explicit BaseError(const std::string& type, const std::string& description); }; -// scalar types - -using byte = std::uint8_t; ///< Unsigned integer type with width of exactly 8 bits -using uint16 = std::uint16_t; ///< Unsigned integer type with width of exactly 16 bits -using uint32 = std::uint32_t; ///< Unsigned integer type with width of exactly 32 bits -using uint64 = std::uint64_t; ///< Unsigned integer type with width of exactly 64 bits - -// container types - -template -using bytearr = std::array; ///< Array of bytes - -template -using u32arr = std::array; ///< Array of 32-bits integers - -using bytevec = std::vector; ///< Vector of bytes -using u32vec = std::vector; ///< Vector of 32-bits integers - // utility functions /// \return the least significant byte of x -inline byte lsb(uint32 x) +constexpr auto lsb(std::uint32_t x) -> std::uint8_t { return x; } /// \return the most significant byte of x -inline byte msb(uint32 x) +constexpr auto msb(std::uint32_t x) -> std::uint8_t { return x >> 24; } -/// \return the absolute difference between two unsigned values -inline std::size_t absdiff(std::size_t x, std::size_t y) -{ - return x < y ? y - x : x - y; -} - // constants -/// Useful constants for masking -enum : uint32 -{ - MASK_0_16 = 0x0000ffff, - MASK_0_24 = 0x00ffffff, - MASK_0_26 = 0x03ffffff, - MASK_0_32 = 0xffffffff, - MASK_26_32 = 0xfc000000, - MASK_24_32 = 0xff000000, - MASK_10_32 = 0xfffffc00, - MASK_8_32 = 0xffffff00, - MASK_2_32 = 0xfffffffc -}; +/// Constant value for bit masking +template +constexpr auto mask = std::uint32_t{~0u << begin & ~0u >> (32 - end)}; /// \brief Maximum difference between 32-bits integers A and B[x,32) /// knowing that A = B + b and b is a byte. @@ -81,10 +47,7 @@ enum : uint32 /// A = B[0,x) + B[x,32) + b /// A - B[x,32) = B[0,x) + b /// A - B[x,32) <= 0xffffffff[0,x) + 0xff -enum : uint32 -{ - MAXDIFF_0_24 = MASK_0_24 + 0xff, - MAXDIFF_0_26 = MASK_0_26 + 0xff -}; +template +constexpr auto maxdiff = std::uint32_t{mask<0, x> + 0xff}; #endif // BKCRACK_TYPES_HPP diff --git a/include/version.hpp.in b/include/version.hpp.in index 27ea1f3..50281c5 100644 --- a/include/version.hpp.in +++ b/include/version.hpp.in @@ -1,7 +1,7 @@ #ifndef BKCRACK_VERSION_HPP #define BKCRACK_VERSION_HPP -#define BKCRACK_VERSION "@bkcrack_VERSION@" -#define BKCRACK_VERSION_DATE "@bkcrack_VERSION_DATE@" +constexpr auto bkcrackVersion = "@bkcrack_VERSION@"; +constexpr auto bkcrackVersionDate = "@bkcrack_VERSION_DATE@"; #endif // BKCRACK_VERSION_HPP diff --git a/src/Arguments.cpp b/src/Arguments.cpp index b18d4a9..164cbb2 100644 --- a/src/Arguments.cpp +++ b/src/Arguments.cpp @@ -12,9 +12,9 @@ namespace { -std::bitset<256> charRange(char first, char last) +auto charRange(char first, char last) -> std::bitset<256> { - std::bitset<256> bitset; + auto bitset = std::bitset<256>{}; do { @@ -33,31 +33,31 @@ auto translateIntParseError(F&& f, const std::string& value) } catch (const std::invalid_argument&) { - throw Arguments::Error("expected an integer, got \"" + value + "\""); + throw Arguments::Error{"expected an integer, got \"" + value + "\""}; } catch (const std::out_of_range&) { - throw Arguments::Error("integer value " + value + " is out of range"); + throw Arguments::Error{"integer value " + value + " is out of range"}; } } -int parseInt(const std::string& value) +auto parseInt(const std::string& value) -> int { return translateIntParseError([](const std::string& value) { return std::stoi(value, nullptr, 0); }, value); } -std::size_t parseSize(const std::string& value) +auto parseSize(const std::string& value) -> std::size_t { return translateIntParseError([](const std::string& value) { return std::stoull(value, nullptr, 0); }, value); } -std::variant parseInterval(const std::string& value) +auto parseInterval(const std::string& value) -> std::variant { - const std::string separator = ".."; + const auto separator = std::string{".."}; if (const auto minEnd = value.find(separator); minEnd != std::string::npos) { - Arguments::LengthInterval interval; + auto interval = Arguments::LengthInterval{}; if (0 < minEnd) interval.minLength = parseSize(value.substr(0, minEnd)); @@ -74,7 +74,7 @@ std::variant parseInterval(const std::st } // namespace Arguments::Error::Error(const std::string& description) -: BaseError("Arguments error", description) +: BaseError{"Arguments error", description} { } @@ -98,57 +98,57 @@ Arguments::Arguments(int argc, const char* argv[]) if (keys) { if (!decipheredFile && !changePassword && !changeKeys && !bruteforce) - throw Error("-d, -U, --change-keys or --bruteforce parameter is missing (required by -k)"); + throw Error{"-d, -U, --change-keys or --bruteforce parameter is missing (required by -k)"}; } else if (!password) { if (cipherFile && cipherIndex) - throw Error("-c and --cipher-index cannot be used at the same time"); + throw Error{"-c and --cipher-index cannot be used at the same time"}; if (plainFile && plainIndex) - throw Error("-p and --plain-index cannot be used at the same time"); + throw Error{"-p and --plain-index cannot be used at the same time"}; if (!cipherFile && !cipherIndex) - throw Error("-c or --cipher-index parameter is missing"); + throw Error{"-c or --cipher-index parameter is missing"}; if (!plainFile && !plainIndex && extraPlaintext.empty()) - throw Error("-p, --plain-index or -x parameter is missing"); + throw Error{"-p, --plain-index or -x parameter is missing"}; if (plainArchive && !plainFile && !plainIndex) - throw Error("-p or --plain-index parameter is missing (required by -P)"); + throw Error{"-p or --plain-index parameter is missing (required by -P)"}; if (cipherIndex && !cipherArchive) - throw Error("-C parameter is missing (required by --cipher-index)"); + throw Error{"-C parameter is missing (required by --cipher-index)"}; if (plainIndex && !plainArchive) - throw Error("-P parameter is missing (required by --plain-index)"); + throw Error{"-P parameter is missing (required by --plain-index)"}; - constexpr int minimumOffset = -static_cast(Data::ENCRYPTION_HEADER_SIZE); + constexpr auto minimumOffset = -static_cast(Data::encryptionHeaderSize); if (offset < minimumOffset) - throw Error("plaintext offset " + std::to_string(offset) + " is too small (minimum is " + - std::to_string(minimumOffset) + ")"); + throw Error{"plaintext offset " + std::to_string(offset) + " is too small (minimum is " + + std::to_string(minimumOffset) + ")"}; } if (decipheredFile && !cipherFile && !cipherIndex) - throw Error("-c or --cipher-index parameter is missing (required by -d)"); + throw Error{"-c or --cipher-index parameter is missing (required by -d)"}; if (decipheredFile && !cipherArchive && decipheredFile == cipherFile) - throw Error("-c and -d parameters must point to different files"); + throw Error{"-c and -d parameters must point to different files"}; if (changePassword && !cipherArchive) - throw Error("-C parameter is missing (required by -U)"); + throw Error{"-C parameter is missing (required by -U)"}; if (changePassword && changePassword->unlockedArchive == cipherArchive) - throw Error("-C and -U parameters must point to different files"); + throw Error{"-C and -U parameters must point to different files"}; if (changeKeys && !cipherArchive) - throw Error("-C parameter is missing (required by --change-keys)"); + throw Error{"-C parameter is missing (required by --change-keys)"}; if (changeKeys && changeKeys->unlockedArchive == cipherArchive) - throw Error("-C and --change-keys parameters must point to different files"); + throw Error{"-C and --change-keys parameters must point to different files"}; if (length && !bruteforce) - throw Error("--bruteforce parameter is missing (required by --length)"); + throw Error{"--bruteforce parameter is missing (required by --length)"}; } -Data Arguments::loadData() const +auto Arguments::loadData() const -> Data { // load known plaintext - bytevec plaintext; + auto plaintext = std::vector{}; if (plainArchive) { const auto archive = Zip{*plainArchive}; @@ -160,14 +160,14 @@ Data Arguments::loadData() const plaintext = loadFile(*plainFile, plainFilePrefix); // load ciphertext needed by the attack - std::size_t needed = Data::ENCRYPTION_HEADER_SIZE; + auto needed = Data::encryptionHeaderSize; if (!plaintext.empty()) - needed = std::max(needed, Data::ENCRYPTION_HEADER_SIZE + offset + plaintext.size()); + needed = std::max(needed, Data::encryptionHeaderSize + offset + plaintext.size()); if (!extraPlaintext.empty()) - needed = std::max(needed, Data::ENCRYPTION_HEADER_SIZE + extraPlaintext.rbegin()->first + 1); + needed = std::max(needed, Data::encryptionHeaderSize + extraPlaintext.rbegin()->first + 1); - bytevec ciphertext; - std::optional> extraPlaintextWithCheckByte; + auto ciphertext = std::vector{}; + auto extraPlaintextWithCheckByte = std::optional>{}; if (cipherArchive) { const auto archive = Zip{*cipherArchive}; @@ -184,16 +184,15 @@ Data Arguments::loadData() const else ciphertext = loadFile(*cipherFile, needed); - return Data(std::move(ciphertext), std::move(plaintext), offset, - extraPlaintextWithCheckByte.value_or(extraPlaintext)); + return {std::move(ciphertext), std::move(plaintext), offset, extraPlaintextWithCheckByte.value_or(extraPlaintext)}; } -Arguments::LengthInterval Arguments::LengthInterval::operator&(const Arguments::LengthInterval& other) const +auto Arguments::LengthInterval::operator&(const Arguments::LengthInterval& other) const -> Arguments::LengthInterval { return {std::max(minLength, other.minLength), std::min(maxLength, other.maxLength)}; } -bool Arguments::finished() const +auto Arguments::finished() const -> bool { return m_current == m_end; } @@ -228,8 +227,8 @@ void Arguments::parseArgument() break; case Option::extraPlaintext: { - int i = readInt("offset"); - for (byte b : readHex("data")) + auto i = readInt("offset"); + for (const auto b : readHex("data")) extraPlaintext[i++] = b; break; } @@ -255,7 +254,7 @@ void Arguments::parseArgument() changePassword = {readString("unlockedzip"), readString("password")}; break; case Option::changeKeys: - changeKeys = {readString("unlockedzip"), Keys{readKey("X"), readKey("Y"), readKey("Z")}}; + changeKeys = {readString("unlockedzip"), {readKey("X"), readKey("Y"), readKey("Z")}}; break; case Option::bruteforce: bruteforce = readCharset(); @@ -287,7 +286,7 @@ void Arguments::parseArgument() break; case Option::recoveryStart: { - const bytevec checkpoint = readHex("checkpoint"); + const auto checkpoint = readHex("checkpoint"); recoveryStart.assign(checkpoint.begin(), checkpoint.end()); break; } @@ -309,21 +308,21 @@ void Arguments::parseArgument() } } -std::string Arguments::readString(const std::string& description) +auto Arguments::readString(const std::string& description) -> std::string { if (finished()) - throw Error("expected " + description + ", got nothing"); + throw Error{"expected " + description + ", got nothing"}; return *m_current++; } -Arguments::Option Arguments::readOption(const std::string& description) +auto Arguments::readOption(const std::string& description) -> Arguments::Option { // clang-format off #define PAIR(string, option) {#string, Option::option} #define PAIRS(short, long, option) PAIR(short, option), PAIR(long, option) - static const std::map stringToOption = { + static const auto stringToOption = std::map{ PAIRS(-c, --cipher-file, cipherFile), PAIR ( --cipher-index, cipherIndex), PAIRS(-C, --cipher-zip, cipherArchive), @@ -356,65 +355,65 @@ Arguments::Option Arguments::readOption(const std::string& description) #undef PAIR #undef PAIRS - std::string str = readString(description); - if (auto it = stringToOption.find(str); it == stringToOption.end()) - throw Error("unknown option " + str); + const auto str = readString(description); + if (const auto it = stringToOption.find(str); it == stringToOption.end()) + throw Error{"unknown option " + str}; else return it->second; } -int Arguments::readInt(const std::string& description) +auto Arguments::readInt(const std::string& description) -> int { return parseInt(readString(description)); } -std::size_t Arguments::readSize(const std::string& description) +auto Arguments::readSize(const std::string& description) -> std::size_t { return parseSize(readString(description)); } -bytevec Arguments::readHex(const std::string& description) +auto Arguments::readHex(const std::string& description) -> std::vector { - std::string str = readString(description); + const auto str = readString(description); if (str.size() % 2) - throw Error("expected an even-length string, got " + str); - if (!std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isxdigit(c); })) - throw Error("expected " + description + " in hexadecimal, got " + str); + throw Error{"expected an even-length string, got " + str}; + if (!std::all_of(str.begin(), str.end(), [](char c) { return std::isxdigit(static_cast(c)); })) + throw Error{"expected " + description + " in hexadecimal, got " + str}; - bytevec data; - for (std::size_t i = 0; i < str.length(); i += 2) - data.push_back(static_cast(std::stoul(str.substr(i, 2), nullptr, 16))); + auto data = std::vector{}; + for (auto i = std::size_t{}; i < str.length(); i += 2) + data.push_back(static_cast(std::stoul(str.substr(i, 2), nullptr, 16))); return data; } -uint32 Arguments::readKey(const std::string& description) +auto Arguments::readKey(const std::string& description) -> std::uint32_t { - std::string str = readString(description); + const auto str = readString(description); if (str.size() > 8) - throw Error("expected a string of length 8 or less, got " + str); - if (!std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isxdigit(c); })) - throw Error("expected " + description + " in hexadecimal, got " + str); + throw Error{"expected a string of length 8 or less, got " + str}; + if (!std::all_of(str.begin(), str.end(), [](char c) { return std::isxdigit(static_cast(c)); })) + throw Error{"expected " + description + " in hexadecimal, got " + str}; - return static_cast(std::stoul(str, nullptr, 16)); + return static_cast(std::stoul(str, nullptr, 16)); } -bytevec Arguments::readCharset() +auto Arguments::readCharset() -> std::vector { - const std::bitset<256> lowercase = charRange('a', 'z'); - const std::bitset<256> uppercase = charRange('A', 'Z'); - const std::bitset<256> digits = charRange('0', '9'); - const std::bitset<256> alphanum = lowercase | uppercase | digits; - const std::bitset<256> printable = charRange(' ', '~'); - const std::bitset<256> punctuation = printable & ~alphanum; - - const std::string charsetArg = readString("charset"); + const auto lowercase = charRange('a', 'z'); + const auto uppercase = charRange('A', 'Z'); + const auto digits = charRange('0', '9'); + const auto alphanum = lowercase | uppercase | digits; + const auto printable = charRange(' ', '~'); + const auto punctuation = printable & ~alphanum; + + const auto charsetArg = readString("charset"); if (charsetArg.empty()) - throw Error("the charset for password recovery is empty"); + throw Error{"the charset for password recovery is empty"}; - std::bitset<256> charset; + auto charset = std::bitset<256>{}; for (auto it = charsetArg.begin(); it != charsetArg.end(); ++it) { @@ -439,15 +438,15 @@ bytevec Arguments::readCharset() case '?': charset.set('?'); break; // clang-format on default: - throw Error(std::string("unknown charset ?") + *it); + throw Error{std::string{"unknown charset ?"} + *it}; } } else charset.set(*it); } - bytevec result; - for (int c = 0; c < 256; c++) + auto result = std::vector{}; + for (auto c = 0; c < 256; c++) if (charset[c]) result.push_back(c); diff --git a/src/Attack.cpp b/src/Attack.cpp index a7e42e8..b37926a 100644 --- a/src/Attack.cpp +++ b/src/Attack.cpp @@ -11,16 +11,16 @@ Attack::Attack(const Data& data, std::size_t index, std::vector& solutions, std::mutex& solutionsMutex, bool exhaustive, Progress& progress) -: data(data) -, index(index + 1 - Attack::CONTIGUOUS_SIZE) -, solutions(solutions) -, solutionsMutex(solutionsMutex) -, exhaustive(exhaustive) -, progress(progress) +: data{data} +, index{index + 1 - Attack::contiguousSize} +, solutions{solutions} +, solutionsMutex{solutionsMutex} +, exhaustive{exhaustive} +, progress{progress} { } -void Attack::carryout(uint32 z7_2_32) +void Attack::carryout(std::uint32_t z7_2_32) { zlist[7] = z7_2_32; exploreZlists(7); @@ -31,16 +31,16 @@ void Attack::exploreZlists(int i) if (i != 0) // the Z-list is not complete so generate Z{i-1}[2,32) values { // get Z{i-1}[10,32) from CRC32^-1 - uint32 zim1_10_32 = Crc32Tab::getZim1_10_32(zlist[i]); + const auto zim1_10_32 = Crc32Tab::getZim1_10_32(zlist[i]); // get Z{i-1}[2,16) values from keystream byte k{i-1} and Z{i-1}[10,16) - for (uint32 zim1_2_16 : KeystreamTab::getZi_2_16_vector(data.keystream[index + i - 1], zim1_10_32)) + for (const auto zim1_2_16 : KeystreamTab::getZi_2_16_vector(data.keystream[index + i - 1], zim1_10_32)) { // add Z{i-1}[2,32) to the Z-list zlist[i - 1] = zim1_10_32 | zim1_2_16; // find Zi[0,2) from CRC32^1 - zlist[i] &= MASK_2_32; // discard 2 least significant bits + zlist[i] &= mask<2, 32>; // discard 2 least significant bits zlist[i] |= (Crc32Tab::crc32inv(zlist[i], 0) ^ zlist[i - 1]) >> 8; // get Y{i+1}[24,32) @@ -53,14 +53,14 @@ void Attack::exploreZlists(int i) else // the Z-list is complete so iterate over possible Y values { // guess Y7[8,24) and keep prod == (Y7[8,32) - 1) * mult^-1 - for (uint32 y7_8_24 = 0, prod = (MultTab::getMultinv(msb(ylist[7])) << 24) - MultTab::MULTINV; - y7_8_24 < 1 << 24; y7_8_24 += 1 << 8, prod += MultTab::MULTINV << 8) + for (auto y7_8_24 = std::uint32_t{}, prod = (MultTab::getMultinv(msb(ylist[7])) << 24) - MultTab::multInv; + y7_8_24 < 1 << 24; y7_8_24 += 1 << 8, prod += MultTab::multInv << 8) // get possible Y7[0,8) values - for (byte y7_0_8 : MultTab::getMsbProdFiber3(msb(ylist[6]) - msb(prod))) + for (const auto y7_0_8 : MultTab::getMsbProdFiber3(msb(ylist[6]) - msb(prod))) // filter Y7[0,8) using Y6[24,32) - if (prod + MultTab::getMultinv(y7_0_8) - (ylist[6] & MASK_24_32) <= MAXDIFF_0_24) + if (prod + MultTab::getMultinv(y7_0_8) - (ylist[6] & mask<24, 32>) <= maxdiff<24>) { - ylist[7] = y7_0_8 | y7_8_24 | (ylist[7] & MASK_24_32); + ylist[7] = y7_0_8 | y7_8_24 | (ylist[7] & mask<24, 32>); exploreYlists(7); } } @@ -70,17 +70,17 @@ void Attack::exploreYlists(int i) { if (i != 3) // the Y-list is not complete so generate Y{i-1} values { - uint32 fy = (ylist[i] - 1) * MultTab::MULTINV; - uint32 ffy = (fy - 1) * MultTab::MULTINV; + const auto fy = (ylist[i] - 1) * MultTab::multInv; + const auto ffy = (fy - 1) * MultTab::multInv; // get possible LSB(Xi) - for (byte xi_0_8 : MultTab::getMsbProdFiber2(msb(ffy - (ylist[i - 2] & MASK_24_32)))) + for (const auto xi_0_8 : MultTab::getMsbProdFiber2(msb(ffy - (ylist[i - 2] & mask<24, 32>)))) { // compute corresponding Y{i-1} - uint32 yim1 = fy - xi_0_8; + const auto yim1 = fy - xi_0_8; // filter values with Y{i-2}[24,32) - if (ffy - MultTab::getMultinv(xi_0_8) - (ylist[i - 2] & MASK_24_32) <= MAXDIFF_0_24 && + if (ffy - MultTab::getMultinv(xi_0_8) - (ylist[i - 2] & mask<24, 32>) <= maxdiff<24> && msb(yim1) == msb(ylist[i - 1])) { // add Y{i-1} to the Y-list @@ -100,25 +100,24 @@ void Attack::exploreYlists(int i) void Attack::testXlist() { // compute X7 - for (int i = 5; i <= 7; i++) - xlist[i] = (Crc32Tab::crc32(xlist[i - 1], data.plaintext[index + i - 1]) & MASK_8_32) // discard the LSB - | lsb(xlist[i]); // set the LSB + for (auto i = 5; i <= 7; i++) + xlist[i] = (Crc32Tab::crc32(xlist[i - 1], data.plaintext[index + i - 1]) & mask<8, 32>) // discard the LSB + | lsb(xlist[i]); // set the LSB // compute X3 - uint32 x = xlist[7]; - for (int i = 6; i >= 3; i--) + auto x = xlist[7]; + for (auto i = 6; i >= 3; i--) x = Crc32Tab::crc32inv(x, data.plaintext[index + i]); // check that X3 fits with Y1[26,32) - uint32 y1_26_32 = Crc32Tab::getYi_24_32(zlist[1], zlist[0]) & MASK_26_32; - if (((ylist[3] - 1) * MultTab::MULTINV - lsb(x) - 1) * MultTab::MULTINV - y1_26_32 > MAXDIFF_0_26) + const auto y1_26_32 = Crc32Tab::getYi_24_32(zlist[1], zlist[0]) & mask<26, 32>; + if (((ylist[3] - 1) * MultTab::multInv - lsb(x) - 1) * MultTab::multInv - y1_26_32 > maxdiff<26>) return; // decipher and filter by comparing with remaining contiguous plaintext forward - Keys keysForward(xlist[7], ylist[7], zlist[7]); + auto keysForward = Keys{xlist[7], ylist[7], zlist[7]}; keysForward.update(data.plaintext[index + 7]); - for (bytevec::const_iterator p = data.plaintext.begin() + index + 8, - c = data.ciphertext.begin() + data.offset + index + 8; + for (auto p = data.plaintext.begin() + index + 8, c = data.ciphertext.begin() + data.offset + index + 8; p != data.plaintext.end(); ++p, ++c) { if ((*c ^ keysForward.getK()) != *p) @@ -126,12 +125,12 @@ void Attack::testXlist() keysForward.update(*p); } - std::size_t indexForward = data.offset + data.plaintext.size(); + auto indexForward = data.offset + data.plaintext.size(); // and also backward - Keys keysBackward(x, ylist[3], zlist[3]); - using rit = std::reverse_iterator; - for (rit p = rit(data.plaintext.begin() + index + 3), c = rit(data.ciphertext.begin() + data.offset + index + 3); + auto keysBackward = Keys{x, ylist[3], zlist[3]}; + for (auto p = std::reverse_iterator{data.plaintext.begin() + index + 3}, + c = std::reverse_iterator{data.ciphertext.begin() + data.offset + index + 3}; p != data.plaintext.rend(); ++p, ++c) { keysBackward.updateBackward(*c); @@ -139,26 +138,26 @@ void Attack::testXlist() return; } - std::size_t indexBackward = data.offset; + auto indexBackward = data.offset; // continue filtering with extra known plaintext - for (const std::pair& extra : data.extraPlaintext) + for (const auto& [extraIndex, extraByte] : data.extraPlaintext) { - byte p; - if (extra.first < indexBackward) + auto p = std::uint8_t{}; + if (extraIndex < indexBackward) { - keysBackward.updateBackward(data.ciphertext, indexBackward, extra.first); - indexBackward = extra.first; + keysBackward.updateBackward(data.ciphertext, indexBackward, extraIndex); + indexBackward = extraIndex; p = data.ciphertext[indexBackward] ^ keysBackward.getK(); } else { - keysForward.update(data.ciphertext, indexForward, extra.first); - indexForward = extra.first; + keysForward.update(data.ciphertext, indexForward, extraIndex); + indexForward = extraIndex; p = data.ciphertext[indexForward] ^ keysForward.getK(); } - if (p != extra.second) + if (p != extraByte) return; } @@ -178,15 +177,15 @@ void Attack::testXlist() progress.state = Progress::State::EarlyExit; } -std::vector attack(const Data& data, const u32vec& zi_2_32_vector, int& start, std::size_t index, int jobs, - const bool exhaustive, Progress& progress) +auto attack(const Data& data, const std::vector& zi_2_32_vector, int& start, std::size_t index, int jobs, + const bool exhaustive, Progress& progress) -> std::vector { - const uint32* candidates = zi_2_32_vector.data(); - const auto size = static_cast(zi_2_32_vector.size()); + const auto* candidates = zi_2_32_vector.data(); + const auto size = static_cast(zi_2_32_vector.size()); - std::vector solutions; - std::mutex solutionsMutex; - Attack worker(data, index, solutions, solutionsMutex, exhaustive, progress); + auto solutions = std::vector{}; + auto solutionsMutex = std::mutex{}; + auto worker = Attack{data, index, solutions, solutionsMutex, exhaustive, progress}; progress.done = start; progress.total = size; diff --git a/src/ConsoleProgress.cpp b/src/ConsoleProgress.cpp index a816d53..6d774f0 100644 --- a/src/ConsoleProgress.cpp +++ b/src/ConsoleProgress.cpp @@ -13,7 +13,7 @@ ConsoleProgress::ConsoleProgress(std::ostream& os, const std::chrono::millisecon ConsoleProgress::~ConsoleProgress() { { - std::scoped_lock lock{m_in_destructor_mutex}; + const auto lock = std::scoped_lock{m_in_destructor_mutex}; m_in_destructor = true; } @@ -23,18 +23,18 @@ ConsoleProgress::~ConsoleProgress() void ConsoleProgress::printerFunction() { - bool repeat = true; + auto repeat = true; // Give a small delay before the first time progress is printed so that // the running operation is likely to have initialized the total number of steps. { - std::unique_lock lock(m_in_destructor_mutex); - repeat = !m_in_destructor_cv.wait_for(lock, std::chrono::milliseconds(1), [this] { return m_in_destructor; }); + auto lock = std::unique_lock{m_in_destructor_mutex}; + repeat = !m_in_destructor_cv.wait_for(lock, std::chrono::milliseconds{1}, [this] { return m_in_destructor; }); } while (repeat) { - if (int total = this->total.load()) + if (const auto total = this->total.load()) log( [done = done.load(), total](std::ostream& os) { @@ -48,11 +48,11 @@ void ConsoleProgress::printerFunction() os.flags(flagsBefore); }); - std::unique_lock lock(m_in_destructor_mutex); - repeat = !m_in_destructor_cv.wait_for(lock, m_interval, [this] { return m_in_destructor; }); + auto lock = std::unique_lock{m_in_destructor_mutex}; + repeat = !m_in_destructor_cv.wait_for(lock, m_interval, [this] { return m_in_destructor; }); } - if (int total = this->total.load()) + if (const auto total = this->total.load()) log( [done = done.load(), total](std::ostream& os) { diff --git a/src/Crc32Tab.cpp b/src/Crc32Tab.cpp index dc811f0..010188a 100644 --- a/src/Crc32Tab.cpp +++ b/src/Crc32Tab.cpp @@ -4,13 +4,16 @@ const Crc32Tab Crc32Tab::instance; Crc32Tab::Crc32Tab() { - for (int b = 0; b < 256; b++) + // CRC32 polynomial representation + constexpr auto crcPolynom = 0xedb88320; + + for (auto b = 0; b < 256; b++) { - uint32 crc = b; + auto crc = static_cast(b); // compute CRC32 from the original definition - for (int i = 0; i < 8; i++) + for (auto i = 0; i < 8; i++) if (crc & 1) - crc = crc >> 1 ^ CRCPOL; + crc = crc >> 1 ^ crcPolynom; else crc = crc >> 1; diff --git a/src/Data.cpp b/src/Data.cpp index 7575a49..2d8ff62 100644 --- a/src/Data.cpp +++ b/src/Data.cpp @@ -11,57 +11,60 @@ namespace struct Range { - std::size_t size() const + auto size() const -> std::size_t { return std::distance(begin, end); } - bool operator<(const Range& other) const + auto operator<(const Range& other) const -> bool { return size() < other.size(); } - std::vector>::iterator begin, end; + std::vector>::iterator begin; + std::vector>::iterator end; }; } // namespace Data::Error::Error(const std::string& description) -: BaseError("Data error", description) +: BaseError{"Data error", description} { } -Data::Data(bytevec ciphertextArg, bytevec plaintextArg, int offsetArg, const std::map& extraPlaintextArg) -: ciphertext(std::move(ciphertextArg)) -, plaintext(std::move(plaintextArg)) +Data::Data(std::vector ciphertextArg, std::vector plaintextArg, int offsetArg, + const std::map& extraPlaintextArg) +: ciphertext{std::move(ciphertextArg)} +, plaintext{std::move(plaintextArg)} { // validate lengths - if (ciphertext.size() < Attack::ATTACK_SIZE) - throw Error("ciphertext is too small for an attack (minimum length is " + std::to_string(Attack::ATTACK_SIZE) + - ")"); + if (ciphertext.size() < Attack::attackSize) + throw Error{"ciphertext is too small for an attack (minimum length is " + std::to_string(Attack::attackSize) + + ")"}; if (ciphertext.size() < plaintext.size()) - throw Error("ciphertext is smaller than plaintext"); + throw Error{"ciphertext is smaller than plaintext"}; // validate offsets - constexpr int minimumOffset = -static_cast(ENCRYPTION_HEADER_SIZE); + constexpr auto minimumOffset = -static_cast(encryptionHeaderSize); if (offsetArg < minimumOffset) - throw Error("plaintext offset " + std::to_string(offsetArg) + " is too small (minimum is " + - std::to_string(minimumOffset) + ")"); - if (ciphertext.size() < ENCRYPTION_HEADER_SIZE + offsetArg + plaintext.size()) - throw Error("plaintext offset " + std::to_string(offsetArg) + " is too large"); + throw Error{"plaintext offset " + std::to_string(offsetArg) + " is too small (minimum is " + + std::to_string(minimumOffset) + ")"}; + if (ciphertext.size() < encryptionHeaderSize + offsetArg + plaintext.size()) + throw Error{"plaintext offset " + std::to_string(offsetArg) + " is too large"}; if (!extraPlaintextArg.empty() && extraPlaintextArg.begin()->first < minimumOffset) - throw Error("extra plaintext offset " + std::to_string(extraPlaintextArg.begin()->first) + - " is too small (minimum is " + std::to_string(minimumOffset) + ")"); - if (!extraPlaintextArg.empty() && ciphertext.size() <= ENCRYPTION_HEADER_SIZE + extraPlaintextArg.rbegin()->first) - throw Error("extra plaintext offset " + std::to_string(extraPlaintextArg.rbegin()->first) + " is too large"); + throw Error{"extra plaintext offset " + std::to_string(extraPlaintextArg.begin()->first) + + " is too small (minimum is " + std::to_string(minimumOffset) + ")"}; + if (!extraPlaintextArg.empty() && ciphertext.size() <= encryptionHeaderSize + extraPlaintextArg.rbegin()->first) + throw Error{"extra plaintext offset " + std::to_string(extraPlaintextArg.rbegin()->first) + " is too large"}; // shift offsets to absolute values - offset = ENCRYPTION_HEADER_SIZE + offsetArg; + offset = encryptionHeaderSize + offsetArg; std::transform(extraPlaintextArg.begin(), extraPlaintextArg.end(), std::back_inserter(extraPlaintext), - [](const std::pair& extra) - { return std::make_pair(ENCRYPTION_HEADER_SIZE + extra.first, extra.second); }); + [](const std::pair& extra) { + return std::pair{encryptionHeaderSize + extra.first, extra.second}; + }); // merge contiguous plaintext with adjacent extra plaintext { @@ -70,12 +73,14 @@ Data::Data(bytevec ciphertextArg, bytevec plaintextArg, int offsetArg, const std // - [before, after) overlapping contiguous plaintext // - [after, extraPlaintext.end()) after contiguous plaintext - auto before = std::lower_bound(extraPlaintext.begin(), extraPlaintext.end(), std::make_pair(offset, byte())); - auto after = std::lower_bound(before, extraPlaintext.end(), std::make_pair(offset + plaintext.size(), byte())); + auto before = std::lower_bound(extraPlaintext.begin(), extraPlaintext.end(), std::pair{offset, std::uint8_t{}}); + auto after = + std::lower_bound(before, extraPlaintext.end(), std::pair{offset + plaintext.size(), std::uint8_t{}}); // overwrite overlapping plaintext std::for_each(before, after, - [this](const std::pair& e) { plaintext[e.first - offset] = e.second; }); + [this](const std::pair& e) + { plaintext[e.first - offset] = e.second; }); // merge contiguous plaintext with extra plaintext immediately before while (before != extraPlaintext.begin() && (before - 1)->first == offset - 1) @@ -94,11 +99,11 @@ Data::Data(bytevec ciphertextArg, bytevec plaintextArg, int offsetArg, const std // find the longest contiguous sequence in extra plaintext and use is as contiguous plaintext if sensible { - Range range = {extraPlaintext.begin(), extraPlaintext.begin()}; // empty + auto range = Range{extraPlaintext.begin(), extraPlaintext.begin()}; // empty for (auto it = extraPlaintext.begin(); it != extraPlaintext.end();) { - Range current = {it, ++it}; + auto current = Range{it, ++it}; while (it != extraPlaintext.end() && it->first == (current.end - 1)->first + 1) current.end = ++it; @@ -107,11 +112,11 @@ Data::Data(bytevec ciphertextArg, bytevec plaintextArg, int offsetArg, const std if (plaintext.size() < range.size()) { - const std::size_t plaintextSize = plaintext.size(); - const std::size_t rangeOffset = range.begin->first; + const auto plaintextSize = plaintext.size(); + const auto rangeOffset = range.begin->first; // append last bytes from the range to contiguous plaintext - for (std::size_t i = plaintextSize; i < range.size(); i++) + for (auto i = plaintextSize; i < range.size(); i++) plaintext.push_back(range.begin[i].second); // remove those bytes from the range @@ -122,7 +127,7 @@ Data::Data(bytevec ciphertextArg, bytevec plaintextArg, int offsetArg, const std // rotate extra plaintext so that it will be sorted at the end of this scope { auto before = - std::lower_bound(extraPlaintext.begin(), extraPlaintext.end(), std::make_pair(offset, byte())); + std::lower_bound(extraPlaintext.begin(), extraPlaintext.end(), std::pair{offset, std::uint8_t{}}); if (offset < rangeOffset) range = {before, std::rotate(before, range.begin, range.end)}; else @@ -130,7 +135,7 @@ Data::Data(bytevec ciphertextArg, bytevec plaintextArg, int offsetArg, const std } // swap bytes between the former contiguous plaintext and the beginning of the range - for (std::size_t i = 0; i < plaintextSize; i++) + for (auto i = std::size_t{}; i < plaintextSize; i++) { range.begin[i].first = offset + i; std::swap(plaintext[i], range.begin[i].second); @@ -141,25 +146,28 @@ Data::Data(bytevec ciphertextArg, bytevec plaintextArg, int offsetArg, const std } // check that there is enough known plaintext - if (plaintext.size() < Attack::CONTIGUOUS_SIZE) - throw Error("not enough contiguous plaintext (" + std::to_string(plaintext.size()) + - " bytes available, minimum is " + std::to_string(Attack::CONTIGUOUS_SIZE) + ")"); - if (plaintext.size() + extraPlaintext.size() < Attack::ATTACK_SIZE) - throw Error("not enough plaintext (" + std::to_string(plaintext.size() + extraPlaintext.size()) + - " bytes available, minimum is " + std::to_string(Attack::ATTACK_SIZE) + ")"); + if (plaintext.size() < Attack::contiguousSize) + throw Error{"not enough contiguous plaintext (" + std::to_string(plaintext.size()) + + " bytes available, minimum is " + std::to_string(Attack::contiguousSize) + ")"}; + if (plaintext.size() + extraPlaintext.size() < Attack::attackSize) + throw Error{"not enough plaintext (" + std::to_string(plaintext.size() + extraPlaintext.size()) + + " bytes available, minimum is " + std::to_string(Attack::attackSize) + ")"}; // reorder remaining extra plaintext for filtering { - auto before = std::lower_bound(extraPlaintext.begin(), extraPlaintext.end(), std::make_pair(offset, byte())); + auto before = std::lower_bound(extraPlaintext.begin(), extraPlaintext.end(), std::pair{offset, std::uint8_t{}}); std::reverse(extraPlaintext.begin(), before); - std::inplace_merge(extraPlaintext.begin(), before, extraPlaintext.end(), - [this](const std::pair& a, const std::pair& b) { - return absdiff(a.first, offset + Attack::CONTIGUOUS_SIZE) < - absdiff(b.first, offset + Attack::CONTIGUOUS_SIZE); - }); + std::inplace_merge( + extraPlaintext.begin(), before, extraPlaintext.end(), + [this](const std::pair& a, const std::pair& b) + { + constexpr auto absdiff = [](std::size_t x, std::size_t y) { return x < y ? y - x : x - y; }; + return absdiff(a.first, offset + Attack::contiguousSize) < + absdiff(b.first, offset + Attack::contiguousSize); + }); } // compute keystream std::transform(plaintext.begin(), plaintext.end(), ciphertext.begin() + offset, std::back_inserter(keystream), - std::bit_xor()); + std::bit_xor<>()); } diff --git a/src/Keys.cpp b/src/Keys.cpp index c65c15c..f2ad1b4 100644 --- a/src/Keys.cpp +++ b/src/Keys.cpp @@ -1,29 +1,27 @@ #include "Keys.hpp" -Keys::Keys(uint32 x, uint32 y, uint32 z) -: x(x) -, y(y) -, z(z) +Keys::Keys(std::uint32_t x, std::uint32_t y, std::uint32_t z) +: x{x} +, y{y} +, z{z} { } Keys::Keys(const std::string& password) -: Keys() { - for (char p : password) + for (const auto p : password) update(p); } -void Keys::update(const bytevec& ciphertext, std::size_t current, std::size_t target) +void Keys::update(const std::vector& ciphertext, std::size_t current, std::size_t target) { - for (bytevec::const_iterator i = ciphertext.begin() + current; i != ciphertext.begin() + target; ++i) + for (auto i = ciphertext.begin() + current; i != ciphertext.begin() + target; ++i) update(*i ^ getK()); } -void Keys::updateBackward(const bytevec& ciphertext, std::size_t current, std::size_t target) +void Keys::updateBackward(const std::vector& ciphertext, std::size_t current, std::size_t target) { - using rit = std::reverse_iterator; - - for (rit i = rit(ciphertext.begin() + current); i != rit(ciphertext.begin() + target); ++i) + for (auto i = std::reverse_iterator{ciphertext.begin() + current}; + i != std::reverse_iterator{ciphertext.begin() + target}; ++i) updateBackward(*i); } diff --git a/src/KeystreamTab.cpp b/src/KeystreamTab.cpp index 0efe078..25c84a3 100644 --- a/src/KeystreamTab.cpp +++ b/src/KeystreamTab.cpp @@ -4,9 +4,10 @@ const KeystreamTab KeystreamTab::instance; KeystreamTab::KeystreamTab() { - for (uint32 z_2_16 = 0; z_2_16 < 1 << 16; z_2_16 += 4) + for (auto z_2_16 = std::uint32_t{}; z_2_16 < 1 << 16; z_2_16 += 4) { - byte k = lsb((z_2_16 | 2) * (z_2_16 | 3) >> 8); + const auto k = lsb((z_2_16 | 2) * (z_2_16 | 3) >> 8); + keystreamtab[z_2_16 >> 2] = k; keystreaminvfiltertab[k][z_2_16 >> 10].push_back(z_2_16); keystreaminvexists[k].set(z_2_16 >> 10); diff --git a/src/MultTab.cpp b/src/MultTab.cpp index 0f6d8f6..1f5ee34 100644 --- a/src/MultTab.cpp +++ b/src/MultTab.cpp @@ -4,9 +4,9 @@ const MultTab MultTab::instance; MultTab::MultTab() { - uint32 prod = 0; // x * MULT - uint32 prodinv = 0; // x * MULT^-1 - for (int x = 0; x < 256; x++, prod += MULT, prodinv += MULTINV) + auto prod = std::uint32_t{}; // x * mult + auto prodinv = std::uint32_t{}; // x * mult^-1 + for (auto x = 0; x < 256; x++, prod += mult, prodinv += multInv) { multtab[x] = prod; multinvtab[x] = prodinv; diff --git a/src/VirtualTerminalSupport.cpp b/src/VirtualTerminalSupport.cpp index 49400ac..74c709a 100644 --- a/src/VirtualTerminalSupport.cpp +++ b/src/VirtualTerminalSupport.cpp @@ -12,7 +12,7 @@ class VirtualTerminalSupport::Impl : hStdOut{GetStdHandle(STD_OUTPUT_HANDLE)} , originalMode{[this] { - DWORD mode; + auto mode = DWORD{}; return GetConsoleMode(hStdOut, &mode) ? std::optional{mode} : std::nullopt; }()} { diff --git a/src/Zip.cpp b/src/Zip.cpp index 0aa6fc7..09ab9d8 100644 --- a/src/Zip.cpp +++ b/src/Zip.cpp @@ -5,118 +5,111 @@ #include #include #include +#include namespace { -template -std::istream& read(std::istream& is, T& x) +template +auto read(std::istream& is) -> T { - static_assert(N <= sizeof(T), "read requires output type to have at least N bytes"); - // We make no assumption about platform endianness. - x = T(); - for (std::size_t index = 0; index < N; index++) + auto x = T{}; + for (auto index = std::size_t{}; index < sizeof(T); index++) x |= static_cast(is.get()) << (8 * index); - return is; + return x; } -std::istream& read(std::istream& is, std::string& string, std::size_t length) +auto read(std::istream& is, std::size_t length) -> std::string { + auto string = std::string{}; string.resize(length); - return is.read(&string[0], string.size()); + is.read(string.data(), string.size()); + return string; } -template -std::ostream& write(std::ostream& os, const T& x) +template +auto write(std::ostream& os, const T& x) -> std::ostream& { - static_assert(N <= sizeof(T), "write requires input type to have at least N bytes"); - // We make no assumption about platform endianness. - for (std::size_t index = 0; index < N; index++) + for (auto index = std::size_t{}; index < sizeof(T); index++) os.put(lsb(x >> (8 * index))); return os; } -enum class Signature : uint32 +enum class Signature : std::uint32_t { - LOCAL_FILE_HEADER = 0x04034b50, - CENTRAL_DIRECTORY_HEADER = 0x02014b50, - ZIP64_EOCD = 0x06064b50, - ZIP64_EOCD_LOCATOR = 0x07064b50, - EOCD = 0x06054b50 + LocalFileHeader = 0x04034b50, + CentralDirectoryHeader = 0x02014b50, + Zip64Eocd = 0x06064b50, + Zip64EocdLocator = 0x07064b50, + Eocd = 0x06054b50 }; -bool checkSignature(std::istream& is, const Signature& signature) +auto checkSignature(std::istream& is, const Signature& signature) -> bool { - uint32 sig; - return read(is, sig) && sig == static_cast(signature); + const auto sig = read(is); + return is && sig == static_cast(signature); } -uint64 findCentralDirectoryOffset(std::istream& is) +auto findCentralDirectoryOffset(std::istream& is) -> std::uint64_t { - uint64 centralDirectoryOffset; + auto centralDirectoryOffset = std::uint64_t{}; // find end of central directory signature { - uint32 signature; - uint16 commentLength = 0; + auto signature = std::uint32_t{}; + auto commentLength = std::uint16_t{}; do { is.seekg(-22 - commentLength, std::ios::end); - } while (read(is, signature) && signature != static_cast(Signature::EOCD) && - commentLength++ < MASK_0_16); + signature = read(is); + } while (is && signature != static_cast(Signature::Eocd) && commentLength++ < mask<0, 16>); - if (!is || signature != static_cast(Signature::EOCD)) - throw Zip::Error("could not find end of central directory signature"); + if (!is || signature != static_cast(Signature::Eocd)) + throw Zip::Error{"could not find end of central directory signature"}; } // read end of central directory record { - uint16 disk; - - read(is, disk); + const auto disk = read(is); is.seekg(10, std::ios::cur); - read(is, centralDirectoryOffset); + centralDirectoryOffset = read(is); if (!is) - throw Zip::Error("could not read end of central directory record"); + throw Zip::Error{"could not read end of central directory record"}; if (disk != 0) - throw Zip::Error("split zip archives are not supported"); + throw Zip::Error{"split zip archives are not supported"}; } // look for Zip64 end of central directory locator is.seekg(-40, std::ios::cur); - if (checkSignature(is, Signature::ZIP64_EOCD_LOCATOR)) + if (checkSignature(is, Signature::Zip64EocdLocator)) { - uint64 zip64EndOfCentralDirectoryOffset; - is.seekg(4, std::ios::cur); - read(is, zip64EndOfCentralDirectoryOffset); + const auto zip64EndOfCentralDirectoryOffset = read(is); if (!is) - throw Zip::Error("could not read Zip64 end of central directory locator record"); + throw Zip::Error{"could not read Zip64 end of central directory locator record"}; // read Zip64 end of central directory record is.seekg(zip64EndOfCentralDirectoryOffset, std::ios::beg); - if (checkSignature(is, Signature::ZIP64_EOCD)) + if (checkSignature(is, Signature::Zip64Eocd)) { - uint16 versionNeededToExtract; - is.seekg(10, std::ios::cur); - read(is, versionNeededToExtract); + const auto versionNeededToExtract = read(is); is.seekg(32, std::ios::cur); - read(is, centralDirectoryOffset); + centralDirectoryOffset = read(is); if (!is) - throw Zip::Error("could not read Zip64 end of central directory record"); + throw Zip::Error{"could not read Zip64 end of central directory record"}; if (versionNeededToExtract >= 62) // Version 6.2 introduces central directory encryption. - throw Zip::Error("central directory encryption is not supported"); + throw Zip::Error{"central directory encryption is not supported"}; } else - throw Zip::Error("could not find Zip64 end of central directory record"); + throw Zip::Error{"could not find Zip64 end of central directory record"}; } return centralDirectoryOffset; @@ -125,7 +118,7 @@ uint64 findCentralDirectoryOffset(std::istream& is) } // namespace Zip::Error::Error(const std::string& description) -: BaseError("Zip error", description) +: BaseError{"Zip error", description} { } @@ -136,34 +129,25 @@ Zip::Iterator::Iterator(const Zip& archive) ++(*this); } -Zip::Iterator& Zip::Iterator::operator++() +auto Zip::Iterator::operator++() -> Zip::Iterator& { - if (!checkSignature(*m_is, Signature::CENTRAL_DIRECTORY_HEADER)) + if (!checkSignature(*m_is, Signature::CentralDirectoryHeader)) return *this = Iterator{}; - uint16 flags; - uint16 method; - uint16 lastModTime; - uint16 lastModDate; - - uint16 filenameLength; - uint16 extraFieldLength; - uint16 fileCommentLength; - m_is->seekg(4, std::ios::cur); - read(*m_is, flags); - read(*m_is, method); - read(*m_is, lastModTime); - read(*m_is, lastModDate); - read(*m_is, m_entry->crc32); - read(*m_is, m_entry->packedSize); - read(*m_is, m_entry->uncompressedSize); - read(*m_is, filenameLength); - read(*m_is, extraFieldLength); - read(*m_is, fileCommentLength); + const auto flags = read(*m_is); + const auto method = read(*m_is); + const auto lastModTime = read(*m_is); + m_is->seekg(2, std::ios::cur); + m_entry->crc32 = read(*m_is); + m_entry->packedSize = read(*m_is); + m_entry->uncompressedSize = read(*m_is); + const auto filenameLength = read(*m_is); + const auto extraFieldLength = read(*m_is); + const auto fileCommentLength = read(*m_is); m_is->seekg(8, std::ios::cur); - read(*m_is, m_entry->offset); - read(*m_is, m_entry->name, filenameLength); + m_entry->offset = read(*m_is); + m_entry->name = read(*m_is, filenameLength); m_entry->encryption = flags & 1 ? method == 99 || (flags >> 6) & 1 ? Encryption::Unsupported : Encryption::Traditional @@ -171,33 +155,31 @@ Zip::Iterator& Zip::Iterator::operator++() m_entry->compression = static_cast(method); - m_entry->checkByte = (flags >> 3) & 1 ? static_cast(lastModTime >> 8) : msb(m_entry->crc32); + m_entry->checkByte = (flags >> 3) & 1 ? static_cast(lastModTime >> 8) : msb(m_entry->crc32); - for (int remaining = extraFieldLength; remaining > 0;) + for (auto remaining = extraFieldLength; remaining > 0;) { // read extra field header - uint16 id; - uint16 size; - read(*m_is, id); - read(*m_is, size); + const auto id = read(*m_is); + auto size = read(*m_is); remaining -= 4 + size; switch (id) { case 0x0001: // Zip64 extended information - if (8 <= size && m_entry->uncompressedSize == MASK_0_32) + if (8 <= size && m_entry->uncompressedSize == mask<0, 32>) { - read(*m_is, m_entry->uncompressedSize); + m_entry->uncompressedSize = read(*m_is); size -= 8; } - if (8 <= size && m_entry->packedSize == MASK_0_32) + if (8 <= size && m_entry->packedSize == mask<0, 32>) { - read(*m_is, m_entry->packedSize); + m_entry->packedSize = read(*m_is); size -= 8; } - if (8 <= size && m_entry->offset == MASK_0_32) + if (8 <= size && m_entry->offset == mask<0, 32>) { - read(*m_is, m_entry->offset); + m_entry->offset = read(*m_is); size -= 8; } break; @@ -205,20 +187,18 @@ Zip::Iterator& Zip::Iterator::operator++() case 0x7075: // Info-ZIP Unicode Path if (5 <= size) { - uint32 nameCrc32 = MASK_0_32; - for (byte b : m_entry->name) - nameCrc32 = Crc32Tab::crc32(nameCrc32, b); - nameCrc32 ^= MASK_0_32; + const auto nameCrc32 = + std::accumulate(m_entry->name.begin(), m_entry->name.end(), mask<0, 32>, Crc32Tab::crc32) ^ + mask<0, 32>; - uint32 expectedNameCrc32; m_is->seekg(1, std::ios::cur); - read(*m_is, expectedNameCrc32); + const auto expectedNameCrc32 = read(*m_is); size -= 5; if (nameCrc32 == expectedNameCrc32) { - read(*m_is, m_entry->name, size); - size = 0; + m_entry->name = read(*m_is, size); + size = 0; } } break; @@ -226,12 +206,11 @@ Zip::Iterator& Zip::Iterator::operator++() case 0x9901: // AE-x encryption structure if (7 <= size) { - uint16 method; m_is->seekg(5, std::ios::cur); - read(*m_is, method); + const auto actualMethod = read(*m_is); size -= 7; - m_entry->compression = static_cast(method); + m_entry->compression = static_cast(actualMethod); } break; @@ -246,12 +225,12 @@ Zip::Iterator& Zip::Iterator::operator++() m_is->seekg(fileCommentLength, std::ios::cur); if (!*m_is) - throw Error("could not read central directory header"); + throw Error{"could not read central directory header"}; return *this; } -Zip::Iterator Zip::Iterator::operator++(int) +auto Zip::Iterator::operator++(int) -> Zip::Iterator { auto copy = *this; ++(*this); @@ -272,24 +251,24 @@ Zip::Zip(const std::string& filename) { } -Zip::Entry Zip::operator[](const std::string& name) const +auto Zip::operator[](const std::string& name) const -> Zip::Entry { const auto it = std::find_if(begin(), end(), [&name](const Entry& entry) { return entry.name == name; }); if (it == end()) - throw Error("found no entry named \"" + name + "\""); + throw Error{"found no entry named \"" + name + "\""}; else return *it; } -Zip::Entry Zip::operator[](std::size_t index) const +auto Zip::operator[](std::size_t index) const -> Zip::Entry { - std::size_t nextIndex = 0; - const auto it = std::find_if(begin(), end(), [&nextIndex, index](const Entry&) { return nextIndex++ == index; }); + auto nextIndex = std::size_t{}; + const auto it = std::find_if(begin(), end(), [&nextIndex, index](const Entry&) { return nextIndex++ == index; }); if (it == end()) - throw Error("found no entry at index " + std::to_string(index) + " (maximum index for this archive is " + - std::to_string(nextIndex - 1) + ")"); + throw Error{"found no entry at index " + std::to_string(index) + " (maximum index for this archive is " + + std::to_string(nextIndex - 1) + ")"}; else return *it; } @@ -299,47 +278,46 @@ void Zip::checkEncryption(const Entry& entry, Encryption expected) if (entry.encryption != expected) { if (entry.encryption == Encryption::None) - throw Error("entry \"" + entry.name + "\" is not encrypted"); + throw Error{"entry \"" + entry.name + "\" is not encrypted"}; else if (expected == Encryption::None) - throw Error("entry \"" + entry.name + "\" is encrypted"); + throw Error{"entry \"" + entry.name + "\" is encrypted"}; else - throw Error("entry \"" + entry.name + "\" is encrypted with an unsupported algorithm"); + throw Error{"entry \"" + entry.name + "\" is encrypted with an unsupported algorithm"}; } } -std::istream& Zip::seek(const Entry& entry) const +auto Zip::seek(const Entry& entry) const -> std::istream& { m_is.seekg(entry.offset, std::ios::beg); - if (!checkSignature(m_is, Signature::LOCAL_FILE_HEADER)) - throw Error("could not find local file header"); + if (!checkSignature(m_is, Signature::LocalFileHeader)) + throw Error{"could not find local file header"}; // skip local file header - uint16 nameSize, extraSize; m_is.seekg(22, std::ios::cur); - read(m_is, nameSize); - read(m_is, extraSize); + const auto nameSize = read(m_is); + const auto extraSize = read(m_is); m_is.seekg(nameSize + extraSize, std::ios::cur); return m_is; } -bytevec Zip::load(const Entry& entry, std::size_t count) const +auto Zip::load(const Entry& entry, std::size_t count) const -> std::vector { - return loadStream(seek(entry), std::min(entry.packedSize, static_cast(count))); + return loadStream(seek(entry), std::min(entry.packedSize, static_cast(count))); } void Zip::changeKeys(std::ostream& os, const Keys& oldKeys, const Keys& newKeys, Progress& progress) const { // Store encrypted entries local file header offset and packed size. // Use std::map to sort them by local file header offset. - std::map packedSizeByLocalOffset; + auto packedSizeByLocalOffset = std::map{}; for (const auto& entry : *this) if (entry.encryption == Encryption::Traditional) packedSizeByLocalOffset.insert({entry.offset, entry.packedSize}); // Rewind input stream and iterate on encrypted entries to change the keys, copy the rest. m_is.seekg(0, std::ios::beg); - uint64 currentOffset = 0; + auto currentOffset = std::uint64_t{}; progress.done = 0; progress.total = packedSizeByLocalOffset.size(); @@ -348,40 +326,38 @@ void Zip::changeKeys(std::ostream& os, const Keys& oldKeys, const Keys& newKeys, { if (currentOffset < localHeaderOffset) { - std::copy_n(std::istreambuf_iterator(m_is), localHeaderOffset - currentOffset, - std::ostreambuf_iterator(os)); + std::copy_n(std::istreambuf_iterator{m_is}, localHeaderOffset - currentOffset, + std::ostreambuf_iterator{os}); m_is.get(); } - if (!checkSignature(m_is, Signature::LOCAL_FILE_HEADER)) - throw Error("could not find local file header"); + if (!checkSignature(m_is, Signature::LocalFileHeader)) + throw Error{"could not find local file header"}; - write(os, static_cast(Signature::LOCAL_FILE_HEADER)); + write(os, static_cast(Signature::LocalFileHeader)); - std::copy_n(std::istreambuf_iterator(m_is), 22, std::ostreambuf_iterator(os)); + std::copy_n(std::istreambuf_iterator{m_is}, 22, std::ostreambuf_iterator{os}); m_is.get(); - uint16 filenameLength, extraSize; - read(m_is, filenameLength); - read(m_is, extraSize); + const auto filenameLength = read(m_is); + const auto extraSize = read(m_is); write(os, filenameLength); write(os, extraSize); if (0 < filenameLength + extraSize) { - std::copy_n(std::istreambuf_iterator(m_is), filenameLength + extraSize, - std::ostreambuf_iterator(os)); + std::copy_n(std::istreambuf_iterator{m_is}, filenameLength + extraSize, std::ostreambuf_iterator{os}); m_is.get(); } - Keys decrypt = oldKeys; - Keys encrypt = newKeys; - std::istreambuf_iterator in(m_is); - std::generate_n(std::ostreambuf_iterator(os), packedSize, + auto decrypt = oldKeys; + auto encrypt = newKeys; + auto in = std::istreambuf_iterator{m_is}; + std::generate_n(std::ostreambuf_iterator{os}, packedSize, [&in, &decrypt, &encrypt]() -> char { - byte p = *in++ ^ decrypt.getK(); - byte c = p ^ encrypt.getK(); + const auto p = *in++ ^ decrypt.getK(); + const auto c = p ^ encrypt.getK(); decrypt.update(p); encrypt.update(p); return c; @@ -392,6 +368,5 @@ void Zip::changeKeys(std::ostream& os, const Keys& oldKeys, const Keys& newKeys, progress.done++; } - std::copy(std::istreambuf_iterator(m_is), std::istreambuf_iterator(), - std::ostreambuf_iterator(os)); + std::copy(std::istreambuf_iterator{m_is}, {}, std::ostreambuf_iterator{os}); } diff --git a/src/Zreduction.cpp b/src/Zreduction.cpp index cee857e..d45058b 100644 --- a/src/Zreduction.cpp +++ b/src/Zreduction.cpp @@ -7,13 +7,13 @@ #include #include -Zreduction::Zreduction(const bytevec& keystream) -: keystream(keystream) +Zreduction::Zreduction(const std::vector& keystream) +: keystream{keystream} { index = keystream.size() - 1; zi_vector.reserve(1 << 22); - for (uint32 zi_10_32_shifted = 0; zi_10_32_shifted < 1 << 22; zi_10_32_shifted++) + for (auto zi_10_32_shifted = std::uint32_t{}; zi_10_32_shifted < 1 << 22; zi_10_32_shifted++) if (KeystreamTab::hasZi_2_16(keystream[index], zi_10_32_shifted << 10)) zi_vector.push_back(zi_10_32_shifted << 10); } @@ -21,33 +21,38 @@ Zreduction::Zreduction(const bytevec& keystream) void Zreduction::reduce(Progress& progress) { // variables to keep track of the smallest Zi[2,32) vector - bool tracking = false; - u32vec bestCopy; - std::size_t bestIndex = index, bestSize = TRACK_SIZE; + constexpr auto trackSizeThreshold = std::size_t{1 << 16}; + + auto tracking = false; + auto bestCopy = std::vector{}; + auto bestIndex = index; + auto bestSize = trackSizeThreshold; // variables to wait for a limited number of steps when a small enough vector is found - bool waiting = false; - std::size_t wait = 0; + constexpr auto waitSizeThreshold = std::size_t{1 << 8}; + + auto waiting = false; + auto wait = std::size_t{}; - u32vec zim1_10_32_vector; + auto zim1_10_32_vector = std::vector{}; zim1_10_32_vector.reserve(1 << 22); - std::bitset<1 << 22> zim1_10_32_set; + auto zim1_10_32_set = std::bitset<1 << 22>{}; progress.done = 0; - progress.total = keystream.size() - Attack::CONTIGUOUS_SIZE; + progress.total = keystream.size() - Attack::contiguousSize; - for (std::size_t i = index; i >= Attack::CONTIGUOUS_SIZE; i--) + for (auto i = index; i >= Attack::contiguousSize; i--) { zim1_10_32_vector.clear(); zim1_10_32_set.reset(); - std::size_t number_of_zim1_2_32 = 0; + auto number_of_zim1_2_32 = std::size_t{}; // generate the Z{i-1}[10,32) values - for (uint32 zi_10_32 : zi_vector) - for (uint32 zi_2_16 : KeystreamTab::getZi_2_16_vector(keystream[i], zi_10_32)) + for (const auto zi_10_32 : zi_vector) + for (const auto zi_2_16 : KeystreamTab::getZi_2_16_vector(keystream[i], zi_10_32)) { // get Z{i-1}[10,32) from CRC32^-1 - uint32 zim1_10_32 = Crc32Tab::getZim1_10_32(zi_10_32 | zi_2_16); + const auto zim1_10_32 = Crc32Tab::getZim1_10_32(zi_10_32 | zi_2_16); // collect without duplicates only those that are compatible with keystream{i-1} if (!zim1_10_32_set[zim1_10_32 >> 10] && KeystreamTab::hasZi_2_16(keystream[i - 1], zim1_10_32)) { @@ -72,7 +77,7 @@ void Zreduction::reduce(Progress& progress) // keep a copy of the vector because size is about to grow std::swap(bestCopy, zi_vector); - if (bestSize <= WAIT_SIZE) + if (bestSize <= waitSizeThreshold) { // enable waiting waiting = true; @@ -93,32 +98,32 @@ void Zreduction::reduce(Progress& progress) if (tracking) { // put bestCopy in zi_vector only if bestIndex is not the index of zi_vector - if (bestIndex != Attack::CONTIGUOUS_SIZE - 1) + if (bestIndex != Attack::contiguousSize - 1) std::swap(zi_vector, bestCopy); index = bestIndex; } else - index = Attack::CONTIGUOUS_SIZE - 1; + index = Attack::contiguousSize - 1; } void Zreduction::generate() { - std::size_t number_of_zi_10_32 = zi_vector.size(); - for (std::size_t i = 0; i < number_of_zi_10_32; i++) + const auto number_of_zi_10_32 = zi_vector.size(); + for (auto i = std::size_t{}; i < number_of_zi_10_32; i++) { - const u32vec& zi_2_16_vector = KeystreamTab::getZi_2_16_vector(keystream[index], zi_vector[i]); - for (std::size_t j = 1; j < zi_2_16_vector.size(); j++) + const auto& zi_2_16_vector = KeystreamTab::getZi_2_16_vector(keystream[index], zi_vector[i]); + for (auto j = std::size_t{1}; j < zi_2_16_vector.size(); j++) zi_vector.push_back(zi_vector[i] | zi_2_16_vector[j]); zi_vector[i] |= zi_2_16_vector[0]; } } -const u32vec& Zreduction::getCandidates() const +auto Zreduction::getCandidates() const -> const std::vector& { return zi_vector; } -std::size_t Zreduction::getIndex() const +auto Zreduction::getIndex() const -> std::size_t { return index; } diff --git a/src/file.cpp b/src/file.cpp index 96e12b6..4b29f8c 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1,38 +1,38 @@ #include "file.hpp" FileError::FileError(const std::string& description) -: BaseError("File error", description) +: BaseError{"File error", description} { } -std::ifstream openInput(const std::string& filename) +auto openInput(const std::string& filename) -> std::ifstream { - if (std::ifstream is = std::ifstream(filename, std::ios::binary)) + if (auto is = std::ifstream{filename, std::ios::binary}) return is; else - throw FileError("could not open input file " + filename); + throw FileError{"could not open input file " + filename}; } -bytevec loadStream(std::istream& is, std::size_t size) +auto loadStream(std::istream& is, std::size_t size) -> std::vector { - bytevec content; - std::istreambuf_iterator it(is); - for (std::size_t i = 0; i < size && it != std::istreambuf_iterator(); i++, ++it) + auto content = std::vector{}; + auto it = std::istreambuf_iterator{is}; + for (auto i = std::size_t{}; i < size && it != std::istreambuf_iterator{}; i++, ++it) content.push_back(*it); return content; } -bytevec loadFile(const std::string& filename, std::size_t size) +auto loadFile(const std::string& filename, std::size_t size) -> std::vector { - std::ifstream is = openInput(filename); + auto is = openInput(filename); return loadStream(is, size); } -std::ofstream openOutput(const std::string& filename) +auto openOutput(const std::string& filename) -> std::ofstream { - if (std::ofstream os = std::ofstream(filename, std::ios::binary)) + if (auto os = std::ofstream{filename, std::ios::binary}) return os; else - throw FileError("could not open output file " + filename); + throw FileError{"could not open output file " + filename}; } diff --git a/src/log.cpp b/src/log.cpp index d3aedec..bd5596e 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -5,13 +5,13 @@ #include #include -std::ostream& put_time(std::ostream& os) +auto put_time(std::ostream& os) -> std::ostream& { - std::time_t t = std::time(nullptr); + const auto t = std::time(nullptr); return os << std::put_time(std::localtime(&t), "%T"); } -std::ostream& operator<<(std::ostream& os, const Keys& keys) +auto operator<<(std::ostream& os, const Keys& keys) -> std::ostream& { const auto flagsBefore = os.setf(std::ios::hex, std::ios::basefield); const auto fillBefore = os.fill('0'); diff --git a/src/main.cpp b/src/main.cpp index d1ebff4..cb9415c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,7 @@ namespace { -const char* usage = R"_(usage: bkcrack [options] +const char* const usage = R"_(usage: bkcrack [options] Crack legacy zip encryption with Biham and Kocher's known plaintext attack. Options to get the internal password representation: @@ -102,16 +102,16 @@ void decipher(std::istream& is, std::size_t size, std::size_t discard, std::ostr } // namespace -int main(int argc, const char* argv[]) +auto main(int argc, const char* argv[]) -> int try { // enable virtual terminal support on Windows, no-op on other platforms - VirtualTerminalSupport vtSupport; + const auto vtSupport = VirtualTerminalSupport{}; // version information - std::cout << "bkcrack " BKCRACK_VERSION " - " BKCRACK_VERSION_DATE << std::endl; + std::cout << "bkcrack " << bkcrackVersion << " - " << bkcrackVersionDate << std::endl; - const Arguments args(argc, argv); + const auto args = Arguments{argc, argv}; if (args.help) { std::cout << usage << std::endl; @@ -130,7 +130,7 @@ try return 0; } - std::vector keysvec; + auto keysvec = std::vector{}; if (args.keys) keysvec.push_back(*args.keys); else if (args.password) @@ -142,16 +142,16 @@ try else // find keys from known plaintext { - const Data data = args.loadData(); + const auto data = args.loadData(); // generate and reduce Zi[10,32) values - Zreduction zr(data.keystream); - if (data.keystream.size() > Attack::CONTIGUOUS_SIZE) + auto zr = Zreduction{data.keystream}; + if (data.keystream.size() > Attack::contiguousSize) { - std::cout << "[" << put_time << "] Z reduction using " << (data.keystream.size() - Attack::CONTIGUOUS_SIZE) + std::cout << "[" << put_time << "] Z reduction using " << (data.keystream.size() - Attack::contiguousSize) << " bytes of known plaintext" << std::endl; - ConsoleProgress progress(std::cout); + auto progress = ConsoleProgress{std::cout}; zr.reduce(progress); } @@ -160,14 +160,14 @@ try // carry out the attack on the remaining Zi[2,32) values std::cout << "[" << put_time << "] Attack on " << zr.getCandidates().size() << " Z values at index " - << (static_cast(data.offset + zr.getIndex()) - static_cast(Data::ENCRYPTION_HEADER_SIZE)) + << (static_cast(data.offset + zr.getIndex()) - static_cast(Data::encryptionHeaderSize)) << std::endl; const auto [state, restart] = [&]() -> std::pair { - int start = args.attackStart; - ConsoleProgress progress(std::cout); - SigintHandler sigintHandler{progress.state}; + auto start = args.attackStart; + auto progress = ConsoleProgress{std::cout}; + const auto sigintHandler = SigintHandler{progress.state}; keysvec = attack(data, zr.getCandidates(), start, zr.getIndex(), args.jobs, args.exhaustive, progress); return {progress.state, start}; }(); @@ -192,14 +192,14 @@ try else { std::cout << "Keys" << std::endl; - for (const Keys& keys : keysvec) + for (const auto& keys : keysvec) std::cout << keys << std::endl; } } // From there, keysvec is not empty. - const Keys keys = keysvec.front(); + const auto keys = keysvec.front(); if ((args.decipheredFile || args.changePassword || args.changeKeys || args.bruteforce) && keysvec.size() > 1) std::cout << "Continuing with keys " << keys << "\n" << "Use the command line option -k to provide other keys." << std::endl; @@ -213,8 +213,8 @@ try std::cout << std::endl; { - std::ifstream cipherstream = openInput(args.cipherArchive ? *args.cipherArchive : *args.cipherFile); - std::size_t ciphersize = std::numeric_limits::max(); + auto cipherstream = openInput(args.cipherArchive ? *args.cipherArchive : *args.cipherFile); + auto ciphersize = std::numeric_limits::max(); if (args.cipherArchive) { @@ -226,10 +226,10 @@ try ciphersize = entry.packedSize; } - std::ofstream decipheredstream = openOutput(*args.decipheredFile); + auto decipheredstream = openOutput(*args.decipheredFile); decipher(cipherstream, ciphersize, - args.keepHeader ? 0 : static_cast(Data::ENCRYPTION_HEADER_SIZE), decipheredstream, + args.keepHeader ? 0 : static_cast(Data::encryptionHeaderSize), decipheredstream, keys); } @@ -245,10 +245,10 @@ try << newPassword << "\"" << std::endl; { - const auto archive = Zip{*args.cipherArchive}; - std::ofstream unlocked = openOutput(unlockedArchive); + const auto archive = Zip{*args.cipherArchive}; + auto unlocked = openOutput(unlockedArchive); - ConsoleProgress progress(std::cout); + auto progress = ConsoleProgress{std::cout}; archive.changeKeys(unlocked, keys, Keys{newPassword}, progress); } @@ -263,10 +263,10 @@ try << std::endl; { - const auto archive = Zip{*args.cipherArchive}; - std::ofstream unlocked = openOutput(unlockedArchive); + const auto archive = Zip{*args.cipherArchive}; + auto unlocked = openOutput(unlockedArchive); - ConsoleProgress progress(std::cout); + auto progress = ConsoleProgress{std::cout}; archive.changeKeys(unlocked, keys, newKeys, progress); } @@ -278,16 +278,15 @@ try { std::cout << "[" << put_time << "] Recovering password" << std::endl; - std::vector passwords; + auto passwords = std::vector{}; const auto [state, restart] = [&]() -> std::pair { const auto& charset = *args.bruteforce; const auto& [minLength, maxLength] = args.length.value_or(Arguments::LengthInterval{}); - std::string start = args.recoveryStart; - - ConsoleProgress progress(std::cout); - SigintHandler sigintHandler(progress.state); + auto start = args.recoveryStart; + auto progress = ConsoleProgress{std::cout}; + const auto sigintHandler = SigintHandler{progress.state}; passwords = recoverPassword(keysvec.front(), charset, minLength, maxLength, start, args.jobs, args.exhaustive, progress); return {progress.state, start}; @@ -306,7 +305,7 @@ try const auto fillBefore = std::cout.fill('0'); std::cout << "You may resume the password recovery with the option: --continue-recovery "; - for (byte c : restart) + for (const auto c : restart) std::cout << std::setw(2) << static_cast(c); std::cout << std::endl; @@ -331,7 +330,7 @@ try for (const auto& password : passwords) { std::cout << "as bytes: "; - for (byte c : password) + for (const auto c : password) std::cout << std::setw(2) << static_cast(c) << ' '; std::cout << std::endl; std::cout << "as text: " << password << std::endl; @@ -359,7 +358,7 @@ catch (const BaseError& e) namespace { -std::string getEncryptionDescription(Zip::Encryption encryption) +auto getEncryptionDescription(Zip::Encryption encryption) -> std::string { switch (encryption) { @@ -375,7 +374,7 @@ std::string getEncryptionDescription(Zip::Encryption encryption) return ""; } -std::string getCompressionDescription(Zip::Compression compression) +auto getCompressionDescription(Zip::Compression compression) -> std::string { switch (compression) { @@ -403,7 +402,7 @@ std::string getCompressionDescription(Zip::Compression compression) void listEntries(const std::string& archiveFilename) { - auto archive = Zip{archiveFilename}; + const auto archive = Zip{archiveFilename}; std::cout << "Archive: " << archiveFilename << "\n" << "Index Encryption Compression CRC32 Uncompressed Packed size Name\n" @@ -413,7 +412,7 @@ void listEntries(const std::string& archiveFilename) std::cout.setf(std::ios::right | std::ios::dec, std::ios::adjustfield | std::ios::basefield); const auto fillBefore = std::cout.fill(' '); - std::size_t index = 0; + auto index = std::size_t{}; for (const auto& entry : archive) { // clang-format off @@ -440,16 +439,16 @@ void listEntries(const std::string& archiveFilename) void decipher(std::istream& is, std::size_t size, std::size_t discard, std::ostream& os, Keys keys) { - std::istreambuf_iterator cipher(is); - std::size_t i; + auto cipher = std::istreambuf_iterator{is}; + auto i = std::size_t{}; - for (i = 0; i < discard && i < size && cipher != std::istreambuf_iterator(); i++, ++cipher) + for (; i < discard && i < size && cipher != std::istreambuf_iterator{}; i++, ++cipher) keys.update(*cipher ^ keys.getK()); - for (std::ostreambuf_iterator plain(os); i < size && cipher != std::istreambuf_iterator(); + for (auto plain = std::ostreambuf_iterator{os}; i < size && cipher != std::istreambuf_iterator{}; i++, ++cipher, ++plain) { - byte p = *cipher ^ keys.getK(); + const auto p = *cipher ^ keys.getK(); keys.update(p); *plain = p; } diff --git a/src/password.cpp b/src/password.cpp index 54236a4..a9dd643 100644 --- a/src/password.cpp +++ b/src/password.cpp @@ -8,13 +8,13 @@ #include #include -Recovery::Recovery(const Keys& keys, const bytevec& charset, std::vector& solutions, +Recovery::Recovery(const Keys& keys, const std::vector& charset, std::vector& solutions, std::mutex& solutionsMutex, bool exhaustive, Progress& progress) -: charset(charset) -, solutions(solutions) -, solutionsMutex(solutionsMutex) -, exhaustive(exhaustive) -, progress(progress) +: charset{charset} +, solutions{solutions} +, solutionsMutex{solutionsMutex} +, exhaustive{exhaustive} +, progress{progress} { // initialize target X, Y and Z values x[6] = keys.getX(); @@ -22,23 +22,23 @@ Recovery::Recovery(const Keys& keys, const bytevec& charset, std::vectorx0 = x0; - y[0] = y0; - z[0] = z0; + x[0] = candidateX0 = x0; + y[0] = y0; + z[0] = z0; // complete Z values and derive Y[24,32) values y[1] = Crc32Tab::getYi_24_32(z[1], z[1 - 1]); @@ -126,7 +126,7 @@ void Recovery::recoverLongPassword(const Keys& initial) { prefix.push_back(charset[0]); - for (byte pi : charset) + for (const auto pi : charset) { Keys init = initial; init.update(pi); @@ -144,17 +144,17 @@ void Recovery::recursion(int i) { if (i != 1) // the Y-list is not complete so generate Y{i-1} values { - uint32 fy = (y[i] - 1) * MultTab::MULTINV; - uint32 ffy = (fy - 1) * MultTab::MULTINV; + const auto fy = (y[i] - 1) * MultTab::multInv; + const auto ffy = (fy - 1) * MultTab::multInv; // get possible LSB(Xi) - for (byte xi_0_8 : MultTab::getMsbProdFiber2(msb(ffy - (y[i - 2] & MASK_24_32)))) + for (const auto xi_0_8 : MultTab::getMsbProdFiber2(msb(ffy - (y[i - 2] & mask<24, 32>)))) { // compute corresponding Y{i-1} - uint32 yim1 = fy - xi_0_8; + const auto yim1 = fy - xi_0_8; // filter values with Y{i-2}[24,32) - if (ffy - MultTab::getMultinv(xi_0_8) - (y[i - 2] & MASK_24_32) <= MAXDIFF_0_24 && + if (ffy - MultTab::getMultinv(xi_0_8) - (y[i - 2] & mask<24, 32>) <= maxdiff<24> && msb(yim1) == msb(y[i - 1])) { // add Y{i-1} to the Y-list @@ -170,27 +170,29 @@ void Recovery::recursion(int i) else // the Y-list is complete { // only the X1 LSB was not set yet, so do it here - x[1] = (y[1] - 1) * MultTab::MULTINV - y[0]; + x[1] = (y[1] - 1) * MultTab::multInv - y[0]; if (x[1] > 0xff) return; // complete X values and derive password - for (int i = 5; 0 <= i; i--) + for (auto j = 5; 0 <= j; j--) { - uint32 xi_xor_pi = Crc32Tab::crc32inv(x[i + 1], 0); - p[i] = lsb(xi_xor_pi ^ x[i]); - x[i] = xi_xor_pi ^ p[i]; + const auto xi_xor_pi = Crc32Tab::crc32inv(x[j + 1], 0); + p[j] = lsb(xi_xor_pi ^ x[j]); + x[j] = xi_xor_pi ^ p[j]; } - if (x[0] == x0) // the password is successfully recovered + if (x[0] == candidateX0) // the password is successfully recovered { - std::string password = std::string(prefix.begin(), prefix.end()); + auto password = prefix; password.append(p.begin(), p.end()); password.erase(password.begin(), password.end() - length); - const bool isInCharset = + const auto isInCharset = std::all_of(password.begin(), password.end(), - [this](unsigned char c) { return std::binary_search(charset.begin(), charset.end(), c); }); + [this](char c) { + return std::binary_search(charset.begin(), charset.end(), static_cast(c)); + }); if (!isInCharset) { @@ -201,7 +203,7 @@ void Recovery::recursion(int i) const auto fillBefore = os.fill('0'); os << "Password: " << password << " (as bytes:"; - for (byte c : password) + for (const auto c : password) os << ' ' << std::setw(2) << static_cast(c); os << ')' << std::endl; @@ -233,9 +235,9 @@ namespace void recoverPasswordRecursive(Recovery& worker, int jobs, const Keys& initial, const std::string& start, std::string& restart, Progress& progress) { - const int charsetSize = worker.charset.size(); + const auto charsetSize = static_cast(worker.charset.size()); - int index_start = 0; + auto index_start = 0; if (worker.prefix.size() < start.size()) while (index_start < charsetSize && worker.charset[index_start] < static_cast(start[worker.prefix.size()])) @@ -256,9 +258,9 @@ void recoverPasswordRecursive(Recovery& worker, int jobs, const Keys& initial, c { for (auto i = nextCandidateIndex++; i < charsetSize; i = nextCandidateIndex++) { - byte pm4 = worker.charset[i]; + const auto pm4 = worker.charset[i]; - Keys init = initial; + auto init = initial; init.update(pm4); worker.prefix.back() = pm4; @@ -297,8 +299,8 @@ void recoverPasswordRecursive(Recovery& worker, int jobs, const Keys& initial, c worker.prefix.push_back(worker.charset[0]); worker.prefix.push_back(worker.charset[0]); - const bool reportProgress = worker.prefix.size() == 2; - const bool reportProgressCoarse = worker.prefix.size() == 3; + const auto reportProgress = worker.prefix.size() == 2; + const auto reportProgressCoarse = worker.prefix.size() == 3; if (reportProgress) progress.done += index_start; @@ -315,10 +317,10 @@ void recoverPasswordRecursive(Recovery& worker, int jobs, const Keys& initial, c { for (auto i = nextCandidateIndex++; i < charsetSize * charsetSize; i = nextCandidateIndex++) { - byte pm4 = worker.charset[i / charsetSize]; - byte pm3 = worker.charset[i % charsetSize]; + const auto pm4 = worker.charset[i / charsetSize]; + const auto pm3 = worker.charset[i % charsetSize]; - Keys init = initial; + auto init = initial; init.update(pm4); init.update(pm3); @@ -352,18 +354,18 @@ void recoverPasswordRecursive(Recovery& worker, int jobs, const Keys& initial, c { worker.prefix.push_back(worker.charset[0]); - const bool reportProgress = worker.prefix.size() == 2; + const auto reportProgress = worker.prefix.size() == 2; if (worker.prefix.size() == 1) progress.done += index_start * charsetSize; else if (reportProgress) progress.done += index_start; - for (int i = index_start; i < charsetSize; i++) + for (auto i = index_start; i < charsetSize; i++) { - byte pi = worker.charset[i]; + const auto pi = worker.charset[i]; - Keys init = initial; + auto init = initial; init.update(pi); worker.prefix.back() = pi; @@ -386,17 +388,17 @@ void recoverPasswordRecursive(Recovery& worker, int jobs, const Keys& initial, c } // namespace -std::vector recoverPassword(const Keys& keys, const bytevec& charset, std::size_t minLength, - std::size_t maxLength, std::string& start, int jobs, bool exhaustive, - Progress& progress) +auto recoverPassword(const Keys& keys, const std::vector& charset, std::size_t minLength, + std::size_t maxLength, std::string& start, int jobs, bool exhaustive, Progress& progress) + -> std::vector { - std::vector solutions; - std::mutex solutionsMutex; - Recovery worker(keys, charset, solutions, solutionsMutex, exhaustive, progress); + auto solutions = std::vector{}; + auto solutionsMutex = std::mutex{}; + auto worker = Recovery{keys, charset, solutions, solutionsMutex, exhaustive, progress}; - std::string restart; - const std::size_t startLength = std::max(minLength, start.empty() ? 0 : start.size() + 6); - for (std::size_t length = startLength; length <= maxLength; length++) + auto restart = std::string{}; + const auto startLength = std::max(minLength, start.empty() ? 0 : start.size() + 6); + for (auto length = startLength; length <= maxLength; length++) { if (progress.state != Progress::State::Normal) break; @@ -405,10 +407,10 @@ std::vector recoverPassword(const Keys& keys, const bytevec& charse { progress.log([](std::ostream& os) { os << "length 0-6..." << std::endl; }); - Keys initial; + auto initial = Keys{}; // look for a password of length between 0 and 6 - for (int l = 6; l >= 0; l--) + for (auto l = 6; l >= 0; l--) { worker.length = l; worker.recoverShortPassword(initial); diff --git a/src/types.cpp b/src/types.cpp index d0476f5..6c30b4e 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1,6 +1,6 @@ #include "types.hpp" BaseError::BaseError(const std::string& type, const std::string& description) -: std::runtime_error(type + ": " + description + ".") +: std::runtime_error{type + ": " + description + "."} { }