Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement GOST-28147-89 block cipher #49

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//---------------------------------------------------------------------------//
// 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_GOST_28147_89_FUNCTIONS_CPP_HPP
#define CRYPTO3_GOST_28147_89_FUNCTIONS_CPP_HPP

#include <nil/crypto3/detail/basic_functions.hpp>

namespace nil {
namespace crypto3 {
namespace block {
namespace detail {
template<std::size_t WordBits>
struct gost_28147_89_functions : public ::nil::crypto3::detail::basic_functions<WordBits> {
typedef typename ::nil::crypto3::detail::basic_functions<WordBits>::word_type word_type;
};
} // namespace detail
} // namespace block
} // namespace crypto3
} // namespace nil

#endif // CRYPTO3_GOST_28147_89_FUNCTIONS_CPP_HPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//---------------------------------------------------------------------------//
// 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_GOST_28147_89_PARAMETERS_HPP
#define CRYPTO3_GOST_28147_89_PARAMETERS_HPP

#include <array>

#include <boost/integer.hpp>

namespace nil {
namespace crypto3 {
namespace block {
namespace detail {
struct gost_28147_89_parameters {
typedef uint8_t byte_type;

constexpr static const std::size_t parameters_size = 64;
typedef std::array<byte_type, parameters_size> parameters_type;
};
} // namespace detail
} // namespace block
} // namespace crypto3
} // namespace nil

#endif // CRYPTO3_GOST_28147_89_POLICY_HPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//---------------------------------------------------------------------------//
// 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_GOST_28147_89_POLICY_HPP
#define CRYPTO3_GOST_28147_89_POLICY_HPP

#include <array>

#include <nil/crypto3/block/detail/gost_28147_89/gost_28147_89_functions.hpp>

namespace nil {
namespace crypto3 {
namespace block {
namespace detail {
/*
* Two rounds of GOST
*/
#define GOST_2ROUND(N1, N2, R1, R2) \
do { \
uint32_t T0 = N1 + key_schedule[R1]; \
N2 ^= expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T0, 3)] | \
expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T0, 2) + 256] | \
expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T0, 1) + 512] | \
expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T0, 0) + 768]; \
\
uint32_t T1 = N2 + key_schedule[R2]; \
N1 ^= expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T1, 3)] | \
expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T1, 2) + 256] | \
expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T1, 1) + 512] | \
expanded_substitution[policy_type::template extract_uint_t<CHAR_BIT>(T1, 0) + 768]; \
} while (0)

template<typename ParamsType>
struct gost_28147_89_policy : gost_28147_89_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<word_type, block_words> block_type;

constexpr static const std::size_t key_bits = 256;
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 = 8;
typedef std::array<word_type, key_schedule_size> key_schedule_type;

constexpr static const std::size_t expanded_substitution_size = 1024;
typedef std::array<byte_type, expanded_substitution_size> expanded_substitution_type;
};
} // namespace detail
} // namespace block
} // namespace crypto3
} // namespace nil

#endif // CRYPTO3_GOST_28147_89_POLICY_HPP
216 changes: 216 additions & 0 deletions include/nil/crypto3/block/gost_28147_89.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//---------------------------------------------------------------------------//
// 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_GOST_28147_89_HPP
#define CRYPTO3_BLOCK_GOST_28147_89_HPP

#include <boost/endian/arithmetic.hpp>
#include <boost/endian/conversion.hpp>

#include <nil/crypto3/block/detail/gost_28147_89/gost_28147_89_policy.hpp>
#include <nil/crypto3/block/detail/gost_28147_89/gost_28147_89_parameters.hpp>

#include <nil/crypto3/block/detail/cipher_modes.hpp>
#include <nil/crypto3/block/detail/block_stream_processor.hpp>

