#pragma once #ifndef MESSMER_CPPUTILS_TEST_CRYPTO_SYMMETRIC_TESTUTILS_FAKEAUTHENTICATEDCIPHER_H_ #define MESSMER_CPPUTILS_TEST_CRYPTO_SYMMETRIC_TESTUTILS_FAKEAUTHENTICATEDCIPHER_H_ #include "cpp-utils/crypto/cryptopp_byte.h" #include "cpp-utils/crypto/symmetric/Cipher.h" #include "cpp-utils/data/FixedSizeData.h" #include "cpp-utils/data/Data.h" #include "cpp-utils/random/RandomGenerator.h" namespace cpputils { struct FakeKey { static FakeKey FromBinary(const void *data) { return FakeKey{*(uint8_t *) data}; } static constexpr unsigned int BINARY_LENGTH = 1; uint8_t value; }; // This is a fake cipher that uses an indeterministic caesar chiffre and a 4-byte parity for a simple authentication mechanism class FakeAuthenticatedCipher { public: BOOST_CONCEPT_ASSERT((CipherConcept)); using EncryptionKey = FakeKey; static EncryptionKey CreateKey(RandomGenerator &randomGenerator) { auto data = randomGenerator.getFixedSize<1>(); return FakeKey{*((uint8_t *) data.data())}; } static EncryptionKey Key1() { return FakeKey{5}; } static EncryptionKey Key2() { return FakeKey{63}; } static constexpr unsigned int ciphertextSize(unsigned int plaintextBlockSize) { return plaintextBlockSize + 5; } static constexpr unsigned int plaintextSize(unsigned int ciphertextBlockSize) { return ciphertextBlockSize - 5; } static Data encrypt(const CryptoPP::byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey) { Data result(ciphertextSize(plaintextSize)); //Add a random IV uint8_t iv = rand(); std::memcpy(result.data(), &iv, 1); //Use caesar chiffre on plaintext _caesar((CryptoPP::byte *) result.data() + 1, plaintext, plaintextSize, encKey.value + iv); //Add parity information int32_t parity = _parity((CryptoPP::byte *) result.data(), plaintextSize + 1); std::memcpy((CryptoPP::byte *) result.data() + plaintextSize + 1, &parity, 4); return result; } static boost::optional decrypt(const CryptoPP::byte *ciphertext, unsigned int ciphertextSize, const EncryptionKey &encKey) { //We need at least 5 bytes (iv + parity) if (ciphertextSize < 5) { return boost::none; } //Check parity int32_t expectedParity = _parity(ciphertext, plaintextSize(ciphertextSize) + 1); int32_t actualParity = *(int32_t * )(ciphertext + plaintextSize(ciphertextSize) + 1); if (expectedParity != actualParity) { return boost::none; } //Decrypt caesar chiffre from ciphertext int32_t iv = *(int32_t *) ciphertext; Data result(plaintextSize(ciphertextSize)); _caesar((CryptoPP::byte *) result.data(), ciphertext + 1, plaintextSize(ciphertextSize), -(encKey.value + iv)); return std::move(result); } static constexpr const char *NAME = "FakeAuthenticatedCipher"; private: static int32_t _parity(const CryptoPP::byte *data, unsigned int size) { int32_t parity = 34343435; // some init value const int32_t *intData = reinterpret_cast(data); unsigned int intSize = size / sizeof(int32_t); for (unsigned int i = 0; i < intSize; ++i) { parity = ((int64_t)parity) + intData[i]; } unsigned int remainingBytes = size - 4 * intSize; for (unsigned int i = 0; i < remainingBytes; ++i) { parity = ((int64_t)parity) + (data[4 * intSize + i] << (24 - 8 * i)); } return parity; } static void _caesar(CryptoPP::byte *dst, const CryptoPP::byte *src, unsigned int size, uint8_t key) { for (unsigned int i = 0; i < size; ++i) { dst[i] = src[i] + key; } } }; } #endif