Skip to content
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
176 changes: 176 additions & 0 deletions include/nil/crypto3/block/blowfish.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//---------------------------------------------------------------------------//
// 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_BLOWFISH_HPP
#define CRYPTO3_BLOCK_BLOWFISH_HPP

#include <nil/crypto3/block/detail/blowfish/blowfish_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 Blowfish. A 64-bit cipher popular in the pre-AES era.
* Very slow key setup. Also used (with bcrypt) for password hashing.
*
* @ingroup block
*/
class blowfish {
protected:
typedef detail::blowfish_policy policy_type;

typedef typename policy_type::permutations_type permutations_type;
typedef typename policy_type::plain_constants_type plain_constants_type;
typedef typename policy_type::constants_type constants_type;

public:
constexpr static const std::size_t word_bits = policy_type::word_bits;
typedef typename policy_type::word_type word_type;

typedef typename policy_type::key_type key_type;
typedef typename policy_type::salt_type salt_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 rounds = policy_type::rounds;

typedef typename policy_type::endian_type endian_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;
};

blowfish(const key_type &key, const salt_type &salt = salt_type()) :
permutations(policy_type::permutations), constants(policy_type::constants) {
key_expansion(key, salt);
}

virtual ~blowfish() {
permutations.fill(0);
constants.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);
}

void salted_set_key(const key_type &key, const salt_type &salt, std::size_t workfactor) {
std::size_t length = key.size();
if (key.size() > 72 / sizeof(key_type::value_type)) {
// Truncate longer passwords to the 72 char bcrypt limit
length = 72;
}

key_expansion(key_type(key.begin(), key.begin() + length), salt);

if (workfactor > 0) {
const size_t rnd = static_cast<size_t>(1) << workfactor;

for (size_t r = 0; r != rnd; ++r) {
key_expansion(key, salt_type());
key_expansion(salt, salt_type());
}
}
}

protected:
permutations_type permutations;
plain_constants_type constants;

inline void key_expansion(const key_type &key, const salt_type &salt) {
for (size_t i = 0, j = 0; i != policy_type::permutations_size; ++i, j += word_bits / 8) {
permutations[i] ^= key[(j) % key.size()];
}

const size_t p_salt_offset = (!salt.empty()) ? policy_type::permutations_size % salt.size() : 0;

word_type L = 0, R = 0;
generate_sbox(permutations, L, R, salt, 0);
generate_sbox(constants, L, R, salt, p_salt_offset);
}

template<typename SubstitutionType>
void generate_sbox(SubstitutionType &box, word_type &L, word_type &R, const salt_type &salt,
std::size_t salt_off) const {
for (size_t i = 0; i != box.size(); i += 2) {
if (!salt.empty()) {
L ^= salt[(i + salt_off) % (salt.size())];
R ^= salt[(i + salt_off + 1) % (salt.size())];
}

for (size_t r = 0; r != policy_type::rounds; r += 2) {
L ^= permutations[r];
R ^= policy_type::bff(L, constants);

R ^= permutations[r + 1];
L ^= policy_type::bff(R, constants);
}

word_type T = R;
R = L ^ permutations[16];
L = T ^ permutations[17];
box[i] = L;
box[i + 1] = R;
}
}

inline block_type encrypt_block(const block_type &plaintext) const {
word_type L0 = plaintext[0], R0 = plaintext[1];

for (size_t r = 0; r != policy_type::rounds; r += 2) {
L0 ^= permutations[r];
R0 ^= policy_type::bff(L0, constants);

R0 ^= permutations[r + 1];
L0 ^= policy_type::bff(R0, constants);
}

L0 ^= permutations[16];
R0 ^= permutations[17];

return {R0, L0};
}

inline block_type decrypt_block(const block_type &ciphertext) const {
word_type L0 = ciphertext[0], R0 = ciphertext[1];

for (size_t r = policy_type::rounds + 1; r != 1; r -= 2) {
L0 ^= permutations[r];
R0 ^= policy_type::bff(L0, constants);

R0 ^= permutations[r - 1];
L0 ^= policy_type::bff(R0, constants);
}

L0 ^= permutations[1];
R0 ^= permutations[0];

return {R0, L0};
}
};
} // namespace block
} // namespace crypto3
} // namespace nil

#endif
41 changes: 41 additions & 0 deletions include/nil/crypto3/block/detail/blowfish/blowfish_functions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//---------------------------------------------------------------------------//
// 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_BLOWFISH_FUNCTIONS_CPP_HPP
#define CRYPTO3_BLOWFISH_FUNCTIONS_CPP_HPP

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

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

constexpr static const std::size_t constants_size = 256;
typedef std::array<word_type, constants_size> constants_type;

constexpr static const std::size_t plain_constants_size = constants_size * 4;
typedef std::array<word_type, plain_constants_size> plain_constants_type;

inline static word_type bff(word_type X, const plain_constants_type &constants) {
return ((constants[::nil::crypto3::detail::extract_uint_t<CHAR_BIT>(X, 0)] +
constants[256 + ::nil::crypto3::detail::extract_uint_t<CHAR_BIT>(X, 1)]) ^
constants[512 + ::nil::crypto3::detail::extract_uint_t<CHAR_BIT>(X, 2)]) +
constants[768 + ::nil::crypto3::detail::extract_uint_t<CHAR_BIT>(X, 3)];
}
};
} // namespace detail
} // namespace block
} // namespace crypto3
} // namespace nil

#endif // CRYPTO3_BLOWFISH_FUNCTIONS_CPP_HPP
Loading