namespace nil {
namespace crypto3 {
namespace block {
struct crypto_pro_params : public detail::gost_28147_89_parameters {
private:
struct col_selector {
col_selector(std::size_t row) : row(row) {
}

byte_type operator[](std::size_t col) const {
const byte_type x = parameters[4 * (col % 16) + row];
const byte_type y = parameters[4 * (col / 16) + row];
return (x >> 4) | (y << 4);
}

private:
std::size_t row;
};

public:
col_selector operator[](std::size_t row) const {
return {row};
}

// GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1)
constexpr static const parameters_type parameters = {
0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42, 0x4A, 0x60, 0xEC, 0xB4, 0x19,
0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F, 0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF,
0xD1, 0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87, 0x03, 0x25, 0xEB, 0xFE,
0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE, 0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC};
};

/**
* @brief Default GOST parameters are the ones given in GOST R 34.11 for
* testing purposes; these sboxes are also used by Crypto++, and,
* at least according to Wikipedia, the Central Bank of Russian
* Federation
*/
struct cbr_params : public detail::gost_28147_89_parameters {
private:
struct col_selector {
col_selector(std::size_t row) : row(row) {
}

byte_type operator[](std::size_t col) const {
const byte_type x = parameters[4 * (col % 16) + row];
const byte_type y = parameters[4 * (col / 16) + row];
return (x >> 4) | (y << 4);
}

private:
std::size_t row;
};

public:
col_selector operator[](std::size_t row) const {
return {row};
}

// GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0)
constexpr static const parameters_type parameters = {
0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A, 0x4D, 0x2C, 0xD1, 0x10, 0x10,
0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38, 0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94,
0x62, 0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3, 0xC1, 0x7C, 0xE5, 0x7E,
0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C, 0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC};
};

/*!
* @brief GOST-28147-89 (Magma). 64-bit Russian cipher. Possible
* security issues. Avoid unless compatibility is needed.
*
* @tparam ParamsType GOST 28147-89 block cipher uses a set of 4 bit Sboxes, however
* the standard does not actually define these Sboxes; they are considered
* a local configuration issue. Several different sets are used.
*
* @ingroup block
*/
template<typename ParamsType = cbr_params>
class gost_28147_89 {
protected:
typedef detail::gost_28147_89_policy<ParamsType> policy_type;

typedef ParamsType parameters_type;

constexpr static const std::size_t rounds = policy_type::rounds;

constexpr static const std::size_t key_schedule_size = policy_type::key_schedule_size;
typedef typename policy_type::key_schedule_type key_schedule_type;

constexpr static const std::size_t expanded_substitution_size = policy_type::expanded_substitution_size;
typedef typename policy_type::expanded_substitution_type expanded_substitution_type;

public:
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;

gost_28147_89(const key_type &key,
const expanded_substitution_type &exp = expanded_substitution_type()) :
expanded_substitution(exp) {
for (size_t i = 0; i != 256; ++i) {
expanded_substitution[i] = policy_type::template rotl<11, word_type>(params[0][i]);
expanded_substitution[i + 256] = policy_type::template rotl<19, word_type>(params[1][i]);
expanded_substitution[i + 512] = policy_type::template rotl<27, word_type>(params[2][i]);
expanded_substitution[i + 768] = policy_type::template rotl<3, word_type>(params[3][i]);
}

schedule_key(key);
}

virtual ~gost_28147_89() {
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:
parameters_type params;
expanded_substitution_type expanded_substitution;
key_schedule_type key_schedule;

inline void schedule_key(const key_type &key) {
for (size_t i = 0; i != key_schedule_size; ++i) {
key_schedule[i] = boost::endian::native_to_little(key[i]);
}
}

inline block_type encrypt_block(const block_type &plaintext) const {
word_type N1 = boost::endian::native_to_little(plaintext[0]);
word_type N2 = boost::endian::native_to_little(plaintext[1]);

for (size_t j = 0; j != 3; ++j) {
GOST_2ROUND(N1, N2, 0, 1);
GOST_2ROUND(N1, N2, 2, 3);
GOST_2ROUND(N1, N2, 4, 5);
GOST_2ROUND(N1, N2, 6, 7);
}

GOST_2ROUND(N1, N2, 7, 6);
GOST_2ROUND(N1, N2, 5, 4);
GOST_2ROUND(N1, N2, 3, 2);
GOST_2ROUND(N1, N2, 1, 0);

return {boost::endian::little_to_native(N2), boost::endian::little_to_native(N1)};
}

inline block_type decrypt_block(const block_type &ciphertext) const {
word_type N1 = boost::endian::native_to_little(ciphertext[0]);
word_type N2 = boost::endian::native_to_little(ciphertext[1]);

GOST_2ROUND(N1, N2, 0, 1);
GOST_2ROUND(N1, N2, 2, 3);
GOST_2ROUND(N1, N2, 4, 5);
GOST_2ROUND(N1, N2, 6, 7);

for (size_t j = 0; j != 3; ++j) {
GOST_2ROUND(N1, N2, 7, 6);
GOST_2ROUND(N1, N2, 5, 4);
GOST_2ROUND(N1, N2, 3, 2);
GOST_2ROUND(N1, N2, 1, 0);
}

return {boost::endian::little_to_native(N2), boost::endian::little_to_native(N1)};
}
};
} // namespace block
} // namespace crypto3
} // namespace nil
#endif
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ endmacro()
set(TESTS_NAMES
"pack"
"rijndael"
"gost_28147_89"
"md4"
"md5"
"shacal"
Expand Down
42 changes: 42 additions & 0 deletions test/gost_28147_89.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//---------------------------------------------------------------------------//
// 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
//---------------------------------------------------------------------------//
#define BOOST_TEST_MODULE gost_28147_89_cipher_test

#include <iostream>

#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/gost_28147_89.hpp>

using namespace nil::crypto3;
using namespace nil::crypto3::block;

struct state_adder {
template<typename T>
void operator()(T &s1, T const &s2) {
typedef typename T::size_type size_type;
size_type n = (s2.size() < s1.size() ? s2.size() : s1.size());
for (typename T::size_type i = 0; i < n; ++i) {
s1[i] += s2[i];
}
}
};


BOOST_AUTO_TEST_SUITE(gost_28147_89_test_suite)

BOOST_AUTO_TEST_CASE(gost_28147_89_test) {
}

BOOST_AUTO_TEST_SUITE_END()