diff --git a/include/nil/crypto3/block/detail/xtea/xtea_functions.hpp b/include/nil/crypto3/block/detail/xtea/xtea_functions.hpp new file mode 100644 index 0000000..29ac34a --- /dev/null +++ b/include/nil/crypto3/block/detail/xtea/xtea_functions.hpp @@ -0,0 +1,27 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_XTEA_FUNCTIONS_CPP_HPP +#define CRYPTO3_XTEA_FUNCTIONS_CPP_HPP + +#include + +namespace nil { + namespace crypto3 { + namespace block { + namespace detail { + template + struct xtea_functions : public ::nil::crypto3::detail::basic_functions { + typedef typename ::nil::crypto3::detail::basic_functions::word_type word_type; + }; + } // namespace detail + } // namespace block + } // namespace crypto3 +} // namespace nil + +#endif // CRYPTO3_MISTY1_FUNCTIONS_CPP_HPP diff --git a/include/nil/crypto3/block/detail/xtea/xtea_policy.hpp b/include/nil/crypto3/block/detail/xtea/xtea_policy.hpp new file mode 100644 index 0000000..5eb8b93 --- /dev/null +++ b/include/nil/crypto3/block/detail/xtea/xtea_policy.hpp @@ -0,0 +1,39 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_XTEA_POLICY_HPP +#define CRYPTO3_XTEA_POLICY_HPP + +#include + +#include + +namespace nil { + namespace crypto3 { + namespace block { + namespace detail { + struct xtea_policy : xtea_functions<32> { + constexpr static const std::size_t rounds = 32; + + constexpr static const std::size_t block_bits = 64; + constexpr static const std::size_t block_words = block_bits / word_bits; + typedef std::array block_type; + + constexpr static const std::size_t key_bits = 128; + constexpr static const std::size_t key_words = key_bits / word_bits; + typedef std::array key_type; + + constexpr static const std::size_t key_schedule_size = 64; + typedef std::array key_schedule_type; + }; + } // namespace detail + } // namespace block + } // namespace crypto3 +} // namespace nil + +#endif // CRYPTO3_MISTY1_POLICY_HPP diff --git a/include/nil/crypto3/block/xtea.hpp b/include/nil/crypto3/block/xtea.hpp new file mode 100644 index 0000000..64c2401 --- /dev/null +++ b/include/nil/crypto3/block/xtea.hpp @@ -0,0 +1,125 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// Copyright (c) 2020 Nikita Kaskov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLOCK_XTEA_HPP +#define CRYPTO3_BLOCK_XTEA_HPP + +#include +#include + +#include + +#include +#include + +namespace nil { + namespace crypto3 { + namespace block { + /*! + * @brief Xtea. A 64-bit cipher popular for its simple implementation. + * Avoid in new code. + * + * @ingroup block + */ + class xtea { + protected: + typedef detail::xtea_policy policy_type; + + constexpr static const std::size_t key_schedule_size = policy_type::key_schedule_size; + typedef typename policy_type::key_schedule_type key_schedule_type; + + public: + constexpr static const std::size_t rounds = policy_type::rounds; + + constexpr static const std::size_t word_bits = policy_type::word_bits; + typedef typename policy_type::word_type word_type; + + constexpr static const std::size_t block_bits = policy_type::block_bits; + constexpr static const std::size_t block_words = policy_type::block_words; + typedef typename policy_type::block_type block_type; + + constexpr static const std::size_t key_bits = policy_type::key_bits; + constexpr static const std::size_t key_words = policy_type::key_words; + typedef typename policy_type::key_type key_type; + + template + struct stream_processor { + struct params_type { + + constexpr static const std::size_t value_bits = ValueBits; + constexpr static const std::size_t length_bits = policy_type::word_bits * 2; + }; + + typedef block_stream_processor type; + }; + + typedef typename stream_endian::little_octet_big_bit endian_type; + + xtea(const key_type &key) { + schedule_key(key); + } + + ~xtea() { + key_schedule.fill(0); + } + + inline block_type encrypt(const block_type &plaintext) const { + return encrypt_block(plaintext); + } + + inline block_type decrypt(const block_type &ciphertext) const { + return decrypt_block(ciphertext); + } + + protected: + key_schedule_type key_schedule; + + inline block_type encrypt_block(const block_type &plaintext) const { + word_type L = boost::endian::native_to_big(plaintext[0]); + word_type R = boost::endian::native_to_big(plaintext[1]); + + for (size_t r = 0; r != rounds; ++r) { + L += (((R << 4) ^ (R >> 5)) + R) ^ key_schedule[2 * r]; + R += (((L << 4) ^ (L >> 5)) + L) ^ key_schedule[2 * r + 1]; + } + + return {boost::endian::big_to_native(L), boost::endian::big_to_native(R)}; + } + + inline block_type decrypt_block(const block_type &ciphertext) const { + word_type L = boost::endian::native_to_big(ciphertext[0]); + word_type R = boost::endian::native_to_big(ciphertext[1]); + + for (size_t r = 0; r != rounds; ++r) { + R -= (((L << 4) ^ (L >> 5)) + L) ^ key_schedule[63 - 2 * r]; + L -= (((R << 4) ^ (R >> 5)) + R) ^ key_schedule[62 - 2 * r]; + } + + return {boost::endian::big_to_native(L), boost::endian::big_to_native(R)}; + } + + inline void schedule_key(const key_type &key) { + std::array UK = {0}; + for (size_t i = 0; i != 4; ++i) { + UK[i] = boost::endian::native_to_big(key[i]); + } + + uint32_t D = 0; + for (size_t i = 0; i != key_schedule_size; i += 2) { + key_schedule[i] = D + UK[D % 4]; + D += 0x9E3779B9; + key_schedule[i + 1] = D + UK[(D >> 11) % 4]; + } + } + }; + } // namespace block + } // namespace crypto3 +} // namespace nil + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6e6c334..9ecf799 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -43,6 +43,7 @@ set(TESTS_NAMES "md5" "shacal" "shacal2" + "xtea" ) foreach(TEST_NAME ${TESTS_NAMES}) diff --git a/test/xtea.cpp b/test/xtea.cpp new file mode 100644 index 0000000..fff0b1b --- /dev/null +++ b/test/xtea.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE xtea_cipher_test + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +using namespace nil::crypto3::block; + +namespace boost { + namespace test_tools { + namespace tt_detail { + template class P, typename K, typename V> + struct print_log_value> { + void operator()(std::ostream&, P const&) { + } + }; + } // namespace tt_detail + } // namespace test_tools +} // namespace boost + +static const std::unordered_map> valid_data = { + {"Zg==", {0x66}}, + {"Zm8=", {0x66, 0x6F}}, + {"Zm9v", {0x66, 0x6F, 0x6F}}, + {"aGVsbG8gd29ybGQ=", {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64}}, + {"aGVsbG8gd29ybGQh", {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21}}, + {"SGVsbG8sIHdvcmxkLg==", {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x2E}}, + {"VGhlIDEyIGNoYXJz", {0x54, 0x68, 0x65, 0x20, 0x31, 0x32, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73}}, + {"VGhlIDEzIGNoYXJzLg==", {0x54, 0x68, 0x65, 0x20, 0x31, 0x33, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x2E}}, + {"VGhlIDE0IGNoYXJzLi4=", {0x54, 0x68, 0x65, 0x20, 0x31, 0x34, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x2E, 0x2E}}, + {"VGhlIDE1IGNoYXJzLi4u", + {0x54, 0x68, 0x65, 0x20, 0x31, 0x35, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x2E, 0x2E, 0x2E}}, + {"QW4gVVRGLTggdXVtbDogw7w=", + {0x41, 0x6E, 0x20, 0x55, 0x54, 0x46, 0x2D, 0x38, 0x20, 0x75, 0x75, 0x6D, 0x6C, 0x3A, 0x20, 0xC3, 0xBC}}, + {"V2VpcmQgR2VybWFuIDIgYnl0ZSB0aGluZzogw58u", + {0x57, 0x65, 0x69, 0x72, 0x64, 0x20, 0x47, 0x65, 0x72, 0x6D, 0x61, 0x6E, 0x20, 0x32, 0x20, + 0x62, 0x79, 0x74, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0xC3, 0x9F, 0x2E}}, + {"mw==", {0x9B}}, + {"HGA=", {0x1C, 0x60}}, + {"gTS9", {0x81, 0x34, 0xBD}}, + {"Xmz/3g==", {0x5E, 0x6C, 0xFF, 0xDE}}, + {"ss3w3H8=", {0xb2, 0xcd, 0xf0, 0xdc, 0x7f}}, + {"/FYt2tQO", {0xfc, 0x56, 0x2d, 0xda, 0xd4, 0x0e}}, + {"KbIyLohB6A==", {0x29, 0xb2, 0x32, 0x2e, 0x88, 0x41, 0xe8}}, + {"Dw/O2Ul6r5I=", {0x0f, 0x0f, 0xce, 0xd9, 0x49, 0x7a, 0xaf, 0x92}}, + {"Jw+xiYKADaZA", {0x27, 0x0f, 0xb1, 0x89, 0x82, 0x80, 0x0d, 0xa6, 0x40}}}; + +static const std::vector invalid_data = {"ZOOL!isnotvalidbase64", "Neitheris:this?"}; + +BOOST_AUTO_TEST_SUITE(xtea_encode_test_suite) + +BOOST_DATA_TEST_CASE(xtea_single_range_encode, boost::unit_test::data::make(valid_data), array_element) { +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file