diff --git a/Chaos/Cipher/Des/DesCrypt.hpp b/Chaos/Cipher/Des/DesCrypt.hpp index 6e6584b..a6881c3 100644 --- a/Chaos/Cipher/Des/DesCrypt.hpp +++ b/Chaos/Cipher/Des/DesCrypt.hpp @@ -1,6 +1,7 @@ #ifndef CHAOS_CIPHER_DES_DESCRYPT_HPP #define CHAOS_CIPHER_DES_DESCRYPT_HPP +#include #include #include "Service/ChaosException.hpp" @@ -98,7 +99,13 @@ public: using RoundKey48 = uint64_t; - KeySchedule(const RawKey & rawKey) + enum class Direction + { + Encrypt, + Decrypt + }; + + KeySchedule(Direction direction, const RawKey & rawKey) { Key56 key56 = Pc1(Bitwise::PackUInt64(rawKey.Begin(), rawKey.End())); @@ -119,6 +126,11 @@ public: Schedule_[i] = Pc2(Bitwise::Merge<28>(c28, d28)); } + + if (direction == Direction::Decrypt) + { + std::reverse(Schedule_.Begin(), Schedule_.End()); + } } RoundKey48 operator[](int_fast8_t i) const @@ -211,7 +223,7 @@ public: { public: Encryptor(const Key & key) - : Schedule_(key.Key_) + : Schedule_(Inner_::KeySchedule::Direction::Encrypt, key.Key_) { } template @@ -226,7 +238,7 @@ public: } Block encrypted - = DesCrypt::EncryptBlock(Inner_::Bitwise::PackUInt64(block.Begin(), + = DesCrypt::ProcessBlock(Inner_::Bitwise::PackUInt64(block.Begin(), block.End()), Schedule_); @@ -237,6 +249,36 @@ public: Inner_::KeySchedule Schedule_; }; + class Decryptor + { + public: + Decryptor(const Key & key) + : Schedule_(Inner_::KeySchedule::Direction::Decrypt, key.Key_) + { } + + template + void DecryptBlock(OutputIt out, InputIt inBegin, InputIt inEnd) + { + RawBlockArray block; + + int_fast8_t i = 0; + for (InputIt in = inBegin; i < block.Size() && in != inEnd; ++i, ++in) + { + block[i] = *in; + } + + Block decrypted + = DesCrypt::ProcessBlock(Inner_::Bitwise::PackUInt64(block.Begin(), + block.End()), + Schedule_); + + Inner_::Bitwise::CrunchUInt64(out, decrypted); + } + + private: + Inner_::KeySchedule Schedule_; + }; + private: using Block = uint64_t; using BlockHalf = uint32_t; @@ -405,7 +447,7 @@ private: FP_TABLE + std::size(FP_TABLE)); } - static Block EncryptBlock(Block block, const Inner_::KeySchedule & schedule) + static Block ProcessBlock(Block block, const Inner_::KeySchedule & schedule) { block = Ip(block); diff --git a/ChaosTests/Cipher/DesCryptTests.cpp b/ChaosTests/Cipher/DesCryptTests.cpp index d5c6b61..21f1d17 100644 --- a/ChaosTests/Cipher/DesCryptTests.cpp +++ b/ChaosTests/Cipher/DesCryptTests.cpp @@ -17,7 +17,7 @@ TEST(DesCryptTests, KeyScheduleTest) key[6] = 0b11011111; key[7] = 0b11110001; - Inner_::KeySchedule schedule(key); + Inner_::KeySchedule schedule(Inner_::KeySchedule::Direction::Encrypt, key); ASSERT_EQ(0b000110110000001011101111111111000111000001110010ULL, schedule[0]); ASSERT_EQ(0b011110011010111011011001110110111100100111100101ULL, schedule[1]); @@ -153,6 +153,122 @@ TEST(DesCryptTests, EncryptLongDataTest) } } +TEST(DesCryptTests, DecryptTest) +{ + struct Helper + { + std::array operator()(const std::array & data, + const std::array & key) const + { + std::array result; + result.fill(0); + + DesCrypt::Key desKey(key.begin(), key.end()); + DesCrypt::Decryptor dec(desKey); + dec.DecryptBlock(result.begin(), data.begin(), data.end()); + + return result; + } + }; + + Helper des; + + { + std::array data = { 0x85, 0xe8, 0x13, 0x54, 0x0f, 0x0a, 0xb4, 0x05 }; + std::array key = { 0x13, 0x34, 0x57, 0x79, 0x9b, 0xbc, 0xdf, 0xf1 }; + + std::array expected = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + + ASSERT_EQ(expected, des(data, key)); + } + + { + std::array data = { 0x07, 0xe8, 0x7f, 0xaa, 0xb3, 0x17, 0x13, 0x18 }; + std::array key = { 0x44, 0xbf, 0x32, 0x19, 0x99, 0x25, 0x81, 0x51 }; + + std::array expected = { 0xaa, 0xf3, 0x83, 0x16, 0x2d, 0x2e, 0x6b, 0xcb }; + + ASSERT_EQ(expected, des(data, key)); + } + + { + std::array data = { 0x42, 0x27, 0x88, 0xa6, 0x7b, 0x6c, 0x18, 0xed }; + std::array key = { 0xda, 0xec, 0x68, 0xae, 0x83, 0xe0, 0x1e, 0xab }; + + std::array expected = { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0xa7, 0x93, 0x44 }; + + ASSERT_EQ(expected, des(data, key)); + } +} + +TEST(DesCryptTests, DecryptShortDataTest) +{ + struct Helper + { + std::vector operator()(const std::vector & data, + const std::vector & key) + { + std::vector result; + result.resize(8, 0); + + DesCrypt::Key desKey(key.begin(), key.end()); + DesCrypt::Decryptor dec(desKey); + dec.DecryptBlock(result.begin(), data.begin(), data.end()); + + return result; + } + }; + + Helper des; + + { + // treated as { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0x00, 0x00, 0x00 } + std::vector dataShort = { 0xe5, 0x1a, 0x9f, 0xd4, 0x19 }; + + std::vector data = { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0x00, 0x00, 0x00 }; + std::vector key = { 0xda, 0xec, 0x68, 0xae, 0x83, 0xe0, 0x1e, 0xab }; + + std::vector expected = { 0x90, 0xe5, 0xf6, 0x5b, 0xe1, 0xd3, 0x8a, 0x64 }; + + ASSERT_EQ(expected, des(data, key)); + ASSERT_EQ(expected, des(dataShort, key)); + } +} + +TEST(DesCryptTests, DecryptLongDataTest) +{ + struct Helper + { + std::vector operator()(const std::vector & data, + const std::vector & key) + { + std::vector result; + result.resize(8, 0); + + DesCrypt::Key desKey(key.begin(), key.end()); + DesCrypt::Decryptor dec(desKey); + dec.DecryptBlock(result.begin(), data.begin(), data.end()); + + return result; + } + }; + + Helper des; + + { + // treated as { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0xa7, 0x93, 0x44 } + std::vector dataLong = { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0xa7, 0x93, 0x44, 0xaa, 0xbb }; + + std::vector data = { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0xa7, 0x93, 0x44 }; + std::vector key = { 0xda, 0xec, 0x68, 0xae, 0x83, 0xe0, 0x1e, 0xab }; + + std::vector expected = { 0x45, 0x69, 0x71, 0x17, 0x13, 0xfb, 0x3e, 0xee }; + + ASSERT_EQ(expected, des(data, key)); + ASSERT_EQ(expected, des(dataLong, key)); + } +} + TEST(DesCryptTests, ShortKeyTest) { { @@ -169,7 +285,7 @@ TEST(DesCryptTests, LongKeyTest) } } -TEST(DesCryptTests, OutIteratorUsageTest) +TEST(DesCryptTests, OutIteratorUsageEncryptTest) { struct OutputItMock { @@ -229,3 +345,64 @@ TEST(DesCryptTests, OutIteratorUsageTest) ASSERT_EQ(8, incrementCalls); } } + +TEST(DesCryptTests, OutIteratorUsageDecryptTest) +{ + struct OutputItMock + { + OutputItMock(size_t & asteriskCalls, size_t & incrementCalls) + : AsteriskCalls_(asteriskCalls) + , IncrementCalls_(incrementCalls) + { } + + uint8_t & operator*() + { + ++AsteriskCalls_; + + static uint8_t dummy = 0; + return dummy; + } + + OutputItMock operator++(int) + { + ++IncrementCalls_; + + return *this; + } + + size_t & AsteriskCalls_; + size_t & IncrementCalls_; + }; + + { + std::array data = { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0xa7, 0x93, 0x44 }; + std::array key = { 0xda, 0xec, 0x68, 0xae, 0x83, 0xe0, 0x1e, 0xab }; + + size_t asteriskCalls = 0; + size_t incrementCalls = 0; + OutputItMock it(asteriskCalls, incrementCalls); + + DesCrypt::Key desKey(key.begin(), key.end()); + DesCrypt::Decryptor dec(desKey); + dec.DecryptBlock(it, data.begin(), data.end()); + + ASSERT_EQ(8, asteriskCalls); + ASSERT_EQ(8, incrementCalls); + } + + { + std::array data = { 0xe5, 0x1a, 0x9f, 0xd4, 0x19, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f }; + std::array key = { 0xda, 0xec, 0x68, 0xae, 0x83, 0xe0, 0x1e, 0xab }; + + size_t asteriskCalls = 0; + size_t incrementCalls = 0; + OutputItMock it(asteriskCalls, incrementCalls); + + DesCrypt::Key desKey(key.begin(), key.end()); + DesCrypt::Decryptor dec(desKey); + dec.DecryptBlock(it, data.begin(), data.end()); + + ASSERT_EQ(8, asteriskCalls); + ASSERT_EQ(8, incrementCalls); + } +}