-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
351 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
//---------------------------------------------------------------------------// | ||
// Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation> | ||
// | ||
// 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_IDEA_FUNCTIONS_HPP | ||
#define CRYPTO3_IDEA_FUNCTIONS_HPP | ||
|
||
#include <nil/crypto3/detail/basic_functions.hpp> | ||
#include <nil/crypto3/block/detail/utilities/constant_time_utilities.hpp> | ||
|
||
namespace nil { | ||
namespace crypto3 { | ||
namespace block { | ||
namespace detail { | ||
template<std::size_t WordBits> | ||
struct idea_functions : public ::nil::crypto3::detail::basic_functions<WordBits> { | ||
typedef typename ::nil::crypto3::detail::basic_functions<WordBits>::word_type word_type; | ||
|
||
/* | ||
* Multiplication modulo 65537 | ||
*/ | ||
static inline word_type mul(word_type x, word_type y) { | ||
const uint32_t P = static_cast<uint32_t>(x) * y; | ||
|
||
const word_type Z_mask = static_cast<uint16_t>(crypto3::detail::expand_mask(P) & 0xFFFF); | ||
|
||
const uint32_t P_hi = P >> 16; | ||
const uint32_t P_lo = P & 0xFFFF; | ||
|
||
const word_type carry = (P_lo < P_hi); | ||
const word_type r_1 = static_cast<uint16_t>((P_lo - P_hi) + carry); | ||
const word_type r_2 = 1 - x - y; | ||
|
||
return crypto3::detail::select(Z_mask, r_1, r_2); | ||
} | ||
|
||
/* | ||
* Find multiplicative inverses modulo 65537 | ||
* | ||
* 65537 is prime; thus Fermat's little theorem tells us that | ||
* x^65537 == x modulo 65537, which means | ||
* x^(65537-2) == x^-1 modulo 65537 since | ||
* x^(65537-2) * x == 1 mod 65537 | ||
* | ||
* Do the exponentiation with a basic square and multiply: all bits are | ||
* of exponent are 1 so we always multiply | ||
*/ | ||
static inline word_type mul_inv(word_type x) { | ||
word_type y = x; | ||
|
||
for (size_t i = 0; i != 15; ++i) { | ||
y = mul(y, y); // square | ||
y = mul(y, x); | ||
} | ||
|
||
return y; | ||
} | ||
}; | ||
} // namespace detail | ||
} // namespace block | ||
} // namespace crypto3 | ||
} // namespace nil | ||
|
||
#endif // CRYPTO3_IDEA_FUNCTIONS_CPP_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
//---------------------------------------------------------------------------// | ||
// Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation> | ||
// | ||
// 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_IDEA_POLICY_HPP | ||
#define CRYPTO3_IDEA_POLICY_HPP | ||
|
||
#include <array> | ||
|
||
#include <nil/crypto3/block/detail/idea/idea_functions.hpp> | ||
|
||
namespace nil { | ||
namespace crypto3 { | ||
namespace block { | ||
namespace detail { | ||
struct idea_policy : idea_functions<16> { | ||
constexpr static const std::size_t rounds = 8; | ||
|
||
constexpr static const std::size_t block_bits = 64; | ||
constexpr static const std::size_t block_words = block_bits / word_bits; | ||
typedef std::array<word_type, block_words> 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<word_type, key_words> key_type; | ||
|
||
constexpr static const std::size_t key_schedule_size = 52; | ||
typedef std::array<word_type, key_schedule_size> key_schedule_type; | ||
}; | ||
} // namespace detail | ||
} // namespace block | ||
} // namespace crypto3 | ||
} // namespace nil | ||
|
||
#endif // CRYPTO3_IDEA_POLICY_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
//---------------------------------------------------------------------------// | ||
// Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation> | ||
// Copyright (c) 2020 Nikita Kaskov <nbering@nil.foundation> | ||
// | ||
// 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_IDEA_HPP | ||
#define CRYPTO3_BLOCK_IDEA_HPP | ||
|
||
#include <boost/endian/arithmetic.hpp> | ||
#include <boost/endian/conversion.hpp> | ||
|
||
#include <nil/crypto3/block/detail/idea/idea_policy.hpp> | ||
|
||
#include <nil/crypto3/block/detail/block_stream_processor.hpp> | ||
#include <nil/crypto3/block/detail/cipher_modes.hpp> | ||
|
||
namespace nil { | ||
namespace crypto3 { | ||
namespace block { | ||
/*! | ||
* @brief Idea. An older but still unbroken 64-bit cipher with a | ||
* 128-bit key. Somewhat common due to its use in PGP. Avoid in new | ||
* designs. | ||
* | ||
* @ingroup block | ||
*/ | ||
class idea { | ||
protected: | ||
typedef detail::idea_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<class Mode, typename StateAccumulator, std::size_t ValueBits> | ||
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<Mode, StateAccumulator, params_type> type; | ||
}; | ||
|
||
typedef typename stream_endian::little_octet_big_bit endian_type; | ||
|
||
idea(const key_type &key) { | ||
schedule_key(key); | ||
} | ||
|
||
~idea() { | ||
encryption_key.fill(0); | ||
decryption_key.fill(0); | ||
} | ||
|
||
inline block_type encrypt(const block_type &plaintext) const { | ||
return idea_op(plaintext, encryption_key); | ||
} | ||
|
||
inline block_type decrypt(const block_type &ciphertext) const { | ||
return idea_op(ciphertext, decryption_key); | ||
} | ||
|
||
protected: | ||
key_schedule_type encryption_key, decryption_key; | ||
|
||
static inline block_type idea_op(const block_type &input, const key_schedule_type &key) { | ||
block_type out = {0}; | ||
word_type X1 = boost::endian::native_to_big(input[0]); | ||
word_type X2 = boost::endian::native_to_big(input[1]); | ||
word_type X3 = boost::endian::native_to_big(input[2]); | ||
word_type X4 = boost::endian::native_to_big(input[3]); | ||
|
||
for (size_t j = 0; j != policy_type::rounds; ++j) { | ||
X1 = policy_type::mul(X1, key[6 * j + 0]); | ||
X2 += key[6 * j + 1]; | ||
X3 += key[6 * j + 2]; | ||
X4 = policy_type::mul(X4, key[6 * j + 3]); | ||
|
||
word_type T0 = X3; | ||
X3 = policy_type::mul(X3 ^ X1, key[6 * j + 4]); | ||
|
||
word_type T1 = X2; | ||
X2 = policy_type::mul((X2 ^ X4) + X3, key[6 * j + 5]); | ||
X3 += X2; | ||
|
||
X1 ^= X2; | ||
X4 ^= X3; | ||
X2 ^= T0; | ||
X3 ^= T1; | ||
} | ||
|
||
X1 = policy_type::mul(X1, key[48]); | ||
X2 += key[50]; | ||
X3 += key[49]; | ||
X4 = policy_type::mul(X4, key[51]); | ||
|
||
return {boost::endian::big_to_native(X1), boost::endian::big_to_native(X2), | ||
boost::endian::big_to_native(X3), boost::endian::big_to_native(X4)}; | ||
} | ||
|
||
inline void schedule_key(const key_type &key) { | ||
crypto3::detail::poison(key.data(), 16); | ||
crypto3::detail::poison(encryption_key.data(), key_schedule_size); | ||
crypto3::detail::poison(decryption_key.data(), key_schedule_size); | ||
|
||
std::array<uint64_t, 2> K = {0}; | ||
|
||
K[0] = boost::endian::native_to_big(key[0]); | ||
K[1] = boost::endian::native_to_big(key[1]); | ||
|
||
for (size_t off = 0; off != 48; off += 8) { | ||
for (size_t i = 0; i != 8; ++i) { | ||
encryption_key[off + i] = K[i / 4] >> (48 - 16 * (i % 4)); | ||
} | ||
|
||
const uint64_t Kx = (K[0] >> 39); | ||
const uint64_t Ky = (K[1] >> 39); | ||
|
||
K[0] = (K[0] << 25) | Ky; | ||
K[1] = (K[1] << 25) | Kx; | ||
} | ||
|
||
for (size_t i = 0; i != 4; ++i) { | ||
encryption_key[48 + i] = K[i / 4] >> (48 - 16 * (i % 4)); | ||
} | ||
|
||
K.fill(0); | ||
|
||
decryption_key[0] = policy_type::mul_inv(encryption_key[48]); | ||
decryption_key[1] = -encryption_key[49]; | ||
decryption_key[2] = -encryption_key[50]; | ||
decryption_key[3] = policy_type::mul_inv(encryption_key[51]); | ||
|
||
for (size_t i = 0; i != 8 * 6; i += 6) { | ||
decryption_key[i + 4] = encryption_key[46 - i]; | ||
decryption_key[i + 5] = encryption_key[47 - i]; | ||
decryption_key[i + 6] = policy_type::mul_inv(encryption_key[42 - i]); | ||
decryption_key[i + 7] = -encryption_key[44 - i]; | ||
decryption_key[i + 8] = -encryption_key[43 - i]; | ||
decryption_key[i + 9] = policy_type::mul_inv(encryption_key[45 - i]); | ||
} | ||
|
||
std::swap(decryption_key[49], decryption_key[50]); | ||
|
||
crypto3::detail::unpoison(key.data(), 16); | ||
crypto3::detail::unpoison(encryption_key.data(), 52); | ||
crypto3::detail::unpoison(decryption_key.data(), 52); | ||
} | ||
}; | ||
} // namespace block | ||
} // namespace crypto3 | ||
} // namespace nil | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ endmacro() | |
set(TESTS_NAMES | ||
"pack" | ||
"rijndael" | ||
"idea" | ||
"md4" | ||
"md5" | ||
"shacal" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
//---------------------------------------------------------------------------// | ||
// Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation> | ||
// | ||
// 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 idea_cipher_test | ||
|
||
#include <iostream> | ||
#include <unordered_map> | ||
|
||
#include <boost/test/unit_test.hpp> | ||
#include <boost/test/data/test_case.hpp> | ||
#include <boost/test/data/monomorphic.hpp> | ||
|
||
#include <nil/crypto3/block/algorithm/encrypt.hpp> | ||
#include <nil/crypto3/block/algorithm/decrypt.hpp> | ||
|
||
#include <nil/crypto3/block/idea.hpp> | ||
|
||
using namespace nil::crypto3::block; | ||
|
||
namespace boost { | ||
namespace test_tools { | ||
namespace tt_detail { | ||
template<template<typename, typename> class P, typename K, typename V> | ||
struct print_log_value<P<K, V>> { | ||
void operator()(std::ostream&, P<K, V> const&) { | ||
} | ||
}; | ||
} // namespace tt_detail | ||
} // namespace test_tools | ||
} // namespace boost | ||
|
||
static const std::unordered_map<std::string, std::vector<uint8_t>> 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<std::string> invalid_data = {"ZOOL!isnotvalidbase64", "Neitheris:this?"}; | ||
|
||
BOOST_AUTO_TEST_SUITE(idea_encode_test_suite) | ||
|
||
BOOST_DATA_TEST_CASE(idea_single_range_encode, boost::unit_test::data::make(valid_data), array_element) { | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() |