diff --git a/Chaos/Cipher/Arc4/Arc4Crypt.hpp b/Chaos/Cipher/Arc4/Arc4Crypt.hpp index 3b30d2d..6d0a637 100644 --- a/Chaos/Cipher/Arc4/Arc4Crypt.hpp +++ b/Chaos/Cipher/Arc4/Arc4Crypt.hpp @@ -2,6 +2,7 @@ #define CHAOS_CIPHER_ARC4CRYPT_HPP #include "Arc4Gen.hpp" +#include "Service/SeArray.hpp" #include "Service/ChaosException.hpp" namespace Chaos::Cipher::Arc4 @@ -29,13 +30,15 @@ public: template void Encrypt(OutputIt out, InputIt in, uint64_t count) { - // TODO: + EnsureInitialized(); + EncryptDecryptImpl(out, in, count); } template void Decrypt(OutputIt out, InputIt in, uint64_t count) { - // TODO: + EnsureInitialized(); + EncryptDecryptImpl(out, in, count); } private: @@ -56,6 +59,25 @@ private: Gen_.Rekey(keyBegin, keyEnd); IsInitialized_ = true; } + + template + void EncryptDecryptImpl(OutputIt out, InputIt in, uint64_t count) + { + Service::SeArray keyBuf; + + while (count > 0) + { + uint64_t keyMaterialBytes = std::min(keyBuf.Size(), count); + Gen_.Generate(keyBuf.Begin(), keyMaterialBytes); + + for (auto keyBufIt = keyBuf.Begin(); + keyMaterialBytes > 0 && count > 0; + ++keyBufIt, --keyMaterialBytes, --count) + { + *out++ = *in++ ^ *keyBufIt; + } + } + } }; } // namespace Chaos::Cipher::Arc4 diff --git a/ChaosTests/CMakeLists.txt b/ChaosTests/CMakeLists.txt index d484fc0..6ee8ee2 100644 --- a/ChaosTests/CMakeLists.txt +++ b/ChaosTests/CMakeLists.txt @@ -15,6 +15,7 @@ set(ChaosTests_SOURCE Hash/Md4HasherTests.cpp Hash/Md5HasherTests.cpp Mac/HmacTests.cpp Cipher/Arc4GenTests.cpp + Cipher/Arc4CryptTests.cpp Service/SeArrayTests.cpp) add_executable(ChaosTests ${ChaosTests_SOURCE}) diff --git a/ChaosTests/Cipher/Arc4CryptTests.cpp b/ChaosTests/Cipher/Arc4CryptTests.cpp new file mode 100644 index 0000000..9f98c6e --- /dev/null +++ b/ChaosTests/Cipher/Arc4CryptTests.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "Cipher/Arc4/Arc4Crypt.hpp" + +using namespace Chaos::Cipher::Arc4; + +static std::vector StrToU8Vec(const char * str) +{ + std::vector result; + result.reserve(strlen(str)); + + for (; *str != '\0'; ++str) + { + result.push_back(static_cast(*str)); + } + + return result; +} + +static std::string U8VecToStr(const std::vector & vec) +{ + std::string result; + result.reserve(vec.size()); + + for (auto it = vec.begin(); it != vec.end(); ++it) + { + result.push_back(static_cast(*it)); + } + + return result; +} + +TEST(Arc4CryptTests, BasicTest) +{ + const std::vector key = StrToU8Vec("Secret"); + const std::vector data = StrToU8Vec("Attack at dawn"); + + std::vector ciphertext; + ciphertext.resize(data.size()); + + { + Arc4Crypt arc4; + arc4.Rekey(key.begin(), key.end()); + + arc4.Encrypt(ciphertext.begin(), data.begin(), data.size()); + } + + ASSERT_EQ(std::vector({ 0x45, 0xA0, 0x1F, 0x64, 0x5F, 0xC3, 0x5B, + 0x38, 0x35, 0x52, 0x54, 0x4B, 0x9B, 0xF5 }), + ciphertext); + + std::vector recoveredData; + recoveredData.resize(data.size()); + + { + Arc4Crypt arc4; + arc4.Rekey(key.begin(), key.end()); + + arc4.Decrypt(recoveredData.begin(), ciphertext.begin(), ciphertext.size()); + } + + ASSERT_EQ(data, recoveredData); +}