mirror of
https://github.com/DarkStore-3DS/Project_CTR.git
synced 2026-07-06 08:49:04 +00:00
Move dependencies to the top level.
This commit is contained in:
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* @file AesImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::AesImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/07/04
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/ArgumentNullException.h>
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class AesImpl
|
||||
* @brief This class implements the AES block encryption algorithm.
|
||||
*/
|
||||
class AesImpl
|
||||
{
|
||||
public:
|
||||
static const size_t kBlockSize = 16; /**< AES processing block size. */
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*
|
||||
* @post
|
||||
* - State is None. @ref initialize() must be called before use.
|
||||
*/
|
||||
AesImpl();
|
||||
~AesImpl();
|
||||
|
||||
/**
|
||||
* @brief Initialize AES state with key.
|
||||
*
|
||||
* @param[in] key Pointer to key data.
|
||||
* @param[in] key_size Size in bytes of key data.
|
||||
*
|
||||
* @pre
|
||||
* - @p key_size must be 16, 24 or 32.
|
||||
* @post
|
||||
* - Instance is now in initialized state.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p key was null.
|
||||
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal 16, 24 or 32.
|
||||
*/
|
||||
void initialize(const byte_t* key, size_t key_size);
|
||||
|
||||
/**
|
||||
* @brief Encrypt data block.
|
||||
*
|
||||
* @param[out] dst Buffer to store encrypted block.
|
||||
* @param[in] src Pointer to block to encrypt.
|
||||
*
|
||||
* @pre
|
||||
* - Instance is in initialized state.
|
||||
*
|
||||
* @details
|
||||
* This encrypts @ref kBlockSize number of bytes of data from @p src, writing it to @p dst.
|
||||
*
|
||||
* @note
|
||||
* - @p dst and @p src can be the same pointer.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p dst was null.
|
||||
* @throw tc::ArgumentNullException @p src was null.
|
||||
*/
|
||||
void encrypt(byte_t* dst, const byte_t* src);
|
||||
|
||||
/**
|
||||
* @brief Decrypt data block.
|
||||
*
|
||||
* @param[out] dst Buffer to store decrypted block.
|
||||
* @param[in] src Pointer to block to decrypt.
|
||||
*
|
||||
* @pre
|
||||
* - Instance is in initialized state.
|
||||
*
|
||||
* @details
|
||||
* This decrypts @ref kBlockSize number of bytes of data from @p src, writing it to @p dst.
|
||||
*
|
||||
* @note
|
||||
* - @p dst and @p src can be the same pointer.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p dst was null.
|
||||
* @throw tc::ArgumentNullException @p src was null.
|
||||
*/
|
||||
void decrypt(byte_t* dst, const byte_t* src);
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
struct ImplCtx;
|
||||
std::unique_ptr<ImplCtx> mImplCtx;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* @file BlockUtilImpl.h
|
||||
* @brief Declaration of block utility functions for tc::crypto
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/10/04
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
template <size_t BlockSize>
|
||||
inline void incr_counter(byte_t* counter, uint64_t incr)
|
||||
{
|
||||
for(uint64_t i = 0; i < incr; i++) {
|
||||
for (uint32_t j = BlockSize; j > 0; j--) {
|
||||
// increment u8 by 1
|
||||
counter[j-1]++;
|
||||
|
||||
// if it didn't overflow to 0, then we can exit now
|
||||
if (counter[j-1])
|
||||
break;
|
||||
|
||||
// if we reach here, the next u8 needs to be incremented
|
||||
if (j == 1)
|
||||
j = BlockSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void incr_counter<16>(byte_t* counter, uint64_t incr)
|
||||
{
|
||||
tc::bn::be64<uint64_t>* counter_words = (tc::bn::be64<uint64_t>*)counter;
|
||||
|
||||
uint64_t carry = incr;
|
||||
for (size_t i = 0; carry != 0 ; i = ((i + 1) % 2))
|
||||
{
|
||||
uint64_t word = counter_words[1 - i].unwrap();
|
||||
uint64_t remaining = std::numeric_limits<uint64_t>::max() - word;
|
||||
|
||||
if (remaining > carry)
|
||||
{
|
||||
counter_words[1 - i].wrap(word + carry);
|
||||
carry = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
counter_words[1 - i].wrap(carry - remaining - 1);
|
||||
carry = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t BlockSize>
|
||||
inline void xor_block(byte_t* dst, const byte_t* src_a, const byte_t* src_b)
|
||||
{
|
||||
for (size_t i = 0; i < BlockSize; i++) { dst[i] = src_a[i] ^ src_b[i];}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void xor_block<16>(byte_t* dst, const byte_t* src_a, const byte_t* src_b)
|
||||
{
|
||||
((uint64_t*)dst)[0] = ((uint64_t*)src_a)[0] ^ ((uint64_t*)src_b)[0];
|
||||
((uint64_t*)dst)[1] = ((uint64_t*)src_a)[1] ^ ((uint64_t*)src_b)[1];
|
||||
}
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,130 +0,0 @@
|
||||
/**
|
||||
* @file CbcModeImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::CbcModeImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/10/04
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/crypto/detail/BlockUtilImpl.h>
|
||||
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/ArgumentNullException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class CbcModeImpl
|
||||
* @brief This class implements the CBC (<b>c</b>ipher <b>b</b>lock <b>c</b>haining) mode cipher as a template class.
|
||||
*
|
||||
* @tparam BlockCipher The class that implements the block cipher used for CBC mode encryption/decryption.
|
||||
*
|
||||
* @details
|
||||
* The implementation of <var>BlockCipher</var> must satisfies the following conditions.
|
||||
*
|
||||
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
|
||||
* -# Has a <tt>kKeySize</tt> constant that defines the required key size to initialize the block cipher.
|
||||
* -# Has an <tt>initialize</tt> method that initializes the state of the block cipher.
|
||||
* -# Has an <tt>encrypt</tt> method that encrypts a block of input data.
|
||||
* -# Has a <tt>decrypt</tt> method that decrypts a block of input data.
|
||||
*/
|
||||
template <class BlockCipher>
|
||||
class CbcModeImpl
|
||||
{
|
||||
public:
|
||||
static const size_t kKeySize = BlockCipher::kKeySize;
|
||||
static const size_t kBlockSize = BlockCipher::kBlockSize;
|
||||
|
||||
CbcModeImpl() :
|
||||
mState(None),
|
||||
mCipher()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void initialize(const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
|
||||
{
|
||||
if (key == nullptr) { throw tc::ArgumentNullException("CbcModeImpl::initialize()", "key was null."); }
|
||||
if (key_size != kKeySize) { throw tc::ArgumentOutOfRangeException("CbcModeImpl::initialize()", "key_size did not equal kKeySize."); }
|
||||
if (iv == nullptr) { throw tc::ArgumentNullException("CbcModeImpl::initialize()", "iv was null."); }
|
||||
if (iv_size != kBlockSize) { throw tc::ArgumentOutOfRangeException("CbcModeImpl::initialize()", "iv_size did not equal kBlockSize."); }
|
||||
|
||||
mCipher.initialize(key, key_size);
|
||||
memcpy(mIv.data(), iv, mIv.size());
|
||||
mState = State::Initialized;
|
||||
}
|
||||
|
||||
void update_iv(const byte_t* iv, size_t iv_size)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (iv == nullptr) { throw tc::ArgumentNullException("CbcModeImpl::update_iv()", "iv was null."); }
|
||||
if (iv_size != kBlockSize) { throw tc::ArgumentOutOfRangeException("CbcModeImpl::update_iv()", "iv_size did not equal kBlockSize."); }
|
||||
|
||||
memcpy(mIv.data(), iv, mIv.size());
|
||||
}
|
||||
|
||||
void encrypt(byte_t* dst, const byte_t* src, size_t size)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (dst == nullptr) { throw tc::ArgumentNullException("CbcModeImpl::encrypt()", "dst was null."); }
|
||||
if (src == nullptr) { throw tc::ArgumentNullException("CbcModeImpl::encrypt()", "src was null."); }
|
||||
if (size == 0 || size % kBlockSize) { throw tc::ArgumentOutOfRangeException("CbcModeImpl::encrypt()", "size was not a multiple of kBlockSize."); }
|
||||
|
||||
auto block = std::array<byte_t, kBlockSize>();
|
||||
|
||||
// iterate through blocks
|
||||
for (size_t block_idx = 0, block_num = (size / kBlockSize); block_idx < block_num; block_idx++)
|
||||
{
|
||||
// block = src_block ^ iv
|
||||
xor_block<kBlockSize>(block.data(), src + (block_idx * kBlockSize), mIv.data());
|
||||
|
||||
// dst_block = encrypt(block)
|
||||
mCipher.encrypt(dst + (block_idx * kBlockSize), block.data());
|
||||
|
||||
// iv = dst_block
|
||||
memcpy(mIv.data(), dst + (block_idx * kBlockSize), kBlockSize);
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt(byte_t* dst, const byte_t* src, size_t size)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (dst == nullptr) { throw tc::ArgumentNullException("CbcModeImpl::decrypt()", "dst was null."); }
|
||||
if (src == nullptr) { throw tc::ArgumentNullException("CbcModeImpl::decrypt()", "src was null."); }
|
||||
if (size == 0 || size % kBlockSize) { throw tc::ArgumentOutOfRangeException("CbcModeImpl::decrypt()", "size was not a multiple of kBlockSize."); }
|
||||
|
||||
auto block = std::array<byte_t, kBlockSize>();
|
||||
auto next_iv = std::array<byte_t, kBlockSize>();
|
||||
|
||||
// iterate through blocks
|
||||
for (size_t block_idx = 0, block_num = (size / kBlockSize); block_idx < block_num; block_idx++)
|
||||
{
|
||||
// next_iv = src_block
|
||||
memcpy(next_iv.data(), src + (block_idx * kBlockSize), kBlockSize);
|
||||
|
||||
// block = decrypt(src_block)
|
||||
mCipher.decrypt(block.data(), src + (block_idx * kBlockSize));
|
||||
|
||||
// dst_block = block ^ iv
|
||||
xor_block<kBlockSize>(dst + (block_idx * kBlockSize), block.data(), mIv.data());
|
||||
|
||||
// iv = next_iv
|
||||
memcpy(mIv.data(), next_iv.data(), kBlockSize);
|
||||
}
|
||||
}
|
||||
private:
|
||||
enum State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
BlockCipher mCipher;
|
||||
std::array<byte_t, kBlockSize> mIv;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,113 +0,0 @@
|
||||
/**
|
||||
* @file CtrModeImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::CtrModeImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/10/04
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/crypto/detail/BlockUtilImpl.h>
|
||||
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/ArgumentNullException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class CtrModeImpl
|
||||
* @brief This class implements the CTR (<b>c</b>oun<b>t</b>e<b>r</b>) mode cipher as a template class.
|
||||
*
|
||||
* @tparam BlockCipher The class that implements the block cipher used for CTR mode encryption/decryption.
|
||||
*
|
||||
* @details
|
||||
* The implementation of <var>BlockCipher</var> must satisfies the following conditions.
|
||||
*
|
||||
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
|
||||
* -# Has a <tt>kKeySize</tt> constant that defines the required key size to initialize the block cipher.
|
||||
* -# Has an <tt>initialize</tt> method that initializes the state of the block cipher.
|
||||
* -# Has an <tt>encrypt</tt> method that encrypts a block of input data.
|
||||
* -# Has a <tt>decrypt</tt> method that decrypts a block of input data.
|
||||
*/
|
||||
template <class BlockCipher>
|
||||
class CtrModeImpl
|
||||
{
|
||||
public:
|
||||
static const size_t kKeySize = BlockCipher::kKeySize;
|
||||
static const size_t kBlockSize = BlockCipher::kBlockSize;
|
||||
|
||||
CtrModeImpl() :
|
||||
mState(None),
|
||||
mCipher()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void initialize(const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
|
||||
{
|
||||
if (key == nullptr) { throw tc::ArgumentNullException("CtrModeImpl::initialize()", "key was null."); }
|
||||
if (key_size != kKeySize) { throw tc::ArgumentOutOfRangeException("CtrModeImpl::initialize()", "key_size did not equal kKeySize."); }
|
||||
if (iv == nullptr) { throw tc::ArgumentNullException("CtrModeImpl::initialize()", "iv was null."); }
|
||||
if (iv_size != kBlockSize) { throw tc::ArgumentOutOfRangeException("CtrModeImpl::initialize()", "iv_size did not equal kBlockSize."); }
|
||||
|
||||
mCipher.initialize(key, key_size);
|
||||
memcpy(mIv.data(), iv, mIv.size());
|
||||
mState = State::Initialized;
|
||||
}
|
||||
|
||||
void crypt(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (dst == nullptr) { throw tc::ArgumentNullException("CtrModeImpl::crypt()", "dst was null."); }
|
||||
if (src == nullptr) { throw tc::ArgumentNullException("CtrModeImpl::crypt()", "src was null."); }
|
||||
if (size == 0) { throw tc::ArgumentOutOfRangeException("CtrModeImpl::crypt()", "size was 0."); }
|
||||
|
||||
auto iv = std::array<byte_t, kBlockSize>();
|
||||
auto enc_iv = std::array<byte_t, kBlockSize>();
|
||||
|
||||
// import and increment iv
|
||||
memcpy(iv.data(), mIv.data(), mIv.size());
|
||||
incr_counter<kBlockSize>(iv.data(), block_number);
|
||||
|
||||
// iterate through blocks
|
||||
for (size_t block_idx = 0, block_num = (size / kBlockSize); block_idx < block_num; block_idx++)
|
||||
{
|
||||
// encrypt IV
|
||||
mCipher.encrypt(enc_iv.data(), iv.data());
|
||||
|
||||
// dst = src ^ enc_iv
|
||||
xor_block<kBlockSize>(dst + (block_idx * kBlockSize), src + (block_idx * kBlockSize), enc_iv.data());
|
||||
|
||||
// increment counter
|
||||
incr_counter<kBlockSize>(iv.data(), 1);
|
||||
}
|
||||
|
||||
// process partial block
|
||||
size_t block_remaining = (size % kBlockSize);
|
||||
if (block_remaining > 0)
|
||||
{
|
||||
// encrypt IV
|
||||
mCipher.encrypt(enc_iv.data(), iv.data());
|
||||
|
||||
// dst = src ^ enc_iv
|
||||
for (size_t i = 0; i < block_remaining; i++)
|
||||
{
|
||||
dst[((size / kBlockSize) * kBlockSize) + i] = src[((size / kBlockSize) * kBlockSize) + i] ^ enc_iv[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
enum State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
BlockCipher mCipher;
|
||||
std::array<byte_t, kBlockSize> mIv;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,147 +0,0 @@
|
||||
/**
|
||||
* @file EcbModeImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::EcbModeImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/07/04
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/ArgumentNullException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class EcbModeImpl
|
||||
* @brief This class implements the ECB (<b>e</b>lectronic <b>c</b>ode<b>b</b>ook) mode cipher as a template class.
|
||||
*
|
||||
* @tparam BlockCipher The class that implements the block cipher used for ECB mode encryption/decryption.
|
||||
*
|
||||
* @details
|
||||
* The implementation of <var>BlockCipher</var> must satisfies the following conditions.
|
||||
*
|
||||
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
|
||||
* -# Has a <tt>kKeySize</tt> constant that defines the required key size to initialize the block cipher.
|
||||
* -# Has an <tt>initialize</tt> method that initializes the state of the block cipher.
|
||||
* -# Has an <tt>encrypt</tt> method that encrypts a block of input data.
|
||||
* -# Has a <tt>decrypt</tt> method that decrypts a block of input data.
|
||||
*/
|
||||
template <class BlockCipher>
|
||||
class EcbModeImpl
|
||||
{
|
||||
public:
|
||||
static const size_t kKeySize = BlockCipher::kKeySize;
|
||||
static const size_t kBlockSize = BlockCipher::kBlockSize;
|
||||
|
||||
EcbModeImpl() :
|
||||
mState(None),
|
||||
mCipher()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void initialize(const byte_t* key, size_t key_size)
|
||||
{
|
||||
if (key == nullptr) { throw tc::ArgumentNullException("EcbModeImpl::initialize()", "key was null."); }
|
||||
if (key_size != kKeySize) { throw tc::ArgumentOutOfRangeException("EcbModeImpl::initialize()", "key_size did not equal kKeySize."); }
|
||||
|
||||
mCipher.initialize(key, key_size);
|
||||
mState = State::Initialized;
|
||||
}
|
||||
|
||||
void encrypt(byte_t* dst, const byte_t* src, size_t size)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (dst == nullptr) { throw tc::ArgumentNullException("EcbModeImpl::encrypt()", "dst was null."); }
|
||||
if (src == nullptr) { throw tc::ArgumentNullException("EcbModeImpl::encrypt()", "src was null."); }
|
||||
if (size < kBlockSize) { throw tc::ArgumentOutOfRangeException("EcbModeImpl::encrypt()", "size was less than kBlockSize."); }
|
||||
|
||||
// for ciphertext stealing
|
||||
size_t block_leftover = size % kBlockSize;
|
||||
|
||||
// iterate through blocks
|
||||
for (size_t block_idx = 0, block_num = (size / kBlockSize); block_idx < block_num; block_idx++)
|
||||
{
|
||||
mCipher.encrypt(dst + (block_idx * kBlockSize), src + (block_idx * kBlockSize));
|
||||
}
|
||||
|
||||
// cipher text stealing
|
||||
if (block_leftover)
|
||||
{
|
||||
size_t block_idx = (size / kBlockSize);
|
||||
const byte_t* src_block = src + (block_idx * kBlockSize);
|
||||
byte_t* prev_dst_block = dst + ((block_idx - 1) * kBlockSize);
|
||||
byte_t* dst_block = dst + (block_idx * kBlockSize);
|
||||
|
||||
// part 1 : prep encryption thru cipher text stealing
|
||||
std::array<byte_t, kBlockSize> block;
|
||||
|
||||
// block [0, block_leftover) = src_block [0, block_leftover)
|
||||
memcpy(block.data(), src_block, block_leftover);
|
||||
|
||||
// block [block_leftover-kBlockSize with previous) = prev_dst_block [block_leftover-kBlockSize)
|
||||
memcpy(block.data() + block_leftover, prev_dst_block + block_leftover, kBlockSize - block_leftover);
|
||||
|
||||
// dst_block [0-block_leftover) = prev_dst_block [0-block_leftover)
|
||||
memcpy(dst_block, prev_dst_block, block_leftover);
|
||||
|
||||
// part 2 : encrypt block
|
||||
mCipher.encrypt(prev_dst_block, block.data());
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt(byte_t* dst, const byte_t* src, size_t size)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (dst == nullptr) { throw tc::ArgumentNullException("EcbModeImpl::decrypt()", "dst was null."); }
|
||||
if (src == nullptr) { throw tc::ArgumentNullException("EcbModeImpl::decrypt()", "src was null."); }
|
||||
if (size < kBlockSize) { throw tc::ArgumentOutOfRangeException("EcbModeImpl::decrypt()", "size less than kBlockSize."); }
|
||||
|
||||
// for ciphertext stealing
|
||||
size_t block_leftover = size % kBlockSize;
|
||||
|
||||
// iterate through blocks
|
||||
for (size_t block_idx = 0, block_num = (size / kBlockSize); block_idx < block_num; block_idx++)
|
||||
{
|
||||
mCipher.decrypt(dst + (block_idx * kBlockSize), src + (block_idx * kBlockSize));
|
||||
}
|
||||
|
||||
// cipher text stealing
|
||||
if (block_leftover)
|
||||
{
|
||||
size_t block_idx = (size / kBlockSize);
|
||||
const byte_t* src_block = src + (block_idx * kBlockSize);
|
||||
byte_t* prev_dst_block = dst + ((block_idx - 1) * kBlockSize);
|
||||
byte_t* dst_block = dst + (block_idx * kBlockSize);
|
||||
|
||||
// part 1 : prep encryption thru cipher text stealing
|
||||
std::array<byte_t, kBlockSize> block;
|
||||
|
||||
// block [0, block_leftover) = src_block [0, block_leftover)
|
||||
memcpy(block.data(), src_block, block_leftover);
|
||||
|
||||
// block [block_leftover-kBlockSize with previous) = prev_dst_block [block_leftover-kBlockSize)
|
||||
memcpy(block.data() + block_leftover, prev_dst_block + block_leftover, kBlockSize - block_leftover);
|
||||
|
||||
// dst_block [0-block_leftover) = prev_dst_block [0-block_leftover)
|
||||
memcpy(dst_block, prev_dst_block, block_leftover);
|
||||
|
||||
// part 2 : encrypt block
|
||||
mCipher.decrypt(prev_dst_block, block.data());
|
||||
}
|
||||
}
|
||||
private:
|
||||
enum State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
BlockCipher mCipher;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,107 +0,0 @@
|
||||
/**
|
||||
* @file HmacImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::HmacImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/06/06
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/ByteData.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class HmacImpl
|
||||
* @brief This class implements HMAC as a template class.
|
||||
*
|
||||
* @tparam HashFunction The class that implements the hash function used for HMAC calculation.
|
||||
*/
|
||||
template <typename HashFunction>
|
||||
class HmacImpl
|
||||
{
|
||||
public:
|
||||
static const size_t kMacSize = HashFunction::kHashSize;
|
||||
static const size_t kBlockSize = HashFunction::kBlockSize;
|
||||
|
||||
HmacImpl() :
|
||||
mHashFunction(),
|
||||
mState(State::None)
|
||||
{
|
||||
}
|
||||
~HmacImpl()
|
||||
{
|
||||
std::memset(mKeyDigest.data(), 0, mKeyDigest.size());
|
||||
std::memset(mMac.data(), 0, mMac.size());
|
||||
mState = State::None;
|
||||
}
|
||||
|
||||
void initialize(const byte_t* key, size_t key_size)
|
||||
{
|
||||
std::memset(mKeyDigest.data(), 0x00, mKeyDigest.size());
|
||||
|
||||
if (key_size > kBlockSize)
|
||||
{
|
||||
mHashFunction.initialize();
|
||||
mHashFunction.update(key, key_size);
|
||||
mHashFunction.getHash(mKeyDigest.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(mKeyDigest.data(), key, key_size);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0 ; i < kBlockSize / sizeof(uint32_t); i++)
|
||||
{
|
||||
((uint32_t*)mKeyDigest.data())[i] ^= uint32_t(0x36363636);
|
||||
}
|
||||
|
||||
mHashFunction.initialize();
|
||||
mHashFunction.update(mKeyDigest.data(), mKeyDigest.size());
|
||||
|
||||
mState = State::Initialized;
|
||||
}
|
||||
|
||||
void update(const byte_t* data, size_t data_size)
|
||||
{
|
||||
mHashFunction.update(data, data_size);
|
||||
}
|
||||
|
||||
void getMac(byte_t* mac)
|
||||
{
|
||||
if (mState == State::Initialized)
|
||||
{
|
||||
mHashFunction.getHash(mMac.data());
|
||||
|
||||
for (uint32_t i = 0 ; i < kBlockSize / sizeof(uint32_t); i++)
|
||||
{
|
||||
((uint32_t*)mKeyDigest.data())[i] ^= uint32_t(0x6A6A6A6A);
|
||||
}
|
||||
|
||||
mHashFunction.initialize();
|
||||
mHashFunction.update(mKeyDigest.data(), mKeyDigest.size());
|
||||
mHashFunction.update(mMac.data(), mMac.size());
|
||||
mHashFunction.getHash(mMac.data());
|
||||
|
||||
mState = State::Done;
|
||||
}
|
||||
if (mState == State::Done)
|
||||
{
|
||||
std::memcpy(mac, mMac.data(), mMac.size());
|
||||
}
|
||||
}
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
None,
|
||||
Initialized,
|
||||
Done
|
||||
};
|
||||
|
||||
HashFunction mHashFunction;
|
||||
std::array<byte_t, kBlockSize> mKeyDigest;
|
||||
std::array<byte_t, kMacSize> mMac;
|
||||
State mState;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* @file Md5Impl.h
|
||||
* @brief Declaration of tc::crypto::detail::Md5Impl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/06/01
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class Md5Impl
|
||||
* @brief This class implements the MD5 hash algorithm.
|
||||
*/
|
||||
class Md5Impl
|
||||
{
|
||||
public:
|
||||
static const size_t kHashSize = 16;
|
||||
static const size_t kBlockSize = 64;
|
||||
|
||||
Md5Impl();
|
||||
~Md5Impl();
|
||||
|
||||
void initialize();
|
||||
void update(const byte_t* data, size_t data_size);
|
||||
void getHash(byte_t* hash);
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
None,
|
||||
Initialized,
|
||||
Done
|
||||
};
|
||||
|
||||
State mState;
|
||||
std::array<byte_t, kHashSize> mHash;
|
||||
|
||||
struct ImplCtx;
|
||||
std::unique_ptr<ImplCtx> mImplCtx;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,159 +0,0 @@
|
||||
/**
|
||||
* @file Pbkdf1Impl.h
|
||||
* @brief Declaration of tc::crypto::detail::Pbkdf1Impl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/06/06
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/crypto/HmacGenerator.h>
|
||||
|
||||
#include <tc/crypto/CryptoException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class Pbkdf1Impl
|
||||
* @brief This class implements Password-Based Key Derivation Function 1 (PBKDF1)
|
||||
*
|
||||
* @tparam HashFunction The class that implements the hash function used for key derivation.
|
||||
*
|
||||
* @details
|
||||
* PBKDF1 is a hash based key derivation function, as defined in RFC 8018.
|
||||
* Applicable hash functions to use with PBKDF1 include.
|
||||
* -# MD4
|
||||
* -# MD5
|
||||
* -# SHA-1
|
||||
*/
|
||||
template <typename HashFunction>
|
||||
class Pbkdf1Impl
|
||||
{
|
||||
public:
|
||||
static const uint64_t kMaxDerivableSize = HashFunction::kHashSize; /**< Maximum total data that can be derived */
|
||||
|
||||
Pbkdf1Impl() :
|
||||
mState(State::None),
|
||||
mPassword(),
|
||||
mSalt(),
|
||||
mRoundCount(0),
|
||||
mHash(),
|
||||
mAvailableData(0),
|
||||
mTotalDataDerived(0)
|
||||
{
|
||||
std::memset(mDerivedData.data(), 0, mDerivedData.size());
|
||||
}
|
||||
|
||||
~Pbkdf1Impl()
|
||||
{
|
||||
mState = State::None;
|
||||
std::memset(mPassword.data(), 0, mPassword.size());
|
||||
std::memset(mSalt.data(), 0, mSalt.size());
|
||||
std::memset(mDerivedData.data(), 0, mDerivedData.size());
|
||||
mRoundCount = 0;
|
||||
mAvailableData = 0;
|
||||
mTotalDataDerived = 0;
|
||||
}
|
||||
|
||||
void initialize(const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
|
||||
{
|
||||
if (n_rounds < 1) { throw tc::crypto::CryptoException("tc::crypto::detail::Pbkdf1Impl", "Round count must be >= 1."); }
|
||||
|
||||
mPassword = tc::ByteData(password, password_size);
|
||||
mSalt = tc::ByteData(salt, salt_size);
|
||||
mRoundCount = n_rounds;
|
||||
|
||||
mAvailableData = 0;
|
||||
mTotalDataDerived = 0;
|
||||
|
||||
mState = State::Initialized;
|
||||
}
|
||||
|
||||
void getBytes(byte_t* key, size_t key_size)
|
||||
{
|
||||
if (mState != State::Initialized) return;
|
||||
|
||||
// determine data remaining
|
||||
uint64_t derivable_data = kMaxDerivableSize - mTotalDataDerived + mAvailableData;
|
||||
|
||||
if (key_size > derivable_data) { throw tc::crypto::CryptoException("tc::crypto::detail::Pbkdf1Impl", "Request too large."); }
|
||||
|
||||
while (key_size != 0)
|
||||
{
|
||||
// if there is no availble data then we generate more
|
||||
if (mAvailableData == 0)
|
||||
{
|
||||
deriveBytes();
|
||||
|
||||
// update the available digest to maximum
|
||||
mAvailableData = mDerivedData.size();
|
||||
|
||||
mTotalDataDerived += mDerivedData.size();
|
||||
}
|
||||
|
||||
// determine how much to copy in this loop
|
||||
size_t copy_size = std::min<size_t>(key_size, size_t(std::min<uint64_t>(mAvailableData, std::numeric_limits<size_t>::max())));
|
||||
|
||||
// copy available data into key
|
||||
memcpy(key, mDerivedData.data() + mDerivedData.size() - mAvailableData, copy_size);
|
||||
|
||||
// increment key pointer so next loop will copy to the right position
|
||||
key += copy_size;
|
||||
|
||||
// decrement key_size so the next loop can track how much data is needed
|
||||
key_size -= copy_size;
|
||||
|
||||
// decrement available digest so the next loop can determine where to copy from and generate more digest if needed
|
||||
mAvailableData -= copy_size;
|
||||
}
|
||||
}
|
||||
private:
|
||||
enum State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
tc::ByteData mPassword;
|
||||
tc::ByteData mSalt;
|
||||
size_t mRoundCount;
|
||||
|
||||
HashFunction mHash;
|
||||
std::array<byte_t, HashFunction::kHashSize> mDerivedData;
|
||||
uint64_t mAvailableData;
|
||||
uint64_t mTotalDataDerived;
|
||||
|
||||
void deriveBytes()
|
||||
{
|
||||
// generate round 0 hash (password | salt)
|
||||
|
||||
// init hash
|
||||
mHash.initialize();
|
||||
|
||||
// Update Hash with password
|
||||
mHash.update(mPassword.data(), mPassword.size());
|
||||
|
||||
// Update Hash with salt
|
||||
mHash.update(mSalt.data(), mSalt.size());
|
||||
|
||||
// Save Hash
|
||||
mHash.getHash(mDerivedData.data());
|
||||
|
||||
// do rounds 1 thru mRoundCount (prev round hash)
|
||||
for (size_t round = 1; round < mRoundCount; round++)
|
||||
{
|
||||
// initialize hash
|
||||
mHash.initialize();
|
||||
|
||||
// update with previous round hash
|
||||
mHash.update(mDerivedData.data(), mDerivedData.size());
|
||||
|
||||
// overwrite old hash digest with new hash digest
|
||||
mHash.getHash(mDerivedData.data());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,179 +0,0 @@
|
||||
/**
|
||||
* @file Pbkdf2Impl.h
|
||||
* @brief Declaration of tc::crypto::detail::Pbkdf2Impl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/06/06
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/crypto/HmacGenerator.h>
|
||||
|
||||
#include <tc/crypto/CryptoException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class Pbkdf2Impl
|
||||
* @brief This class implements Password-Based Key Derivation Function 2 (PBKDF2)
|
||||
*
|
||||
* @tparam HashFunction The class that implements the hash function used for key derivation.
|
||||
*
|
||||
* @details
|
||||
* PBKDF2 is a hmac based key derivation function, as defined in RFC 8018.
|
||||
* Applicable hash functions to use with PBKDF2 include.
|
||||
* -# SHA-1
|
||||
* -# SHA-224
|
||||
* -# SHA-256
|
||||
* -# SHA-384
|
||||
* -# SHA-512
|
||||
*/
|
||||
template <typename HashFunction>
|
||||
class Pbkdf2Impl
|
||||
{
|
||||
public:
|
||||
static const uint64_t kMaxDerivableSize = uint64_t(0xffffffff) * uint64_t(HashFunction::kHashSize); /**< Maximum total data that can be derived */
|
||||
|
||||
Pbkdf2Impl() :
|
||||
mState(State::None),
|
||||
mPassword(),
|
||||
mSalt(),
|
||||
mRoundCount(0),
|
||||
mHmac(),
|
||||
mAvailableData(0),
|
||||
mTotalDataDerived(0),
|
||||
mBlockIndex(0)
|
||||
{
|
||||
std::memset(mDerivedData.data(), 0, mDerivedData.size());
|
||||
}
|
||||
|
||||
~Pbkdf2Impl()
|
||||
{
|
||||
mState = State::None;
|
||||
std::memset(mPassword.data(), 0, mPassword.size());
|
||||
std::memset(mSalt.data(), 0, mSalt.size());
|
||||
std::memset(mDerivedData.data(), 0, mDerivedData.size());
|
||||
mRoundCount = 0;
|
||||
mBlockIndex = 0;
|
||||
mAvailableData = 0;
|
||||
}
|
||||
|
||||
void initialize(const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
|
||||
{
|
||||
if (n_rounds < 1) { throw tc::crypto::CryptoException("tc::crypto::detail::Pbkdf2Impl", "Round count must be >= 1."); }
|
||||
|
||||
mPassword = tc::ByteData(password, password_size);
|
||||
mSalt = tc::ByteData(salt, salt_size);
|
||||
mRoundCount = n_rounds;
|
||||
mBlockIndex = 1;
|
||||
|
||||
mAvailableData = 0;
|
||||
mTotalDataDerived = 0;
|
||||
|
||||
mState = State::Initialized;
|
||||
}
|
||||
|
||||
void getBytes(byte_t* key, size_t key_size)
|
||||
{
|
||||
if (mState != State::Initialized) return;
|
||||
|
||||
// determine data remaining
|
||||
uint64_t derivable_data = kMaxDerivableSize - mTotalDataDerived + mAvailableData;
|
||||
|
||||
if (key_size > derivable_data) { throw tc::crypto::CryptoException("tc::crypto::detail::Pbkdf1Impl", "Request too large."); }
|
||||
|
||||
while (key_size != 0)
|
||||
{
|
||||
// if there is no availble data then we generate more
|
||||
if (mAvailableData == 0)
|
||||
{
|
||||
deriveBytes();
|
||||
|
||||
// incrementing the block index ensures the next block is (predictably) unique
|
||||
mBlockIndex++;
|
||||
|
||||
// update the available digest to maximum
|
||||
mAvailableData = mDerivedData.size();
|
||||
|
||||
mTotalDataDerived += mDerivedData.size();
|
||||
}
|
||||
|
||||
// determine how much to copy in this loop
|
||||
size_t copy_size = std::min<size_t>(key_size, size_t(std::min<uint64_t>(mAvailableData, std::numeric_limits<size_t>::max())));
|
||||
|
||||
// copy available data into key
|
||||
memcpy(key, mDerivedData.data() + mDerivedData.size() - mAvailableData, copy_size);
|
||||
|
||||
// increment key pointer so next loop will copy to the right position
|
||||
key += copy_size;
|
||||
|
||||
// decrement key_size so the next loop can track how much data is needed
|
||||
key_size -= copy_size;
|
||||
|
||||
// decrement available digest so the next loop can determine where to copy from and generate more digest if needed
|
||||
mAvailableData -= copy_size;
|
||||
}
|
||||
}
|
||||
private:
|
||||
static const size_t kMacSize = HmacGenerator<HashFunction>::kMacSize;
|
||||
|
||||
enum State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
tc::ByteData mPassword;
|
||||
tc::ByteData mSalt;
|
||||
size_t mRoundCount;
|
||||
|
||||
HmacGenerator<HashFunction> mHmac;
|
||||
std::array<byte_t, kMacSize> mDerivedData;
|
||||
uint64_t mAvailableData;
|
||||
uint64_t mTotalDataDerived;
|
||||
uint32_t mBlockIndex;
|
||||
|
||||
void deriveBytes()
|
||||
{
|
||||
// Init HMAC with password
|
||||
mHmac.initialize(mPassword.data(), mPassword.size());
|
||||
|
||||
// Update HMAC with Salt
|
||||
mHmac.update(mSalt.data(), mSalt.size());
|
||||
|
||||
// Update HMAC with BigEndian block index
|
||||
tc::bn::be32<uint32_t> be_block_index;
|
||||
be_block_index.wrap(mBlockIndex);
|
||||
mHmac.update((const byte_t*)&be_block_index, sizeof(tc::bn::be32<uint32_t>));
|
||||
|
||||
// Save MAC to temporary value
|
||||
std::array<byte_t, kMacSize> mac;
|
||||
mHmac.getMac(mac.data());
|
||||
|
||||
// Also save MAC to derived data
|
||||
mHmac.getMac(mDerivedData.data());
|
||||
|
||||
// do HMAC rounds
|
||||
for (size_t round = 1; round < mRoundCount; round++)
|
||||
{
|
||||
// initialize HMAC again from password
|
||||
mHmac.initialize(mPassword.data(), mPassword.size());
|
||||
|
||||
// update hmac with old hmac digest
|
||||
mHmac.update(mac.data(), mac.size());
|
||||
|
||||
// overwrite old hmac digest with new hmac digest
|
||||
mHmac.getMac(mac.data());
|
||||
|
||||
// XOR temp digest with derived data
|
||||
for (size_t i = 0; i < kMacSize; i++)
|
||||
{
|
||||
mDerivedData[i] ^= mac[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* @file PrbgImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::PrbgImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/06/12
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/crypto/CryptoException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class PrbgImpl
|
||||
* @brief This class implements a Psuedo Random Byte Generator.
|
||||
*
|
||||
* @details
|
||||
* The underlying algorithm is CTR_DBRG.
|
||||
* This class generates random data suitable for encryption use cases.
|
||||
* - Initialization vectors
|
||||
* - Salts / Nonces
|
||||
* - HMAC keys
|
||||
* - AES keys
|
||||
*/
|
||||
class PrbgImpl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @details
|
||||
* This initializes random number generator state
|
||||
*/
|
||||
PrbgImpl();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
* @details
|
||||
* Cleans up random number generator state
|
||||
*/
|
||||
~PrbgImpl();
|
||||
|
||||
/**
|
||||
* @brief Populate array with random data.
|
||||
*
|
||||
* @param[out] data Buffer to hold random data.
|
||||
* @param[in] data_size Size of @p data buffer.
|
||||
*
|
||||
* @throw tc::crypto::CryptoException An unexpected error has occurred.
|
||||
* @throw tc::crypto::CryptoException Request too big.
|
||||
*/
|
||||
void getBytes(byte_t* data, size_t data_size);
|
||||
private:
|
||||
static const std::string kClassName;
|
||||
|
||||
struct ImplCtx;
|
||||
std::unique_ptr<ImplCtx> mImplCtx;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* @file RsaImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::RsaImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/09/12
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/ArgumentNullException.h>
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/crypto/CryptoException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class RsaImpl
|
||||
* @brief This class implements the RSA algorithm.
|
||||
*/
|
||||
class RsaImpl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*
|
||||
* @post
|
||||
* - State is None. @ref initialize() must be called before use.
|
||||
*/
|
||||
RsaImpl();
|
||||
~RsaImpl();
|
||||
|
||||
/**
|
||||
* @brief Initialize RSA state with key.
|
||||
*
|
||||
* @param[in] key_bit_size Size of rsa key in bits.
|
||||
* @param[in] n Pointer to modulus data.
|
||||
* @param[in] n_size Size in bytes of modulus data.
|
||||
* @param[in] p Pointer to prime p data.
|
||||
* @param[in] p_size Size in bytes of prime p data.
|
||||
* @param[in] q Pointer to prime q data.
|
||||
* @param[in] q_size Size in bytes of prime q data.
|
||||
* @param[in] d Pointer to private exponent data.
|
||||
* @param[in] d_size Size in bytes of private exponent data.
|
||||
* @param[in] e Pointer to public exponent data.
|
||||
* @param[in] e_size Size in bytes of public exponent data.
|
||||
*
|
||||
* @pre
|
||||
* - @p key_bit_size must a multiple of 8 bits (byte aligned).
|
||||
* @post
|
||||
* - Instance is now in initialized state.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p n was null when @p n_size was not 0.
|
||||
* @throw tc::ArgumentNullException @p n was not null when @p n_size was 0.
|
||||
* @throw tc::ArgumentNullException @p p was null when @p p_size was not 0.
|
||||
* @throw tc::ArgumentNullException @p p was not null when @p p_size was 0.
|
||||
* @throw tc::ArgumentNullException @p q was null when @p q_size was not 0.
|
||||
* @throw tc::ArgumentNullException @p q was not null when @p q_size was 0.
|
||||
* @throw tc::ArgumentNullException @p d was null when @p d_size was not 0.
|
||||
* @throw tc::ArgumentNullException @p d was not null when @p d_size was 0.
|
||||
* @throw tc::ArgumentNullException @p e was null when @p e_size was not 0.
|
||||
* @throw tc::ArgumentNullException @p e was not null when @p e_size was 0.
|
||||
* @throw tc::ArgumentOutOfRangeException @p key_bit_size was not a multiple of 8 bits.
|
||||
*/
|
||||
void initialize(size_t key_bit_size, const byte_t* n, size_t n_size, const byte_t* p, size_t p_size, const byte_t* q, size_t q_size, const byte_t* d, size_t d_size, const byte_t* e, size_t e_size);
|
||||
|
||||
/**
|
||||
* @brief Transform data block using public key.
|
||||
*
|
||||
* @param[out] dst Buffer to store transformed block.
|
||||
* @param[in] src Pointer to block to transform.
|
||||
*
|
||||
* @pre
|
||||
* - Instance is in initialized state.
|
||||
*
|
||||
* @details
|
||||
* This transforms block_size number of bytes of data from @p src, writing it to @p dst.
|
||||
*
|
||||
* @note
|
||||
* - @p dst and @p src can be the same pointer.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p dst was null.
|
||||
* @throw tc::ArgumentNullException @p src was null.
|
||||
*/
|
||||
void publicTransform(byte_t* dst, const byte_t* src);
|
||||
|
||||
/**
|
||||
* @brief Transform data block using private key.
|
||||
*
|
||||
* @param[out] dst Buffer to store transformed block.
|
||||
* @param[in] src Pointer to block to transform.
|
||||
*
|
||||
* @pre
|
||||
* - Instance is in initialized state.
|
||||
*
|
||||
* @details
|
||||
* This transforms block_size number of bytes of data from @p src, writing it to @p dst.
|
||||
*
|
||||
* @note
|
||||
* - @p dst and @p src can be the same pointer.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p dst was null.
|
||||
* @throw tc::ArgumentNullException @p src was null.
|
||||
*/
|
||||
void privateTransform(byte_t* dst, const byte_t* src);
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
struct ImplCtx;
|
||||
std::unique_ptr<ImplCtx> mImplCtx;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* @file RsaKeyGeneratorImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::RsaKeyGeneratorImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/09/12
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/ArgumentNullException.h>
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/crypto/CryptoException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class RsaKeyGeneratorImpl
|
||||
* @brief This class implements the RSA key generation.
|
||||
*/
|
||||
class RsaKeyGeneratorImpl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @details
|
||||
* This initializes RSA key generator state.
|
||||
*/
|
||||
RsaKeyGeneratorImpl();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
* @details
|
||||
* Cleans up RSA key generator state.
|
||||
*/
|
||||
~RsaKeyGeneratorImpl();
|
||||
|
||||
/**
|
||||
* @brief Generate an RSA key.
|
||||
*
|
||||
* @param[in] key_bit_size Size of rsa key in bits.
|
||||
* @param[out] n Buffer to store modulus.
|
||||
* @param[in] n_size Size of modulus buffer.
|
||||
* @param[out] p Buffer to store prime p.
|
||||
* @param[in] p_size Size of prime p buffer.
|
||||
* @param[out] q Buffer to store prime q.
|
||||
* @param[in] q_size Size of prime q buffer.
|
||||
* @param[out] d Buffer to store private exponent.
|
||||
* @param[in] d_size Size of private exponent buffer.
|
||||
* @param[out] e Buffer to store public exponent.
|
||||
* @param[in] e_size Size of public exponent buffer.
|
||||
*
|
||||
* @pre
|
||||
* - @p key_bit_size must a multiple of 8 bits (byte aligned).
|
||||
* @post
|
||||
* - Key components are exported if the related buffers were not null.
|
||||
*
|
||||
* @note
|
||||
* - Key components can be optionally not exported if the corresponding input variables are null and zero.
|
||||
*
|
||||
* @throw tc::ArgumentOutOfRangeException @p key_bit_size was not a multiple of 8 bits.
|
||||
* @throw tc::crypto::CryptoException An unexpected error has occurred.
|
||||
* @throw tc::crypto::CryptoException Something failed during generation of a key.
|
||||
* @throw tc::crypto::CryptoException The random generator failed to generate non-zeros.
|
||||
* @throw tc::ArgumentException @p n was not null, but @p n_size was not large enough.
|
||||
* @throw tc::ArgumentException @p p was not null, but @p p_size was not large enough.
|
||||
* @throw tc::ArgumentException @p q was not null, but @p q_size was not large enough.
|
||||
* @throw tc::ArgumentException @p d was not null, but @p d_size was not large enough.
|
||||
* @throw tc::ArgumentException @p e was not null, but @p e_size was not large enough.
|
||||
*/
|
||||
void generateKey(size_t key_bit_size, byte_t* n, size_t n_size, byte_t* p, size_t p_size, byte_t* q, size_t q_size, byte_t* d, size_t d_size, byte_t* e, size_t e_size);
|
||||
private:
|
||||
static const std::string kClassName;
|
||||
|
||||
struct ImplCtx;
|
||||
std::unique_ptr<ImplCtx> mImplCtx;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,169 +0,0 @@
|
||||
/**
|
||||
* @file RsaOaepPadding.h
|
||||
* @brief Declaration of tc::crypto::detail::RsaOaepPadding
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/09/12
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/ByteData.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class RsaOaepPadding
|
||||
* @brief This class implements RSA OAEP Padding as a template class.
|
||||
*
|
||||
* @tparam HashFunction The class that implements the hash function used for padding generation.
|
||||
*/
|
||||
template <typename HashFunction>
|
||||
class RsaOaepPadding
|
||||
{
|
||||
public:
|
||||
static const size_t kHashSize = HashFunction::kHashSize;
|
||||
|
||||
enum class Result
|
||||
{
|
||||
kSuccess,
|
||||
kBadSeedSize,
|
||||
kBadLabelDigestSize,
|
||||
kBlockSizeTooSmall,
|
||||
kBadPadding,
|
||||
kOutputBufferTooSmall
|
||||
};
|
||||
|
||||
RsaOaepPadding::Result BuildPad(byte_t* out_block, size_t block_size, const byte_t* label_digest, size_t label_digest_size, const byte_t* raw_message, size_t raw_message_size, const byte_t* seed, size_t seed_size)
|
||||
{
|
||||
if (seed_size != kHashSize) { return Result::kBadSeedSize; }
|
||||
if (label_digest_size != kHashSize) { return Result::kBadLabelDigestSize; }
|
||||
if (block_size < (1 + seed_size + label_digest_size + 1 + raw_message_size)) { return Result::kBlockSizeTooSmall; }
|
||||
|
||||
size_t seed_offset = 0x01;
|
||||
size_t label_digest_offset = seed_offset + seed_size;
|
||||
size_t padding_offset = label_digest_offset + label_digest_size;
|
||||
size_t padding_size = block_size - (1 + seed_size + label_digest_size + 1 + raw_message_size);
|
||||
size_t msg_offset = padding_offset + padding_size + 0x01;
|
||||
|
||||
out_block[0] = 0x00;
|
||||
memcpy(out_block + seed_offset, seed, seed_size);
|
||||
memcpy(out_block + label_digest_offset, label_digest, label_digest_size);
|
||||
memset(out_block + padding_offset, 00, padding_size);
|
||||
out_block[padding_offset + padding_size] = 0x01;
|
||||
memcpy(out_block + msg_offset, raw_message, raw_message_size);
|
||||
|
||||
// apply mask
|
||||
apply_mgf1_mask<kHashSize>(out_block + label_digest_offset, block_size - label_digest_offset, out_block + seed_offset, seed_size);
|
||||
apply_mgf1_mask<kHashSize>(out_block + seed_offset, seed_size, out_block + label_digest_offset, block_size - label_digest_offset);
|
||||
|
||||
return Result::kSuccess;
|
||||
}
|
||||
|
||||
RsaOaepPadding::Result RecoverFromPad(byte_t* out_message, size_t out_size, size_t& message_size, const byte_t* label_digest, size_t label_digest_size, byte_t* block, size_t block_size)
|
||||
{
|
||||
size_t seed_size = kHashSize;
|
||||
|
||||
if (out_size == 0) { return Result::kOutputBufferTooSmall; }
|
||||
if (label_digest_size != kHashSize) { return Result::kBadLabelDigestSize; }
|
||||
if (block_size < (1 + seed_size + label_digest_size + 1 + 1)) { return Result::kBlockSizeTooSmall; }
|
||||
|
||||
size_t seed_offset = 0x01;
|
||||
size_t label_digest_offset = seed_offset + seed_size;
|
||||
size_t padding_offset = label_digest_offset + label_digest_size;
|
||||
size_t padding_size = 0; // set later
|
||||
size_t msg_offset = 0;// set later
|
||||
size_t msg_size = 0;// set later
|
||||
|
||||
// constant time check
|
||||
byte_t bad = 0;
|
||||
|
||||
// check byte 0
|
||||
bad |= block[0] != 0x00;
|
||||
|
||||
// apply mask
|
||||
apply_mgf1_mask<kHashSize>(block + seed_offset, seed_size, block + label_digest_offset, block_size - label_digest_offset);
|
||||
apply_mgf1_mask<kHashSize>(block + label_digest_offset, block_size - label_digest_offset, block + seed_offset, seed_size);
|
||||
|
||||
// check label
|
||||
for (size_t i = 0; i < label_digest_size; i++)
|
||||
bad |= block[label_digest_offset + i] ^ label_digest[i];
|
||||
|
||||
// seek message begin {0x00, ..., 0x01, message}
|
||||
bool is0x01MarkerLocated = false;
|
||||
for (size_t i = 0, size = block_size - padding_offset; i < size && is0x01MarkerLocated == false; i++)
|
||||
{
|
||||
// padding byte that should prefix the start marker
|
||||
if (block[padding_offset + i] == 0x00)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// if the byte is the start marker then set other offsets/sizes and note the marker was located
|
||||
else if (block[padding_offset + i] == 0x01)
|
||||
{
|
||||
padding_size = i;
|
||||
msg_offset = padding_offset + padding_size + 0x01;
|
||||
msg_size = block_size - msg_offset;
|
||||
is0x01MarkerLocated = true;
|
||||
}
|
||||
// otherwise this is unexpected data
|
||||
else
|
||||
{
|
||||
bad |= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// throw error if bad
|
||||
if (is0x01MarkerLocated == false || bad != 0)
|
||||
{
|
||||
return Result::kBadPadding;
|
||||
}
|
||||
|
||||
// throw error if out_size isn't large enough
|
||||
if (out_size < msg_size)
|
||||
{
|
||||
return Result::kOutputBufferTooSmall;
|
||||
}
|
||||
|
||||
// export message
|
||||
memcpy(out_message, &block[msg_offset], msg_size);
|
||||
message_size = msg_size;
|
||||
|
||||
return Result::kSuccess;
|
||||
}
|
||||
|
||||
private:
|
||||
template <size_t HashSize>
|
||||
inline void apply_mgf1_mask(byte_t* dst, size_t dst_size, const byte_t* src, size_t src_size)
|
||||
{
|
||||
HashFunction hash;
|
||||
std::array<byte_t, HashSize> mask;
|
||||
tc::bn::be32<uint32_t> beRoundNum;
|
||||
|
||||
for (size_t round_idx = 0, round_num = (dst_size + HashSize - 1) / HashSize; round_idx < round_num; round_idx++)
|
||||
{
|
||||
hash.initialize();
|
||||
|
||||
// update using src data
|
||||
hash.update(src, src_size);
|
||||
|
||||
// update using big endian round num
|
||||
beRoundNum.wrap((uint32_t)round_idx);
|
||||
hash.update((byte_t*)&beRoundNum, sizeof(tc::bn::be32<uint32_t>));
|
||||
|
||||
// get mask
|
||||
hash.getHash(mask.data());
|
||||
|
||||
// merge mask and dst
|
||||
size_t dst_pos = round_idx * HashSize;
|
||||
|
||||
for (size_t i = 0, len = std::min(dst_size - dst_pos, HashSize); i < len; i++)
|
||||
{
|
||||
dst[dst_pos + i] ^= mask[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,117 +0,0 @@
|
||||
/**
|
||||
* @file RsaPkcs1Padding.h
|
||||
* @brief Declaration of tc::crypto::detail::RsaPkcs1Padding
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/09/12
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/ByteData.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class RsaPkcs1Padding
|
||||
* @brief This class implements RSA PKCS1 Padding as a template class.
|
||||
*
|
||||
* @tparam HashFunction The class that implements the hash function used for padding generation.
|
||||
*/
|
||||
template <typename HashFunction>
|
||||
class RsaPkcs1Padding
|
||||
{
|
||||
public:
|
||||
static const size_t kHashSize = HashFunction::kHashSize;
|
||||
|
||||
enum class Result
|
||||
{
|
||||
kSuccess,
|
||||
kBadMessageDigestSize,
|
||||
kBlockSizeTooSmall,
|
||||
kVerificationFailure
|
||||
};
|
||||
|
||||
RsaPkcs1Padding::Result BuildPad(byte_t* out_block, size_t block_size, const byte_t* message_digest, size_t message_digest_size)
|
||||
{
|
||||
if (message_digest_size != kHashSize) { return Result::kBadMessageDigestSize; }
|
||||
|
||||
// the minimum block size has 0 padding and the ASN1 OID data, message digest and marker bytes
|
||||
if (block_size < 2 + 1 + HashFunction::kAsn1OidData.size() + kHashSize) { return Result::kBlockSizeTooSmall; }
|
||||
|
||||
// determine sizes
|
||||
size_t padding_size = block_size - 2 - 1 - HashFunction::kAsn1OidDataSize - kHashSize;
|
||||
|
||||
// determine offsets
|
||||
size_t padding_offset = 0x02;
|
||||
size_t asn1oid_offset = padding_offset + padding_size + 1;
|
||||
size_t message_digest_offset = asn1oid_offset + HashFunction::kAsn1OidData.size();
|
||||
|
||||
// clear block
|
||||
memset(out_block, 0, block_size);
|
||||
|
||||
// write begin marker
|
||||
out_block[0] = 0x00;
|
||||
out_block[1] = 0x01;
|
||||
|
||||
// write padding
|
||||
memset(out_block + padding_offset, 0xff, padding_size);
|
||||
|
||||
// write payload marker
|
||||
out_block[padding_offset + padding_size] = 0x00;
|
||||
|
||||
// write ASN.1 encoded OID
|
||||
memcpy(out_block + asn1oid_offset, HashFunction::kAsn1OidData.data(), HashFunction::kAsn1OidData.size());
|
||||
|
||||
// write message digest
|
||||
memcpy(out_block + message_digest_offset, message_digest, kHashSize);
|
||||
|
||||
return Result::kSuccess;
|
||||
}
|
||||
|
||||
RsaPkcs1Padding::Result CheckPad(const byte_t* message_digest, size_t message_digest_size, byte_t* block, size_t block_size)
|
||||
{
|
||||
if (message_digest_size != kHashSize) { return Result::kBadMessageDigestSize; }
|
||||
|
||||
// the minimum block size has 0 padding and the ASN1 OID data, message digest and marker bytes
|
||||
if (block_size < 2 + 1 + HashFunction::kAsn1OidData.size() + kHashSize) { return Result::kBlockSizeTooSmall; }
|
||||
|
||||
// determine sizes
|
||||
size_t padding_size = block_size - 2 - 1 - HashFunction::kAsn1OidDataSize - kHashSize;
|
||||
|
||||
// determine offsets
|
||||
size_t padding_offset = 0x02;
|
||||
size_t asn1oid_offset = padding_offset + padding_size + 1;
|
||||
size_t message_digest_offset = asn1oid_offset + HashFunction::kAsn1OidData.size();
|
||||
|
||||
byte_t bad = 0;
|
||||
|
||||
// validate start marker
|
||||
bad |= block[0] != 0x00;
|
||||
bad |= block[1] != 0x01;
|
||||
|
||||
// validate padding
|
||||
for (size_t i = 0; i < padding_size; i++)
|
||||
{
|
||||
bad |= block[padding_offset + i] != 0xFF;
|
||||
}
|
||||
|
||||
// validate payload marker
|
||||
bad |= block[padding_offset + padding_size] != 0x00;
|
||||
|
||||
// validate ASN.1 data
|
||||
for (size_t i = 0; i < HashFunction::kAsn1OidData.size(); i++)
|
||||
{
|
||||
bad |= block[asn1oid_offset + i] != HashFunction::kAsn1OidData[i];
|
||||
}
|
||||
|
||||
// validate message digest
|
||||
for (size_t i = 0; i < kHashSize; i++)
|
||||
{
|
||||
bad |= block[message_digest_offset + i] != message_digest[i];
|
||||
}
|
||||
|
||||
return bad == 0? Result::kSuccess : Result::kVerificationFailure;
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,260 +0,0 @@
|
||||
/**
|
||||
* @file RsaPssPadding.h
|
||||
* @brief Declaration of tc::crypto::detail::RsaPssPadding
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/09/12
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/ByteData.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class RsaPssPadding
|
||||
* @brief This class implements RSA PSS Padding as a template class.
|
||||
*
|
||||
* @tparam HashFunction The class that implements the hash function used for padding generation.
|
||||
*/
|
||||
template <typename HashFunction>
|
||||
class RsaPssPadding
|
||||
{
|
||||
public:
|
||||
static const size_t kHashSize = HashFunction::kHashSize;
|
||||
|
||||
enum class Result
|
||||
{
|
||||
kSuccess,
|
||||
kBadMessageDigestSize,
|
||||
kBadSaltSize,
|
||||
kBlockSizeTooSmall,
|
||||
kBadPadding,
|
||||
kBadInputData,
|
||||
kVerificationFailure
|
||||
};
|
||||
|
||||
/**
|
||||
* @note modulus_msb is usually (for byte aligned key sizes) ((block_size << 3) - 1)
|
||||
* @note Where (modulus_msb % 8 == 0) this fails tests. Investigation required.
|
||||
*/
|
||||
RsaPssPadding::Result BuildPad(byte_t* out_block, size_t block_size, const byte_t* message_digest, size_t message_digest_size, const byte_t* salt, size_t salt_size, size_t modulus_msb)
|
||||
{
|
||||
size_t min_salt_size = kHashSize - 2;
|
||||
size_t expected_salt_size = 0;
|
||||
|
||||
// the block size is large enough to support a full sized salt (hash size)
|
||||
if (block_size >= kHashSize + kHashSize + 2)
|
||||
{
|
||||
expected_salt_size = kHashSize;
|
||||
}
|
||||
// the block size is too small for a full sized salt, but is large enough for a smaller legal sized salt
|
||||
else if (block_size >= min_salt_size + kHashSize + 2)
|
||||
{
|
||||
expected_salt_size = block_size - kHashSize - 2;
|
||||
}
|
||||
// else the block size is too small for any valid salt size
|
||||
else
|
||||
{
|
||||
return Result::kBlockSizeTooSmall;
|
||||
}
|
||||
|
||||
if (message_digest_size != kHashSize) { return Result::kBadMessageDigestSize; }
|
||||
|
||||
// salt_size cannot have any variance from the expected size
|
||||
if (salt_size != expected_salt_size) { return Result::kBadSaltSize; }
|
||||
|
||||
// initial config
|
||||
size_t signature_size = block_size;
|
||||
size_t db_offset = 0x00;
|
||||
|
||||
/* Compensate for boundary condition when applying mask */
|
||||
if (modulus_msb % 8 == 0)
|
||||
{
|
||||
db_offset++;
|
||||
signature_size--;
|
||||
}
|
||||
|
||||
// determine offsets and sizes
|
||||
size_t db_size = signature_size - kHashSize - 1;
|
||||
size_t db_padding_size = db_size - salt_size - 1;
|
||||
|
||||
size_t salt_offset = db_offset + db_padding_size + 1;
|
||||
size_t message_digest_offset = db_offset + db_size;
|
||||
|
||||
// clear block
|
||||
memset(out_block, 0, block_size);
|
||||
|
||||
// write salt start marker
|
||||
out_block[db_offset + db_padding_size] = 0x01;
|
||||
// write salt
|
||||
memcpy(out_block + salt_offset, salt, salt_size);
|
||||
|
||||
// write encoded message digest
|
||||
compute_encoded_message_digest(out_block + message_digest_offset, message_digest, salt, salt_size);
|
||||
|
||||
// mask db
|
||||
apply_mgf1_mask<kHashSize>(out_block + db_offset, db_size, out_block + message_digest_offset, kHashSize);
|
||||
|
||||
out_block[0] &= 0xFF >> ( signature_size * 8 - modulus_msb );
|
||||
|
||||
// write BC to final byte of block when complete
|
||||
out_block[block_size - 1] = 0xBC;
|
||||
|
||||
return Result::kSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @note modulus_msb is usually (for byte aligned key sizes) ((block_size << 3) - 1)
|
||||
* @note Where (modulus_msb % 8 == 0) this fails tests. Investigation required.
|
||||
*/
|
||||
RsaPssPadding::Result CheckPad(const byte_t* message_digest, size_t message_digest_size, byte_t* block, size_t block_size, size_t modulus_msb)
|
||||
{
|
||||
size_t min_salt_size = kHashSize - 2;
|
||||
size_t salt_size = 0;
|
||||
|
||||
// the block size is large enough to support a full sized salt (hash size)
|
||||
if (block_size >= kHashSize + kHashSize + 2)
|
||||
{
|
||||
salt_size = kHashSize;
|
||||
}
|
||||
// the block size is too small for a full sized salt, but is large enought for a smaller legal sized salt
|
||||
else if (block_size >= min_salt_size + kHashSize + 2)
|
||||
{
|
||||
salt_size = block_size - kHashSize - 2;
|
||||
}
|
||||
// else the block size is too small for any valid salt size
|
||||
else
|
||||
{
|
||||
return Result::kBlockSizeTooSmall;
|
||||
}
|
||||
|
||||
size_t signature_size = block_size;
|
||||
size_t db_offset = 0x00;
|
||||
|
||||
// check byte at end of block (written when padding is completed, so this should be here)
|
||||
if (block[block_size - 1] != 0xBC) { return Result::kBadPadding; }
|
||||
|
||||
/*
|
||||
* Note: EMSA-PSS verification is over the length of N - 1 bits
|
||||
*/
|
||||
if (block[0] >> ( 8 - block_size * 8 + modulus_msb )) { return Result::kBadInputData; }
|
||||
|
||||
/* Compensate for boundary condition when applying mask */
|
||||
if (modulus_msb % 8 == 0)
|
||||
{
|
||||
db_offset++;
|
||||
signature_size--;
|
||||
}
|
||||
|
||||
// determine offsets and sizes
|
||||
size_t db_size = signature_size - kHashSize - 1;
|
||||
size_t db_padding_size = db_size - salt_size - 1;
|
||||
|
||||
size_t salt_offset = db_offset + db_padding_size + 1;
|
||||
size_t message_digest_offset = db_offset + db_size;
|
||||
|
||||
// apply mask
|
||||
apply_mgf1_mask<kHashSize>(block + db_offset, db_size, block + message_digest_offset, kHashSize);
|
||||
|
||||
// mask byte0
|
||||
block[0] &= 0xFF >> ( signature_size * 8 - modulus_msb );
|
||||
|
||||
// constant time check
|
||||
byte_t bad = 0;
|
||||
|
||||
// validate padding seeking 01 byte, and validating the supposed salt size
|
||||
bool salt_marker_located = false;
|
||||
for (size_t i = 0, size = salt_offset; i < size && salt_marker_located == false; i++)
|
||||
{
|
||||
// padding byte that should prefix the start marker
|
||||
if (block[i] == 0x00)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// if the byte is the salt start marker then check that the salt offset is correct
|
||||
else if (block[i] == 0x01)
|
||||
{
|
||||
bad |= (i + 1) != salt_offset;
|
||||
salt_marker_located = true;
|
||||
}
|
||||
// otherwise this is unexpected data
|
||||
else
|
||||
{
|
||||
bad |= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// update bad if marker did not exist
|
||||
bad |= salt_marker_located == false;
|
||||
|
||||
// calculate encoded hash (all these offsets should be safe as they aren't provided by the user)
|
||||
std::array<byte_t, kHashSize> encoded_digest;
|
||||
compute_encoded_message_digest(encoded_digest.data(), message_digest, block + salt_offset, salt_size);
|
||||
|
||||
// check encoded hash (all these offsets should be safe as they aren't provided by the user)
|
||||
for (size_t i = 0; i < kHashSize; i++)
|
||||
bad |= block[message_digest_offset + i] ^ encoded_digest[i];
|
||||
|
||||
// return success if no errors
|
||||
return bad == 0 ? Result::kSuccess : Result::kVerificationFailure;
|
||||
}
|
||||
|
||||
private:
|
||||
template <size_t HashSize>
|
||||
inline void apply_mgf1_mask(byte_t* dst, size_t dst_size, const byte_t* src, size_t src_size)
|
||||
{
|
||||
HashFunction hash;
|
||||
std::array<byte_t, HashSize> mask;
|
||||
tc::bn::be32<uint32_t> beRoundNum;
|
||||
|
||||
for (size_t round_idx = 0, round_num = (dst_size + HashSize - 1) / HashSize; round_idx < round_num; round_idx++)
|
||||
{
|
||||
hash.initialize();
|
||||
|
||||
// update using src data
|
||||
hash.update(src, src_size);
|
||||
|
||||
// update using big endian round num
|
||||
beRoundNum.wrap((uint32_t)round_idx);
|
||||
hash.update((byte_t*)&beRoundNum, sizeof(tc::bn::be32<uint32_t>));
|
||||
|
||||
// get mask
|
||||
hash.getHash(mask.data());
|
||||
|
||||
// merge mask and dst
|
||||
size_t dst_pos = round_idx * HashSize;
|
||||
|
||||
for (size_t i = 0, len = std::min(dst_size - dst_pos, HashSize); i < len; i++)
|
||||
{
|
||||
dst[dst_pos + i] ^= mask[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void compute_encoded_message_digest(byte_t* dst, const byte_t* message_digest, const byte_t* salt, size_t salt_size)
|
||||
{
|
||||
HashFunction hash;
|
||||
std::array<byte_t, 8> prime;
|
||||
|
||||
// initialize hash
|
||||
hash.initialize();
|
||||
|
||||
// update hash with prime
|
||||
memset(prime.data(), 0, prime.size());
|
||||
hash.update(prime.data(), prime.size());
|
||||
|
||||
// update hash with original message digest
|
||||
hash.update(message_digest, kHashSize);
|
||||
|
||||
// update hash with salt
|
||||
hash.update(salt, salt_size);
|
||||
|
||||
// compute final hash digest
|
||||
hash.getHash(dst);
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* @file Sha1Impl.h
|
||||
* @brief Declaration of tc::crypto::detail::Sha1Impl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/06/01
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class Sha1Impl
|
||||
* @brief This class implements the SHA-1 hash algorithm.
|
||||
*/
|
||||
class Sha1Impl
|
||||
{
|
||||
public:
|
||||
static const size_t kHashSize = 20;
|
||||
static const size_t kBlockSize = 64;
|
||||
|
||||
Sha1Impl();
|
||||
~Sha1Impl();
|
||||
|
||||
void initialize();
|
||||
void update(const byte_t* data, size_t data_size);
|
||||
void getHash(byte_t* hash);
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
None,
|
||||
Initialized,
|
||||
Done
|
||||
};
|
||||
|
||||
State mState;
|
||||
std::array<byte_t, kHashSize> mHash;
|
||||
|
||||
struct ImplCtx;
|
||||
std::unique_ptr<ImplCtx> mImplCtx;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* @file Sha2Impl.h
|
||||
* @brief Declaration of tc::crypto::detail::Sha2Impl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2022/02/27
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/crypto/CryptoException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class Sha2Impl
|
||||
* @brief This class implements the SHA2 family of hash algorithms.
|
||||
*/
|
||||
class Sha2Impl
|
||||
{
|
||||
public:
|
||||
enum SHA2BitSize
|
||||
{
|
||||
SHA2BitSize_256 = 256,
|
||||
SHA2BitSize_512 = 512
|
||||
};
|
||||
|
||||
static const size_t kSha2_256_HashSize = 32;
|
||||
static const size_t kSha2_256_BlockSize = 64;
|
||||
|
||||
static const size_t kSha2_512_HashSize = 64;
|
||||
static const size_t kSha2_512_BlockSize = 128;
|
||||
|
||||
Sha2Impl(SHA2BitSize algo = SHA2BitSize_256);
|
||||
~Sha2Impl();
|
||||
|
||||
void initialize();
|
||||
void update(const byte_t* data, size_t data_size);
|
||||
void getHash(byte_t* hash);
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
None,
|
||||
Initialized,
|
||||
Done
|
||||
};
|
||||
|
||||
State mState;
|
||||
|
||||
size_t mHashSize;
|
||||
std::array<byte_t, kSha2_512_HashSize> mHash;
|
||||
|
||||
struct ImplCtx;
|
||||
std::unique_ptr<ImplCtx> mImplCtx;
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
@@ -1,330 +0,0 @@
|
||||
/**
|
||||
* @file XtsModeImpl.h
|
||||
* @brief Declaration of tc::crypto::detail::XtsModeImpl
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/07/04
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/ArgumentNullException.h>
|
||||
|
||||
namespace tc { namespace crypto { namespace detail {
|
||||
|
||||
/**
|
||||
* @class XtsModeImpl
|
||||
* @brief This class implements the XTS (<b>X</b>EX mode with cipher<b>t</b>ext <b>s</b>tealing) mode cipher as a template class.
|
||||
*
|
||||
* @tparam BlockCipher The class that implements the block cipher used for XTS mode encryption/decryption.
|
||||
*
|
||||
* @details
|
||||
* The implementation of <var>BlockCipher</var> must satisfies the following conditions.
|
||||
*
|
||||
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
|
||||
* -# Has a <tt>kKeySize</tt> constant that defines the required key size to initialize the block cipher.
|
||||
* -# Has an <tt>initialize</tt> method that initializes the state of the block cipher.
|
||||
* -# Has an <tt>encrypt</tt> method that encrypts a block of input data.
|
||||
* -# Has a <tt>decrypt</tt> method that decrypts a block of input data.
|
||||
*/
|
||||
template <class BlockCipher>
|
||||
class XtsModeImpl
|
||||
{
|
||||
public:
|
||||
static_assert(BlockCipher::kBlockSize == 16, "XtsModeImpl only supports BlockCiphers with block size 16.");
|
||||
|
||||
static const size_t kKeySize = BlockCipher::kKeySize;
|
||||
static const size_t kBlockSize = BlockCipher::kBlockSize;
|
||||
|
||||
size_t sector_size() const { return mSectorSize; }
|
||||
|
||||
XtsModeImpl() :
|
||||
mState(None),
|
||||
mCryptCipher(),
|
||||
mTweakCipher(),
|
||||
mSectorSize(0),
|
||||
mTweakIsLittleEndian(true)
|
||||
{
|
||||
}
|
||||
|
||||
void initialize(const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_little_endian = true)
|
||||
{
|
||||
if (key1 == nullptr) { throw tc::ArgumentNullException("XtsModeImpl::initialize()", "key1 was null."); }
|
||||
if (key1_size != kKeySize) { throw tc::ArgumentOutOfRangeException("XtsModeImpl::initialize()", "key1_size did not equal kKeySize."); }
|
||||
if (key2 == nullptr) { throw tc::ArgumentNullException("XtsModeImpl::initialize()", "key2 was null."); }
|
||||
if (key2_size != kKeySize) { throw tc::ArgumentOutOfRangeException("XtsModeImpl::initialize()", "key2_size did not equal kKeySize."); }
|
||||
if (sector_size < kBlockSize) { throw tc::ArgumentOutOfRangeException("XtsModeImpl::initialize()", "sector_size was less than kBlockSize."); }
|
||||
|
||||
mCryptCipher.initialize(key1, key1_size);
|
||||
mTweakCipher.initialize(key2, key2_size);
|
||||
mSectorSize = sector_size;
|
||||
mTweakIsLittleEndian = tweak_little_endian;
|
||||
mState = State::Initialized;
|
||||
}
|
||||
|
||||
void encrypt(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (dst == nullptr) { throw tc::ArgumentNullException("XtsModeImpl::encrypt()", "dst was null."); }
|
||||
if (src == nullptr) { throw tc::ArgumentNullException("XtsModeImpl::encrypt()", "src was null."); }
|
||||
if (size == 0 || size % mSectorSize) { throw tc::ArgumentOutOfRangeException("XtsModeImpl::encrypt()", "size was not a multiple of the sector size."); }
|
||||
|
||||
auto block = std::array<byte_t, kBlockSize>();
|
||||
auto dec_tweak = std::array<byte_t, kBlockSize>();
|
||||
auto enc_tweak = std::array<byte_t, kBlockSize>();
|
||||
|
||||
// for ciphertext stealing
|
||||
size_t sector_leftover = mSectorSize % kBlockSize;
|
||||
|
||||
// initialize tweak
|
||||
set_tweak(dec_tweak.data(), sector_number);
|
||||
|
||||
// iterate through sectors
|
||||
for (size_t sector_idx = 0, sector_num = (size / mSectorSize); sector_idx < sector_num; sector_idx++)
|
||||
{
|
||||
// encrypt tweak
|
||||
mTweakCipher.encrypt(enc_tweak.data(), dec_tweak.data());
|
||||
|
||||
// process each block within a sector
|
||||
for (size_t block_idx = 0, block_num = (mSectorSize / kBlockSize); block_idx < block_num; block_idx++)
|
||||
{
|
||||
const byte_t* src_block = src + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
byte_t* dst_block = dst + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
|
||||
// block = src_block XOR enc_tweak
|
||||
xor_block(block.data(), enc_tweak.data(), src_block);
|
||||
|
||||
// encrypt block
|
||||
mCryptCipher.encrypt(block.data(), block.data());
|
||||
|
||||
// dst_block = enc_block XOR enc_tweak
|
||||
xor_block(dst_block, block.data(), enc_tweak.data());
|
||||
|
||||
// Update encrypted tweak
|
||||
galois_func(enc_tweak.data());
|
||||
}
|
||||
|
||||
// cipher text stealing
|
||||
if (sector_leftover > 0)
|
||||
{
|
||||
size_t block_idx = (mSectorSize / kBlockSize);
|
||||
const byte_t* src_block = src + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
byte_t* prev_dst_block = dst + (sector_idx * mSectorSize) + ((block_idx - 1) * kBlockSize);
|
||||
byte_t* dst_block = dst + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
|
||||
for (size_t j = 0; j < sector_leftover; j++)
|
||||
{
|
||||
// block [0, sector_leftover) = src_block [0, sector_leftover) ^ enc_tweak[0, sector_leftover)
|
||||
block[j] = src_block[j] ^ enc_tweak[j];
|
||||
|
||||
// dst_block [0, sector_leftover) = prev_dst_block [0, sector_leftover)
|
||||
dst_block[j] = prev_dst_block[j];
|
||||
}
|
||||
|
||||
for (size_t j = sector_leftover; j < kBlockSize; j++)
|
||||
{
|
||||
// block [sector_leftover, kBlockSize) = prev_dst_block[sector_leftover, kBlockSize) ^ enc_tweak[sector_leftover, kBlockSize)
|
||||
block[j] = prev_dst_block[j] ^ enc_tweak[j];
|
||||
}
|
||||
|
||||
// encrypt block
|
||||
mCryptCipher.encrypt(block.data(), block.data());
|
||||
|
||||
// prev_dst_block = enc_block XOR enc_tweak
|
||||
xor_block(prev_dst_block, block.data(), enc_tweak.data());
|
||||
}
|
||||
|
||||
// increment tweak
|
||||
incr_tweak(dec_tweak.data(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number)
|
||||
{
|
||||
if (mState != State::Initialized) { return ; }
|
||||
if (dst == nullptr) { throw tc::ArgumentNullException("XtsModeImpl::decrypt()", "dst was null."); }
|
||||
if (src == nullptr) { throw tc::ArgumentNullException("XtsModeImpl::decrypt()", "src was null."); }
|
||||
if (size == 0 || size % mSectorSize) { throw tc::ArgumentOutOfRangeException("XtsModeImpl::decrypt()", "size was not a multiple of sector_size."); }
|
||||
|
||||
auto block = std::array<byte_t, kBlockSize>();
|
||||
auto dec_tweak = std::array<byte_t, kBlockSize>();
|
||||
auto enc_tweak = std::array<byte_t, kBlockSize>();
|
||||
|
||||
// for ciphertext stealing
|
||||
auto prev_tweak = std::array<byte_t, kBlockSize>();
|
||||
size_t sector_leftover = mSectorSize % kBlockSize;
|
||||
|
||||
// initialize tweak
|
||||
set_tweak(dec_tweak.data(), sector_number);
|
||||
|
||||
// iterate through sectors
|
||||
for (size_t sector_idx = 0, sector_num = (size / mSectorSize); sector_idx < sector_num; sector_idx++)
|
||||
{
|
||||
// encrypt tweak
|
||||
mTweakCipher.encrypt(enc_tweak.data(), dec_tweak.data());
|
||||
|
||||
// process each block within a sector
|
||||
for (size_t block_idx = 0, block_num = (mSectorSize / kBlockSize); block_idx < block_num; block_idx++)
|
||||
{
|
||||
const byte_t* src_block = src + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
byte_t* dst_block = dst + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
|
||||
// if this is the last block && there is left-over data
|
||||
if ((block_idx + 1) == block_num && sector_leftover > 0)
|
||||
{
|
||||
// save tweak for the cipher text stealing decryption
|
||||
memcpy(prev_tweak.data(), enc_tweak.data(), kBlockSize);
|
||||
|
||||
// Update encrypted tweak since this block uses the next tweak due to encryption mode cipher text stealing
|
||||
galois_func(enc_tweak.data());
|
||||
}
|
||||
|
||||
// block = src_block XOR enc_tweak
|
||||
xor_block(block.data(), enc_tweak.data(), src_block);
|
||||
|
||||
// decrypt block
|
||||
mCryptCipher.decrypt(block.data(), block.data());
|
||||
|
||||
// dst_block = dec_block XOR enc_tweak
|
||||
xor_block(dst_block, block.data(), enc_tweak.data());
|
||||
|
||||
// Update encrypted tweak
|
||||
galois_func(enc_tweak.data());
|
||||
}
|
||||
|
||||
// cipher text stealing
|
||||
if (sector_leftover > 0)
|
||||
{
|
||||
size_t block_idx = (mSectorSize / kBlockSize);
|
||||
const byte_t* src_block = src + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
byte_t* prev_dst_block = dst + (sector_idx * mSectorSize) + ((block_idx - 1) * kBlockSize);
|
||||
byte_t* dst_block = dst + (sector_idx * mSectorSize) + (block_idx * kBlockSize);
|
||||
|
||||
for (size_t j = 0; j < sector_leftover; j++)
|
||||
{
|
||||
// block [0, sector_leftover) = src_block [0, sector_leftover) ^ prev_tweak[0, sector_leftover)
|
||||
block[j] = src_block[j] ^ prev_tweak[j];
|
||||
|
||||
// dst_block [0, sector_leftover) = prev_dst_block [0, sector_leftover)
|
||||
dst_block[j] = prev_dst_block[j];
|
||||
}
|
||||
|
||||
for (size_t j = sector_leftover; j < kBlockSize; j++)
|
||||
{
|
||||
// block [sector_leftover, kBlockSize) = prev_dst_block[sector_leftover, kBlockSize) ^ prev_tweak[sector_leftover, kBlockSize)
|
||||
block[j] = prev_dst_block[j] ^ prev_tweak[j];
|
||||
}
|
||||
|
||||
// encrypt block
|
||||
mCryptCipher.decrypt(block.data(), block.data());
|
||||
|
||||
// prev_dst_block = enc_block XOR prev_tweak
|
||||
xor_block(prev_dst_block, block.data(), prev_tweak.data());
|
||||
}
|
||||
|
||||
// increment tweak
|
||||
incr_tweak(dec_tweak.data(), 1);
|
||||
}
|
||||
}
|
||||
private:
|
||||
enum State
|
||||
{
|
||||
None,
|
||||
Initialized
|
||||
};
|
||||
|
||||
State mState;
|
||||
BlockCipher mCryptCipher;
|
||||
BlockCipher mTweakCipher;
|
||||
size_t mSectorSize;
|
||||
bool mTweakIsLittleEndian;
|
||||
|
||||
inline void xor_block(byte_t* dst, const byte_t* src_a, const byte_t* src_b)
|
||||
{
|
||||
((uint64_t*)dst)[0] = ((uint64_t*)src_a)[0] ^ ((uint64_t*)src_b)[0];
|
||||
((uint64_t*)dst)[1] = ((uint64_t*)src_a)[1] ^ ((uint64_t*)src_b)[1];
|
||||
//for (size_t i = 0; i < kBlockSize; i++) { dst[i] = src_a[i] ^ src_b[i];}
|
||||
}
|
||||
|
||||
inline void set_tweak_le(byte_t* tweak, uint64_t sector_number)
|
||||
{
|
||||
((tc::bn::le64<uint64_t>*)tweak)[0].wrap(sector_number);
|
||||
((tc::bn::le64<uint64_t>*)tweak)[1].wrap(0x0);
|
||||
}
|
||||
|
||||
inline void set_tweak_be(byte_t* tweak, uint64_t sector_number)
|
||||
{
|
||||
((tc::bn::be64<uint64_t>*)tweak)[1].wrap(sector_number);
|
||||
((tc::bn::be64<uint64_t>*)tweak)[0].wrap(0x0);
|
||||
}
|
||||
|
||||
inline void set_tweak(byte_t* tweak, uint64_t sector_number)
|
||||
{
|
||||
mTweakIsLittleEndian ? set_tweak_le(tweak, sector_number) : set_tweak_be(tweak, sector_number);
|
||||
}
|
||||
|
||||
inline void incr_tweak_be(byte_t* tweak, uint64_t incr)
|
||||
{
|
||||
tc::bn::be64<uint64_t>* tweak_words = (tc::bn::be64<uint64_t>*)tweak;
|
||||
|
||||
uint64_t carry = incr;
|
||||
for (size_t i = 0; carry != 0 ; i = ((i + 1) % 2))
|
||||
{
|
||||
uint64_t word = tweak_words[1 - i].unwrap();
|
||||
uint64_t remaining = std::numeric_limits<uint64_t>::max() - word;
|
||||
|
||||
if (remaining > carry)
|
||||
{
|
||||
tweak_words[1 - i].wrap(word + carry);
|
||||
carry = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tweak_words[1 - i].wrap(carry - remaining - 1);
|
||||
carry = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void incr_tweak_le(byte_t* tweak, uint64_t incr)
|
||||
{
|
||||
tc::bn::le64<uint64_t>* tweak_words = (tc::bn::le64<uint64_t>*)tweak;
|
||||
|
||||
uint64_t carry = incr;
|
||||
for (size_t i = 0; carry != 0 ; i = ((i + 1) % 2))
|
||||
{
|
||||
uint64_t word = tweak_words[i].unwrap();
|
||||
uint64_t remaining = std::numeric_limits<uint64_t>::max() - word;
|
||||
|
||||
if (remaining > carry)
|
||||
{
|
||||
tweak_words[i].wrap(word + carry);
|
||||
carry = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tweak_words[i].wrap(carry - remaining - 1);
|
||||
carry = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void incr_tweak(byte_t* tweak, uint64_t incr)
|
||||
{
|
||||
mTweakIsLittleEndian ? incr_tweak_le(tweak, incr) : incr_tweak_be(tweak, incr);
|
||||
}
|
||||
|
||||
inline void galois_func(byte_t* tweak)
|
||||
{
|
||||
tc::bn::le64<uint64_t>* tweak_u64 = (tc::bn::le64<uint64_t>*)tweak;
|
||||
|
||||
uint64_t ra = ( tweak_u64[0].unwrap() << 1 ) ^ 0x0087 >> ( 8 - ( ( tweak_u64[1].unwrap() >> 63 ) << 3 ) );
|
||||
uint64_t rb = ( tweak_u64[0].unwrap() >> 63 ) | ( tweak_u64[1].unwrap() << 1 );
|
||||
|
||||
tweak_u64[0].wrap(ra);
|
||||
tweak_u64[1].wrap(rb);
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace tc::crypto::detail
|
||||
Reference in New Issue
Block a user