Skip to content

Commit

Permalink
Refactorize code and use GSL (gsl::span)
Browse files Browse the repository at this point in the history
  • Loading branch information
matlo607 committed Feb 17, 2017
1 parent 45e135a commit a634713
Show file tree
Hide file tree
Showing 19 changed files with 439 additions and 318 deletions.
33 changes: 15 additions & 18 deletions include/HashingStrategy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
#include <array>
#include <iostream>
#include <memory>
#include <gsl/span>

namespace crypto {

template <typename T, size_t N>
std::ostream& operator<< (std::ostream& stream, const std::array<T,N>& array);
template <typename T, std::ptrdiff_t N>
std::ostream& operator<< (std::ostream& stream, const gsl::span<T,N>& array);

template <size_t N>
using CryptoHash_uint8 = std::array<uint8_t, N>;
Expand All @@ -20,26 +21,19 @@ namespace crypto {
template <size_t N>
using CryptoHash_uint64 = std::array<uint64_t, N / sizeof(uint64_t)>;

template <size_t N>
using MsgBlock_uint8 = std::array<uint8_t, N>;

template <size_t N>
using MsgBlock_uint32 = std::array<uint32_t, N / sizeof(uint32_t)>;

template <size_t N>
using MsgBlock_uint64 = std::array<uint64_t, N / sizeof(uint64_t)>;

template <size_t N>
using CryptoHash = CryptoHash_uint8<N>;

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest = N_tmpdigest>
template <size_t N_tmpdigest, size_t N_digest = N_tmpdigest,
typename T_subTypeBlock = uint32_t,
size_t N_blockSize = 16 * sizeof(T_subTypeBlock)>
class HashingStrategy
{
public:

virtual ~HashingStrategy() = default;

bool update(const uint8_t array[], size_t size, size_t offset = 0);
bool update(gsl::span<const uint8_t> &buf);
CryptoHash<N_digest> getHash(void);

protected:
Expand All @@ -58,6 +52,10 @@ namespace crypto {
{
public:

using MsgBlock_uint8 = std::array<uint8_t, N_blockSize>;
using MsgBlock_uint32 = std::array<uint32_t, sizeof(MsgBlock_uint8) / sizeof(uint32_t)>;
using MsgBlock_uint64 = std::array<uint64_t, sizeof(MsgBlock_uint8) / sizeof(uint64_t)>;

StrategyBlockCipherLike(void);
virtual ~StrategyBlockCipherLike() = default;

Expand All @@ -67,16 +65,16 @@ namespace crypto {
StrategyBlockCipherLike(StrategyBlockCipherLike&& other);
StrategyBlockCipherLike& operator=(StrategyBlockCipherLike&& other);

size_t write(const uint8_t buf[], size_t len);
size_t write(gsl::span<const uint8_t> &buf);
CryptoHash<N_digest> addPadding(size_t totalMsgLength);
virtual void reset(void) = 0;

protected:

MsgBlock_uint8<N_msgBlock> m_msgBlock;
size_t m_msgBlockIndex;
MsgBlock_uint8 m_msgBlock;
gsl::span<uint8_t> m_spaceAvailable;

std::array<T_workWord, N_tmpdigest / sizeof(T_workWord)> m_intermediateHash;
std::array<T_subTypeBlock, N_tmpdigest / sizeof(T_subTypeBlock)> m_intermediateHash;

virtual void process(void) = 0;
virtual CryptoHash<N_digest> getDigest(void) = 0;
Expand All @@ -96,4 +94,3 @@ namespace crypto {
#include "HashingStrategy.ipp"

#endif /* _HASHING_STRATEGY_HPP */

123 changes: 65 additions & 58 deletions include/HashingStrategy.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace crypto {

template <typename T, std::size_t N>
std::ostream& operator<< (std::ostream& stream, const std::array<T,N>& array)
template <typename T, std::ptrdiff_t N>
std::ostream& operator<< (std::ostream& stream, const gsl::span<T,N>& span)
{
char oldfill = stream.fill();
stream.fill('0');
Expand All @@ -20,8 +20,8 @@ namespace crypto {

stream.flags(ff);

for (auto elt : array) {
if (std::is_same<T, uint8_t>::value) {
for (auto elt : span) {
if (std::is_same<typename std::remove_cv<T>::type, uint8_t>::value) {
stream.width(sizeof(T) * 2); // width is not sticky as the other flags
stream << static_cast<uint16_t>(elt);
} else {
Expand All @@ -35,20 +35,20 @@ namespace crypto {
return stream;
}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::HashingStrategy(std::unique_ptr<StrategyBlockCipherLike>&& p) :
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::HashingStrategy(std::unique_ptr<StrategyBlockCipherLike>&& p) :
m_msgLength(0),
m_blockCipherStrategy(std::move(p))
{}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::HashingStrategy(HashingStrategy&& other) :
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::HashingStrategy(HashingStrategy&& other) :
m_msgLength(other.m_msgLength),
m_blockCipherStrategy(std::move(other.m_blockCipherStrategy))
{}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>& HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::operator=(HashingStrategy&& other)
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>& HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::operator=(HashingStrategy&& other)
{
if (this != &other) {
m_msgLength = other.m_msgLength;
Expand All @@ -57,30 +57,29 @@ namespace crypto {
return *this;
}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
bool HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::update(const uint8_t buf[], size_t len, size_t offset)
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
bool HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::update(gsl::span<const uint8_t> &buf)
{
assert(buf != NULL && offset <= len);
assert(buf.data() != nullptr && !buf.empty());

len -= offset;
buf += offset;

if (m_msgLength + len > MAX_MSG_LENGTH) {
if (m_msgLength + buf.size() > MAX_MSG_LENGTH) {
return false;
}

while (len > 0) {
size_t written = m_blockCipherStrategy->write(buf, len);
len -= written;
auto in(buf);
while ( !in.empty() ) {
auto written = m_blockCipherStrategy->write(in);
in = in.subspan(written);

// update message length
m_msgLength += written;
buf += written;
}

return true;
}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
CryptoHash<N_digest> HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::getHash(void)
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
CryptoHash<N_digest> HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::getHash(void)
{
// size of the message in bits
CryptoHash<N_digest> digest = m_blockCipherStrategy->addPadding(m_msgLength * 8);
Expand All @@ -94,74 +93,82 @@ namespace crypto {
return std::move(digest);
}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::StrategyBlockCipherLike::StrategyBlockCipherLike() :
m_msgBlockIndex(0) {}
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::StrategyBlockCipherLike::StrategyBlockCipherLike() :
m_spaceAvailable(m_msgBlock)
{}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::StrategyBlockCipherLike::StrategyBlockCipherLike(StrategyBlockCipherLike&& other) :
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::StrategyBlockCipherLike::StrategyBlockCipherLike(StrategyBlockCipherLike&& other) :
m_msgBlock(std::move(other.m_msgBlock)),
m_msgBlockIndex(other.m_msgBlockIndex),
m_spaceAvailable(gsl::span<uint8_t>(m_msgBlock).subspan(
m_msgBlock.size() - other.m_spaceAvailable.size())),
m_intermediateHash(std::move(other.m_intermediateHash))
{}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
typename HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::StrategyBlockCipherLike&
HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::StrategyBlockCipherLike::operator=(StrategyBlockCipherLike&& other)
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
typename HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::StrategyBlockCipherLike&
HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::StrategyBlockCipherLike::operator=(StrategyBlockCipherLike&& other)
{
if (this != &other) {
m_msgBlockIndex = other.m_msgBlockIndex;
m_msgBlock = std::move(other.m_msgBlock);
m_intermediateHash = std::move(other.m_intermediateHash);
m_spaceAvailable = gsl::span<uint8_t>(m_msgBlock).subspan(
m_msgBlock.size() - other.m_spaceAvailable.size());
}
return *this;
}


template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
size_t HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::StrategyBlockCipherLike::write(const uint8_t buf[], size_t len)
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
size_t HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::StrategyBlockCipherLike::write(gsl::span<const uint8_t> &buf)
{
assert(buf != NULL && len > 0);

auto writable = sizeof(MsgBlock_uint8<N_msgBlock>) - m_msgBlockIndex;
bool processing = (len >= writable);
auto toWrite = processing ? writable : len;
assert(buf.data() != nullptr && !buf.empty());

memcpy(m_msgBlock.data() + m_msgBlockIndex, buf, toWrite);
auto n = std::min(m_spaceAvailable.size(), buf.size());
std::copy_n(buf.begin(), n, m_spaceAvailable.begin());

if (processing) {
if (n == m_spaceAvailable.size()) {
process();
m_spaceAvailable = gsl::span<uint8_t>(m_msgBlock);
} else {
m_msgBlockIndex += len;
m_spaceAvailable = m_spaceAvailable.subspan(n);
}

return toWrite;
return n;
}

template <size_t N_tmpdigest, typename T_workWord, size_t N_msgBlock, size_t N_digest>
CryptoHash<N_digest> HashingStrategy<N_tmpdigest,T_workWord,N_msgBlock,N_digest>::StrategyBlockCipherLike::addPadding(size_t len)
template <size_t N_tmpdigest, size_t N_digest, typename T_subTypeBlock, size_t N_blockSize>
CryptoHash<N_digest> HashingStrategy<N_tmpdigest,N_digest,T_subTypeBlock,N_blockSize>::StrategyBlockCipherLike::addPadding(size_t len)
{
auto const MSGLENGTH_offset =
(std::is_same<T_workWord, uint64_t>::value) ?
sizeof(MsgBlock_uint8<N_msgBlock>) - sizeof(uint64_t) * 2 :
sizeof(MsgBlock_uint8<N_msgBlock>) - sizeof(uint64_t);
// Usually the size is encoded on 64bits although in new hashing algorithms like SHA512 this size's encoding was increased to 128bits.
// Given the probability of meeting a file with a size greater than 2^64-1 nowadays, and the possibilities of handling such numbers with
// the C++ native features, we will stick for simplicity to file's effective size encoded on 64 bits.
constexpr auto const MSG_BLOCK_SIZE = std::tuple_size<decltype(m_msgBlock)>::value;
constexpr auto const offset_MSGLENGTH =
(std::is_same<T_subTypeBlock, uint64_t>::value) ?
MSG_BLOCK_SIZE - sizeof(uint64_t) * 2 :
MSG_BLOCK_SIZE - sizeof(uint64_t);

// Write a "1" followed by 7 "0"s
m_msgBlock[m_msgBlockIndex++] = 0x80;
gsl::span<uint8_t> msgBlock { m_msgBlock };

auto const it_MSGLENGTH = std::next(msgBlock.begin(), offset_MSGLENGTH);
auto it = std::next(msgBlock.begin(), msgBlock.size() - m_spaceAvailable.size());

auto it = m_msgBlock.begin() + m_msgBlockIndex;
// Write a "1" followed by 7 "0"s
*it++ = 0x80;

// Do we have the space to write the length of the message ?
if(m_msgBlockIndex > MSGLENGTH_offset)
{
if (std::distance(it, it_MSGLENGTH) < 0) {
// Pad with "0"s until the end of the block and create a new block
std::fill_n(it, m_msgBlock.end() - it, 0x00);
std::fill(it, msgBlock.end(), 0);
process();
it = m_msgBlock.begin();

it = msgBlock.begin();
}

// Pad with "0"s until the message length's offset
std::fill_n(it, m_msgBlock.begin() + MSGLENGTH_offset - it, 0x00);
std::fill(it, it_MSGLENGTH, 0);

// Store the message length as the last 8 octets
setMsgSize(len);
Expand Down
6 changes: 4 additions & 2 deletions include/MD4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
namespace crypto {

#define MD4_HASH_SIZE 16 // (in bytes)
#define MD4_MSGBLOCK_SIZE 64 // (in bytes)

using MD4hash = CryptoHash<MD4_HASH_SIZE>;

class MD4hashing : public HashingStrategy<MD4_HASH_SIZE, uint32_t, MD4_MSGBLOCK_SIZE>
class MD4hashing : public HashingStrategy<MD4_HASH_SIZE>
{
public:

Expand All @@ -25,6 +24,9 @@ namespace crypto {

private:

using HS = HashingStrategy<MD4_HASH_SIZE>;
using HSBC = HS::StrategyBlockCipherLike;

class MD4BlockCipherLike final : public StrategyBlockCipherLike
{
private:
Expand Down
6 changes: 4 additions & 2 deletions include/MD5.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
namespace crypto {

#define MD5_HASH_SIZE 16 // (in bytes)
#define MD5_MSGBLOCK_SIZE 64 // (in bytes)

using MD5hash = CryptoHash<MD5_HASH_SIZE>;

class MD5hashing : public HashingStrategy<MD5_HASH_SIZE, uint32_t, MD5_MSGBLOCK_SIZE>
class MD5hashing : public HashingStrategy<MD5_HASH_SIZE>
{
public:

Expand All @@ -25,6 +24,9 @@ namespace crypto {

private:

using HS = HashingStrategy<MD5_HASH_SIZE>;
using HSBC = HS::StrategyBlockCipherLike;

class MD5BlockCipherLike final : public StrategyBlockCipherLike
{
private:
Expand Down
6 changes: 4 additions & 2 deletions include/SHA1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
namespace crypto {

#define SHA1_HASH_SIZE 20 // (in bytes)
#define SHA1_MSGBLOCK_SIZE 64 // (in bytes)

using SHA1hash = CryptoHash<SHA1_HASH_SIZE>;

class SHA1hashing final : public HashingStrategy<SHA1_HASH_SIZE, uint32_t, SHA1_MSGBLOCK_SIZE>
class SHA1hashing final : public HashingStrategy<SHA1_HASH_SIZE>
{
public:

Expand All @@ -25,6 +24,9 @@ namespace crypto {

private:

using HS = HashingStrategy<SHA1_HASH_SIZE>;
using HSBC = HS::StrategyBlockCipherLike;

class SHA1BlockCipherLike final : public StrategyBlockCipherLike
{
private:
Expand Down
20 changes: 10 additions & 10 deletions include/SHA224.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ namespace crypto {
private:

class SHA224BlockCipherLike final : public SHA256224BlockCipherLike
{
public:
SHA224BlockCipherLike(void);
virtual ~SHA224BlockCipherLike() = default;
{
public:
SHA224BlockCipherLike(void);
virtual ~SHA224BlockCipherLike() = default;

SHA224BlockCipherLike(const SHA224BlockCipherLike& other) = delete;
SHA224BlockCipherLike& operator=(const SHA224BlockCipherLike& other) = delete;
SHA224BlockCipherLike(const SHA224BlockCipherLike& other) = delete;
SHA224BlockCipherLike& operator=(const SHA224BlockCipherLike& other) = delete;

SHA224BlockCipherLike(SHA224BlockCipherLike&& other) = default;
SHA224BlockCipherLike& operator=(SHA224BlockCipherLike&& other) = default;
SHA224BlockCipherLike(SHA224BlockCipherLike&& other) = default;
SHA224BlockCipherLike& operator=(SHA224BlockCipherLike&& other) = default;

virtual void reset(void) final override;
};
virtual void reset(void) final override;
};
};

} /* namespace crypto */
Expand Down
Loading

0 comments on commit a634713

Please sign in to comment.