Move dependencies to the top level.

This commit is contained in:
jakcron
2022-04-16 18:27:14 +08:00
parent b67980d3d2
commit 5d62e839e7
844 changed files with 74 additions and 114431 deletions
@@ -0,0 +1,168 @@
/**
* @file Aes128CbcEncryptedStream.h
* @brief Declaration of tc::crypto::Aes128CbcEncryptedStream
* @author Jack (jakcron)
* @version 0.2
* @date 2022/02/13
**/
#pragma once
#include <list>
#include <tc/ByteData.h>
#include <tc/io/IStream.h>
#include <tc/crypto/Aes128CbcEncryptor.h>
#include <tc/ArgumentOutOfRangeException.h>
#include <tc/ObjectDisposedException.h>
#include <tc/NotSupportedException.h>
#include <tc/NotImplementedException.h>
#include <tc/io/IOException.h>
namespace tc { namespace crypto {
/**
* @class Aes128CbcEncryptedStream
* @brief Class for reading from a stream that is encrypted with AES128-CBC.
* @details This class takes an encrypted IStream, encryption parameters and creates an IStream that will transparently decrypt data when reading.
*/
class Aes128CbcEncryptedStream : public tc::io::IStream
{
public:
/**
* @brief This is the data-type for AES128-CBC key used with Aes128CbcEncryptedStream.
*
*/
using key_t = std::array<byte_t, tc::crypto::Aes128CbcEncryptor::kKeySize>;
/**
* @brief This is the data-type for AES128-CBC initialization vector used with Aes128CbcEncryptedStream.
*
*/
using iv_t = std::array<byte_t, tc::crypto::Aes128CbcEncryptor::kBlockSize>;
/**
* @brief This is the data-type for AES128-CBC data block used with Aes128CbcEncryptedStream.
*
*/
using block_t = std::array<byte_t, tc::crypto::Aes128CbcEncryptor::kBlockSize>;
/**
* @brief Default Constructor
* @post This will create an uninitialized Aes128CbcEncryptedStream, it will have to be assigned from a valid Aes128CbcEncryptedStream object to be usable.
**/
Aes128CbcEncryptedStream();
/**
* @brief Create Aes128CbcEncryptedStream
*
* @param[in] stream The base IStream object which this stream will decrypt data from.
* @param[in] key AES128 Encryption Key. See @ref Aes128CbcEncryptedStream::key_t.
* @param[in] iv AES128-CBC Initilization vector relative to offset 0x0 of the base stream. See @ref Aes128CbcEncryptedStream::iv_t.
*
* @pre The sub stream must be a subset of the base stream.
* @pre A stream must support seeking for @ref seek to work.
*
* @throw tc::ArgumentNullException @p stream is a @p nullptr.
* @throw tc::NotSupportedException The base stream does not support seeking or reading.
* @throw tc::NotSupportedException The base stream is not block aligned.
**/
Aes128CbcEncryptedStream(const std::shared_ptr<tc::io::IStream>& stream, const key_t& key, const iv_t& iv);
/**
* @brief Indicates whether the current stream supports reading.
**/
bool canRead() const;
/**
* @brief Indicates whether the current stream supports writing.
**/
bool canWrite() const;
/**
* @brief Indicates whether the current stream supports seeking.
**/
bool canSeek() const;
/**
* @brief Gets the length in bytes of the stream.
**/
int64_t length();
/**
* @brief Gets the position within the current stream.
*
* @return This is returns the current position within the stream.
**/
int64_t position();
/**
* @brief Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
*
* @param[out] ptr Pointer to an array of bytes. When this method returns, @p ptr contains the specified byte array with the values between 0 and (@p count - 1) replaced by the bytes read from the current source.
* @param[in] count The maximum number of bytes to be read from the current stream.
*
* @return The total number of bytes read into @p ptr. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
*
* @pre A stream must support reading for @ref read to work.
* @note Use @ref canRead to determine if this stream supports reading.
* @note Exceptions thrown by the base stream are not altered/intercepted, refer to that module's documentation for those exceptions.
*
* @throw tc::ArgumentOutOfRangeException @p count exceeds the length of readable data in the sub stream.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
size_t read(byte_t* ptr, size_t count);
/**
* @brief Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. @ref write is not implemented for @ref Aes128CbcEncryptedStream.
* @throw tc::NotImplementedException @ref write is not implemented for @ref Aes128CbcEncryptedStream.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
size_t write(const byte_t* ptr, size_t count);
/**
* @brief Sets the position within the current stream.
*
* @param[in] offset A byte offset relative to the origin parameter.
* @param[in] origin A value of type @ref tc::io::SeekOrigin indicating the reference point used to obtain the new position.
*
* @return The new position within the current stream.
*
* @pre A stream must support seeking for @ref seek to work.
* @note Use @ref canSeek to determine if this stream supports seeking.
* @note Exceptions thrown by the base stream are not altered/intercepted, refer to that module's documentation for those exceptions.
*
* @throw tc::ArgumentOutOfRangeException @p origin contains an invalid value.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
int64_t seek(int64_t offset, tc::io::SeekOrigin origin);
/**
* @brief Sets the length of the current stream. This is not implemented for @ref Aes128CbcEncryptedStream.
* @throw tc::NotImplementedException @ref setLength is not implemented for @ref Aes128CbcEncryptedStream.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
void setLength(int64_t length);
/**
* @brief Clears all buffers for this and the base stream and causes any buffered data to be written to the underlying device.
*
* @throw tc::io::IOException An I/O error occurs.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
void flush();
/**
* @brief Releases internal resources including base stream and clears internal state.
**/
void dispose();
private:
static const std::string kClassName;
// base source
std::shared_ptr<tc::io::IStream> mBaseStream;
// encryption cfg
std::shared_ptr<tc::crypto::Aes128CbcEncryptor> mCryptor;
iv_t mBaseIv;
};
}} // namespace tc::crypto
@@ -0,0 +1,94 @@
/**
* @file Aes128CbcEncryptor.h
* @brief Declarations for API resources for related to AES128-CBC mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/CbcEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes128CbcEncryptor
* @brief Class for AES-CBC encryption/decryption with a keysize of 128 bits.
*
* @details This class encrypts/decrypts data using using AES128-CBC.
* For more information refer to @ref CbcEncryptor.
*/
using Aes128CbcEncryptor = CbcEncryptor<Aes128Encryptor>;
/**
* @brief Utility function for AES128-CBC encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size is a multiple of @ref Aes128CbcEncryptor::kBlockSize.
* - @p key_size == @ref Aes128CbcEncryptor::kKeySize.
* - @p iv_size == @ref Aes128CbcEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @ref Aes128CbcEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes128CbcEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes128CbcEncryptor::kBlockSize.
*/
void EncryptAes128Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for AES128-CBC decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size is a multiple of @ref Aes128CbcEncryptor::kBlockSize.
* - @p key_size == @ref Aes128CbcEncryptor::kKeySize.
* - @p iv_size == @ref Aes128CbcEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @ref Aes128CbcEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes128CbcEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes128CbcEncryptor::kBlockSize.
*/
void DecryptAes128Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
}} // namespace tc::crypto
@@ -0,0 +1,166 @@
/**
* @file Aes128CtrEncryptedStream.h
* @brief Declaration of tc::crypto::Aes128CtrEncryptedStream
* @author Jack (jakcron)
* @version 0.2
* @date 2022/02/13
**/
#pragma once
#include <list>
#include <tc/ByteData.h>
#include <tc/io/IStream.h>
#include <tc/crypto/Aes128CtrEncryptor.h>
#include <tc/ArgumentOutOfRangeException.h>
#include <tc/ObjectDisposedException.h>
#include <tc/NotSupportedException.h>
#include <tc/NotImplementedException.h>
#include <tc/io/IOException.h>
namespace tc { namespace crypto {
/**
* @class Aes128CtrEncryptedStream
* @brief Class for reading from a stream that is encrypted with AES128-CTR.
* @details This class takes an encrypted IStream, encryption parameters and creates an IStream that will transparently decrypt data when reading.
*/
class Aes128CtrEncryptedStream : public tc::io::IStream
{
public:
/**
* @brief This is the data-type for AES128-CTR key used with Aes128CtrEncryptedStream.
*
*/
using key_t = std::array<byte_t, tc::crypto::Aes128CtrEncryptor::kKeySize>;
/**
* @brief This is the data-type for AES128-CTR block counter used with Aes128CtrEncryptedStream.
*
*/
using counter_t = std::array<byte_t, tc::crypto::Aes128CtrEncryptor::kBlockSize>;
/**
* @brief This is the data-type for AES128-CTR data block used with Aes128CtrEncryptedStream.
*
*/
using block_t = std::array<byte_t, tc::crypto::Aes128CtrEncryptor::kBlockSize>;
/**
* @brief Default Constructor
* @post This will create an uninitialized Aes128CtrEncryptedStream, it will have to be assigned from a valid Aes128CtrEncryptedStream object to be usable.
**/
Aes128CtrEncryptedStream();
/**
* @brief Create Aes128CtrEncryptedStream
*
* @param[in] stream The base IStream object which this stream will decrypt data from.
* @param[in] key AES128 Encryption Key. See @ref key_t.
* @param[in] counter AES128-CTR Counter relative to offset 0x0 of the base stream. See @ref counter_t.
*
* @pre The sub stream must be a subset of the base stream.
* @pre A stream must support seeking for @ref seek to work.
*
* @throw tc::ArgumentNullException @p stream is a @p nullptr.
* @throw tc::NotSupportedException The base stream does not support seeking or reading.
**/
Aes128CtrEncryptedStream(const std::shared_ptr<tc::io::IStream>& stream, const key_t& key, const counter_t& counter);
/**
* @brief Indicates whether the current stream supports reading.
**/
bool canRead() const;
/**
* @brief Indicates whether the current stream supports writing.
**/
bool canWrite() const;
/**
* @brief Indicates whether the current stream supports seeking.
**/
bool canSeek() const;
/**
* @brief Gets the length in bytes of the stream.
**/
int64_t length();
/**
* @brief Gets the position within the current stream.
*
* @return This is returns the current position within the stream.
**/
int64_t position();
/**
* @brief Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
*
* @param[out] ptr Pointer to an array of bytes. When this method returns, @p ptr contains the specified byte array with the values between 0 and (@p count - 1) replaced by the bytes read from the current source.
* @param[in] count The maximum number of bytes to be read from the current stream.
*
* @return The total number of bytes read into @p ptr. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
*
* @pre A stream must support reading for @ref read to work.
* @note Use @ref canRead to determine if this stream supports reading.
* @note Exceptions thrown by the base stream are not altered/intercepted, refer to that module's documentation for those exceptions.
*
* @throw tc::ArgumentOutOfRangeException @p count exceeds the length of readable data in the sub stream.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
size_t read(byte_t* ptr, size_t count);
/**
* @brief Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. @ref write is not implemented for @ref Aes128CtrEncryptedStream.
* @throw tc::NotImplementedException @ref write is not implemented for @ref Aes128CtrEncryptedStream.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
size_t write(const byte_t* ptr, size_t count);
/**
* @brief Sets the position within the current stream.
*
* @param[in] offset A byte offset relative to the origin parameter.
* @param[in] origin A value of type @ref tc::io::SeekOrigin indicating the reference point used to obtain the new position.
*
* @return The new position within the current stream.
*
* @pre A stream must support seeking for @ref seek to work.
* @note Use @ref canSeek to determine if this stream supports seeking.
* @note Exceptions thrown by the base stream are not altered/intercepted, refer to that module's documentation for those exceptions.
*
* @throw tc::ArgumentOutOfRangeException @p origin contains an invalid value.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
int64_t seek(int64_t offset, tc::io::SeekOrigin origin);
/**
* @brief Sets the length of the current stream. This is not implemented for @ref Aes128CtrEncryptedStream.
* @throw tc::NotImplementedException @ref setLength is not implemented for @ref Aes128CtrEncryptedStream.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
void setLength(int64_t length);
/**
* @brief Clears all buffers for this and the base stream and causes any buffered data to be written to the underlying device.
*
* @throw tc::io::IOException An I/O error occurs.
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
**/
void flush();
/**
* @brief Releases internal resources including base stream and clears internal state.
**/
void dispose();
private:
static const std::string kClassName;
// base source
std::shared_ptr<tc::io::IStream> mBaseStream;
// encryption cfg
std::shared_ptr<tc::crypto::Aes128CtrEncryptor> mCryptor;
};
}} // namespace tc::crypto
+115
View File
@@ -0,0 +1,115 @@
/**
* @file Aes128CtrEncryptor.h
* @brief Declarations for API resources for related to AES128-CTR mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/CtrEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes128CtrEncryptor
* @brief Class for AES-CTR encryption/decryption with a keysize of 128 bits.
*
* @details This class encrypts/decrypts data using using AES128-CTR.
* For more information refer to @ref CtrEncryptor.
*/
using Aes128CtrEncryptor = CtrEncryptor<Aes128Encryptor>;
/**
* @brief Utility function for AES128-CTR encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] block_number Block number of initial block to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size > 0.
* - @p key_size == @ref Aes128CtrEncryptor::kKeySize.
* - @p iv_size == @ref Aes128CtrEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was 0.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes128CtrEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes128CtrEncryptor::kBlockSize.
*/
void EncryptAes128Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for AES128-CTR decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] block_number Block number of initial block to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size > 0.
* - @p key_size == @ref Aes128CtrEncryptor::kKeySize.
* - @p iv_size == @ref Aes128CtrEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was 0.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes128CtrEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes128CtrEncryptor::kBlockSize.
*/
void DecryptAes128Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for incrementing a AES128-CTR block counter.
*
* @param[in,out] counter Pointer to block counter to increment.
* @param[in] incr Value to increment the block counter with.
*
* @pre
* - @p counter != nullptr
*
* @post
* - Block counter @p counter is incremented by the value of @p incr.
*
* @details
* This increments the block counter (@p counter) (used in CTR-Mode as the initialization vector) by the value of @p incr.
*
* @throw tc::ArgumentNullException @p counter was null.
*/
void IncrementCounterAes128Ctr(byte_t* counter, uint64_t incr);
}} // namespace tc::crypto
@@ -0,0 +1,84 @@
/**
* @file Aes128EcbEncryptor.h
* @brief Declarations for API resources for related to AES128-ECB mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/EcbEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes128EcbEncryptor
* @brief Class for AES-ECB encryption/decryption with a keysize of 128 bits.
*
* @details This class encrypts/decrypts data using using AES128-ECB.
* For more information refer to @ref EcbEncryptor.
*/
using Aes128EcbEncryptor = EcbEncryptor<Aes128Encryptor>;
/**
* @brief Utility function for AES128-ECB encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - @p size >= @ref Aes128EcbEncryptor::kBlockSize.
* - @p key_size == @ref Aes128EcbEncryptor::kKeySize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref Aes128EcbEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes128EcbEncryptor::kKeySize.
*/
void EncryptAes128Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size);
/**
* @brief Utility function for AES128-ECB decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - @p size >= @ref Aes128EcbEncryptor::kBlockSize.
* - @p key_size == @ref Aes128EcbEncryptor::kKeySize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref Aes128EcbEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes128EcbEncryptor::kKeySize.
*/
void DecryptAes128Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size);
}} // namespace tc::crypto
+104
View File
@@ -0,0 +1,104 @@
/**
* @file Aes128XtsEncryptor.h
* @brief Declarations for API resources for related to AES128-XTS mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/XtsEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes128XtsEncryptor
* @brief Class for AES-XTS encryption/decryption with a keysize of 128 bits.
*
* @details This class encrypts/decrypts data using using AES128-XTS.
* For more information refer to @ref XtsEncryptor.
*/
using Aes128XtsEncryptor = XtsEncryptor<Aes128Encryptor>;
/**
* @brief Utility function for AES128-XTS encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] sector_number Initial sector number of sector to encrypt.
* @param[in] key1 Pointer to key1 data.
* @param[in] key1_size Size in bytes of key1 data.
* @param[in] key2 Pointer to key2 data.
* @param[in] key2_size Size in bytes of key2 data.
* @param[in] sector_size Size in bytes of the XTS data unit.
* @param[in] tweak_word_order Boolean to determine endianness of tweak. True = LittleEndian, False = BigEndian.
*
* @pre
* - @p size is a multiple of @p sector_size.
* - @p key1_size == @ref Aes128XtsEncryptor::kKeySize.
* - @p key2_size == @ref Aes128XtsEncryptor::kKeySize.
* - @p sector_size >= @ref Aes128XtsEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @p sector_size.
* @throw tc::ArgumentNullException @p key1 was null.
* @throw tc::ArgumentOutOfRangeException @p key1_size did not equal @ref Aes128XtsEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p key2 was null.
* @throw tc::ArgumentOutOfRangeException @p key2_size did not equal @ref Aes128XtsEncryptor::kKeySize.
* @throw tc::ArgumentOutOfRangeException @p sector_size was less than @ref Aes128XtsEncryptor::kBlockSize.
*/
void EncryptAes128Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order);
/**
* @brief Utility function for AES128-XTS decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] sector_number Initial sector number of sector to decrypt.
* @param[in] key1 Pointer to key1 data.
* @param[in] key1_size Size in bytes of key1 data.
* @param[in] key2 Pointer to key2 data.
* @param[in] key2_size Size in bytes of key2 data.
* @param[in] sector_size Size in bytes of the XTS data unit.
* @param[in] tweak_word_order Boolean to determine endianness of tweak. True = LittleEndian, False = BigEndian.
*
* @pre
* - @p size is a multiple of @p sector_size.
* - @p key1_size == @ref Aes128XtsEncryptor::kKeySize.
* - @p key2_size == @ref Aes128XtsEncryptor::kKeySize.
* - @p sector_size >= @ref Aes128XtsEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @p sector_size.
* @throw tc::ArgumentNullException @p key1 was null.
* @throw tc::ArgumentOutOfRangeException @p key1_size did not equal @ref Aes128XtsEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p key2 was null.
* @throw tc::ArgumentOutOfRangeException @p key2_size did not equal @ref Aes128XtsEncryptor::kKeySize.
* @throw tc::ArgumentOutOfRangeException @p sector_size was less than @ref Aes128XtsEncryptor::kBlockSize.
*/
void DecryptAes128Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order);
}} // namespace tc::crypto
@@ -0,0 +1,94 @@
/**
* @file Aes192CbcEncryptor.h
* @brief Declarations for API resources for related to AES192-CBC mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/CbcEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes192CbcEncryptor
* @brief Class for AES-CBC encryption/decryption with a keysize of 192 bits.
*
* @details This class encrypts/decrypts data using using AES192-CBC.
* For more information refer to @ref CbcEncryptor.
*/
using Aes192CbcEncryptor = CbcEncryptor<Aes192Encryptor>;
/**
* @brief Utility function for AES192-CBC encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size is a multiple of @ref Aes192CbcEncryptor::kBlockSize.
* - @p key_size == @ref Aes192CbcEncryptor::kKeySize.
* - @p iv_size == @ref Aes192CbcEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @ref Aes192CbcEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes192CbcEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes192CbcEncryptor::kBlockSize.
*/
void EncryptAes192Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for AES192-CBC decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size is a multiple of @ref Aes192CbcEncryptor::kBlockSize.
* - @p key_size == @ref Aes192CbcEncryptor::kKeySize.
* - @p iv_size == @ref Aes192CbcEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @ref Aes192CbcEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes192CbcEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes192CbcEncryptor::kBlockSize.
*/
void DecryptAes192Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
}} // namespace tc::crypto
+115
View File
@@ -0,0 +1,115 @@
/**
* @file Aes192CtrEncryptor.h
* @brief Declarations for API resources for related to AES192-CTR mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/CtrEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes192CtrEncryptor
* @brief Class for AES-CTR encryption/decryption with a keysize of 192 bits.
*
* @details This class encrypts/decrypts data using using AES192-CTR.
* For more information refer to @ref CtrEncryptor.
*/
using Aes192CtrEncryptor = CtrEncryptor<Aes192Encryptor>;
/**
* @brief Utility function for AES192-CTR encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] block_number Block number of initial block to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size > 0.
* - @p key_size == @ref Aes192CtrEncryptor::kKeySize.
* - @p iv_size == @ref Aes192CtrEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was 0.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes192CtrEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes192CtrEncryptor::kBlockSize.
*/
void EncryptAes192Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for AES192-CTR decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] block_number Block number of initial block to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size > 0.
* - @p key_size == @ref Aes192CtrEncryptor::kKeySize.
* - @p iv_size == @ref Aes192CtrEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was 0.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes192CtrEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes192CtrEncryptor::kBlockSize.
*/
void DecryptAes192Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for incrementing a AES192-CTR block counter.
*
* @param[in,out] counter Pointer to block counter to increment.
* @param[in] incr Value to increment the block counter with.
*
* @pre
* - @p counter != nullptr
*
* @post
* - Block counter @p counter is incremented by the value of @p incr.
*
* @details
* This increments the block counter (@p counter) (used in CTR-Mode as the initialization vector) by the value of @p incr.
*
* @throw tc::ArgumentNullException @p counter was null.
*/
void IncrementCounterAes192Ctr(byte_t* counter, uint64_t incr);
}} // namespace tc::crypto
@@ -0,0 +1,84 @@
/**
* @file Aes192EcbEncryptor.h
* @brief Declarations for API resources for related to AES192-ECB mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/EcbEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes192EcbEncryptor
* @brief Class for AES-ECB encryption/decryption with a keysize of 192 bits.
*
* @details This class encrypts/decrypts data using using AES192-ECB.
* For more information refer to @ref EcbEncryptor.
*/
using Aes192EcbEncryptor = EcbEncryptor<Aes192Encryptor>;
/**
* @brief Utility function for AES192-ECB encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - @p size >= @ref Aes192EcbEncryptor::kBlockSize.
* - @p key_size == @ref Aes192EcbEncryptor::kKeySize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref Aes192EcbEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes192EcbEncryptor::kKeySize.
*/
void EncryptAes192Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size);
/**
* @brief Utility function for AES192-ECB decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - @p size >= @ref Aes192EcbEncryptor::kBlockSize.
* - @p key_size == @ref Aes192EcbEncryptor::kKeySize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref Aes192EcbEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes192EcbEncryptor::kKeySize.
*/
void DecryptAes192Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size);
}} // namespace tc::crypto
@@ -0,0 +1,94 @@
/**
* @file Aes256CbcEncryptor.h
* @brief Declarations for API resources for related to AES256-CBC mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/CbcEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes256CbcEncryptor
* @brief Class for AES-CBC encryption/decryption with a keysize of 256 bits.
*
* @details This class encrypts/decrypts data using using AES256-CBC.
* For more information refer to @ref CbcEncryptor.
*/
using Aes256CbcEncryptor = CbcEncryptor<Aes256Encryptor>;
/**
* @brief Utility function for AES256-CBC encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size is a multiple of @ref Aes256CbcEncryptor::kBlockSize.
* - @p key_size == @ref Aes256CbcEncryptor::kKeySize.
* - @p iv_size == @ref Aes256CbcEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @ref Aes256CbcEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes256CbcEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes256CbcEncryptor::kBlockSize.
*/
void EncryptAes256Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for AES256-CBC decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size is a multiple of @ref Aes256CbcEncryptor::kBlockSize.
* - @p key_size == @ref Aes256CbcEncryptor::kKeySize.
* - @p iv_size == @ref Aes256CbcEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @ref Aes256CbcEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes256CbcEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes256CbcEncryptor::kBlockSize.
*/
void DecryptAes256Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
}} // namespace tc::crypto
+115
View File
@@ -0,0 +1,115 @@
/**
* @file Aes256CtrEncryptor.h
* @brief Declarations for API resources for related to AES256-CTR mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/CtrEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes256CtrEncryptor
* @brief Class for AES-CTR encryption/decryption with a keysize of 256 bits.
*
* @details This class encrypts/decrypts data using using AES256-CTR.
* For more information refer to @ref CtrEncryptor.
*/
using Aes256CtrEncryptor = CtrEncryptor<Aes256Encryptor>;
/**
* @brief Utility function for AES256-CTR encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] block_number Block number of initial block to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size > 0.
* - @p key_size == @ref Aes256CtrEncryptor::kKeySize.
* - @p iv_size == @ref Aes256CtrEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was 0.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes256CtrEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes256CtrEncryptor::kBlockSize.
*/
void EncryptAes256Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for AES256-CTR decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] block_number Block number of initial block to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p size > 0.
* - @p key_size == @ref Aes256CtrEncryptor::kKeySize.
* - @p iv_size == @ref Aes256CtrEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was 0.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes256CtrEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal @ref Aes256CtrEncryptor::kBlockSize.
*/
void DecryptAes256Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size);
/**
* @brief Utility function for incrementing a AES256-CTR block counter.
*
* @param[in,out] counter Pointer to block counter to increment.
* @param[in] incr Value to increment the block counter with.
*
* @pre
* - @p counter != nullptr
*
* @post
* - Block counter @p counter is incremented by the value of @p incr.
*
* @details
* This increments the block counter (@p counter) (used in CTR-Mode as the initialization vector) by the value of @p incr.
*
* @throw tc::ArgumentNullException @p counter was null.
*/
void IncrementCounterAes256Ctr(byte_t* counter, uint64_t incr);
}} // namespace tc::crypto
@@ -0,0 +1,84 @@
/**
* @file Aes256EcbEncryptor.h
* @brief Declarations for API resources for related to AES256-ECB mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/EcbEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes256EcbEncryptor
* @brief Class for AES-ECB encryption/decryption with a keysize of 256 bits.
*
* @details This class encrypts/decrypts data using using AES256-ECB.
* For more information refer to @ref EcbEncryptor.
*/
using Aes256EcbEncryptor = EcbEncryptor<Aes256Encryptor>;
/**
* @brief Utility function for AES256-ECB encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - @p size >= @ref Aes256EcbEncryptor::kBlockSize.
* - @p key_size == @ref Aes256EcbEncryptor::kKeySize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref Aes256EcbEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes256EcbEncryptor::kKeySize.
*/
void EncryptAes256Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size);
/**
* @brief Utility function for AES256-ECB decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - @p size >= @ref Aes256EcbEncryptor::kBlockSize.
* - @p key_size == @ref Aes256EcbEncryptor::kKeySize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref Aes256EcbEncryptor::kBlockSize.
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref Aes256EcbEncryptor::kKeySize.
*/
void DecryptAes256Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size);
}} // namespace tc::crypto
+104
View File
@@ -0,0 +1,104 @@
/**
* @file Aes256XtsEncryptor.h
* @brief Declarations for API resources for related to AES256-XTS mode encryption/decryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/AesEncryptor.h>
#include <tc/crypto/XtsEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Aes256XtsEncryptor
* @brief Class for AES-XTS encryption/decryption with a keysize of 256 bits.
*
* @details This class encrypts/decrypts data using using AES256-XTS.
* For more information refer to @ref XtsEncryptor.
*/
using Aes256XtsEncryptor = XtsEncryptor<Aes256Encryptor>;
/**
* @brief Utility function for AES256-XTS encryption.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] sector_number Initial sector number of sector to encrypt.
* @param[in] key1 Pointer to key1 data.
* @param[in] key1_size Size in bytes of key1 data.
* @param[in] key2 Pointer to key2 data.
* @param[in] key2_size Size in bytes of key2 data.
* @param[in] sector_size Size in bytes of the XTS data unit.
* @param[in] tweak_word_order Boolean to determine endianness of tweak. True = LittleEndian, False = BigEndian.
*
* @pre
* - @p size is a multiple of @p sector_size.
* - @p key1_size == @ref Aes256XtsEncryptor::kKeySize.
* - @p key2_size == @ref Aes256XtsEncryptor::kKeySize.
* - @p sector_size >= @ref Aes256XtsEncryptor::kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @p sector_size.
* @throw tc::ArgumentNullException @p key1 was null.
* @throw tc::ArgumentOutOfRangeException @p key1_size did not equal @ref Aes256XtsEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p key2 was null.
* @throw tc::ArgumentOutOfRangeException @p key2_size did not equal @ref Aes256XtsEncryptor::kKeySize.
* @throw tc::ArgumentOutOfRangeException @p sector_size was less than @ref Aes256XtsEncryptor::kBlockSize.
*/
void EncryptAes256Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order);
/**
* @brief Utility function for AES256-XTS decryption.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] sector_number Initial sector number of sector todecrypt.
* @param[in] key1 Pointer to key1 data.
* @param[in] key1_size Size in bytes of key1 data.
* @param[in] key2 Pointer to key2 data.
* @param[in] key2_size Size in bytes of key2 data.
* @param[in] sector_size Size in bytes of the XTS data unit.
* @param[in] tweak_word_order Boolean to determine endianness of tweak. True = LittleEndian, False = BigEndian.
*
* @pre
* - @p size is a multiple of @p sector_size.
* - @p key1_size == @ref Aes256XtsEncryptor::kKeySize.
* - @p key2_size == @ref Aes256XtsEncryptor::kKeySize.
* - @p sector_size >= @ref Aes256XtsEncryptor::kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of @p sector_size.
* @throw tc::ArgumentNullException @p key1 was null.
* @throw tc::ArgumentOutOfRangeException @p key1_size did not equal @ref Aes256XtsEncryptor::kKeySize.
* @throw tc::ArgumentNullException @p key2 was null.
* @throw tc::ArgumentOutOfRangeException @p key2_size did not equal @ref Aes256XtsEncryptor::kKeySize.
* @throw tc::ArgumentOutOfRangeException @p sector_size was less than @ref Aes256XtsEncryptor::kBlockSize.
*/
void DecryptAes256Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order);
}} // namespace tc::crypto
+140
View File
@@ -0,0 +1,140 @@
/**
* @file AesEncryptor.h
* @brief Declarations for API resources related to AES block encryption.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/AesImpl.h>
#include <tc/ArgumentOutOfRangeException.h>
#include <tc/ArgumentNullException.h>
namespace tc { namespace crypto {
/**
* @class AesEncryptor
* @brief Class for AES encryption/decryption.
*
* @tparam KeySize Size in bytes of the AES encryption key. This must be 16, 24 or 32.
*
* @details
* This class has three states:
* - None : Not ready
* - Initialized : Ready to process data
*
* General usage of this class is as follows:
* - Initialize AES state with @ref initialize().
* - Encrypt or decrypt block(s) using @ref encrypt() or @ref decrypt().
*/
template <size_t KeySize>
class AesEncryptor
{
public:
static_assert(KeySize == 16 || KeySize == 24 || KeySize == 32, "Unsupported AES KeySize");
static const size_t kKeySize = KeySize; /**< AES key size. */
static const size_t kBlockSize = 16; /**< AES processing block size. */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
AesEncryptor() :
mImpl()
{}
/**
* @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 == @ref kKeySize.
* @post
* - Instance is now in initialized state.
*
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal @ref kKeySize.
*/
void initialize(const byte_t* key, size_t key_size)
{
if (key_size != kKeySize) { throw tc::ArgumentOutOfRangeException("AesEncryptor::initialize()", "key_size did not equal kKeySize."); }
mImpl.initialize(key, 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)
{
mImpl.encrypt(dst, 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)
{
mImpl.decrypt(dst, src);
}
private:
detail::AesImpl mImpl;
};
/**
* @typedef Aes128Encryptor
* @brief Class for AES-128 encryption/decryption.
*/
using Aes128Encryptor = AesEncryptor<16>;
/**
* @typedef Aes192Encryptor
* @brief Class for AES-192 encryption/decryption.
*/
using Aes192Encryptor = AesEncryptor<24>;
/**
* @typedef Aes256Encryptor
* @brief Class for AES-256 encryption/decryption.
*/
using Aes256Encryptor = AesEncryptor<32>;
}} // namespace tc::crypto
+177
View File
@@ -0,0 +1,177 @@
/**
* @file CbcEncryptor.h
* @brief Declaration of tc::crypto::CbcEncryptor
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/CbcModeImpl.h>
namespace tc { namespace crypto {
/**
* @class CbcEncryptor
* @brief Class for CBC mode encryption/decryption.
*
* @tparam BlockCipher The class that implements the block cipher used for CBC mode encryption/decryption.
*
* @details
* Cipher block chaining (CBC) mode is intended to encrypt whole sets of data. Random access is not a feature of CBC mode.
*
* This class is a template class that takes a block cipher implementation class as template parameter.
* See @ref Aes128CbcEncryptor or similar for supplied realizations of this template class.
*
* The implementation of @a BlockCipher must satisfies the following conditions.
* See @ref AesEncryptor or similar class, for more information including parameters to each function.
*
* -# Has a @p kBlockSize constant that defines the size of the block to process.
* -# Has a @p kKeySize constant that defines the required key size to initialize the block cipher.
* -# Has an @p initialize method that initializes the state of the block cipher.
* -# Has an @p encrypt method that encrypts a block of input data.
* -# Has a @p decrypt method that decrypts a block of input data.
*
* This class has two states:
* - None : Not ready
* - Initialized : Ready to process data
*
* General usage of this class is as follows:
* - Initialize CBC state with @ref initialize().
* - Encrypt or decrypt data using @ref encrypt() or @ref decrypt().
*/
template <class BlockCipher>
class CbcEncryptor
{
public:
static const size_t kKeySize = BlockCipher::kKeySize; /**< CBC mode key size. */
static const size_t kBlockSize = BlockCipher::kBlockSize; /**< CBC mode block processing size. */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
CbcEncryptor() :
mImpl()
{}
/**
* @brief Initializes the CBC encryption state.
*
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p key_size == @ref kKeySize.
* - @p iv_size == @ref kBlockSize.
*
* @post
* - Instance is now in a Initialized state.
*
* @details
* This resets the CBC state, initializing the key schedule and initialization vector.
*
* @note
* - This must be called before performing encryption/decryption.
*
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal kBlockSize.
*/
void initialize(const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
mImpl.initialize(key, key_size, iv, iv_size);
}
/**
* @brief Updates the CBC initialization vector.
*
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p iv_size == @ref kBlockSize.
* - Instance is in a Initialized state.
*
* @post
* - Initialization vector is updated.
*
* @details
* This updates the CBC state, initializing the initialization vector. The intended use is when data is encrypted/decrypted out of order, so the initialization vector needs to be updated manually.
*
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal kBlockSize.
*/
void update_iv(const byte_t* iv, size_t iv_size)
{
mImpl.update_iv(iv, iv_size);
}
/**
* @brief Encrypt data.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
*
* @pre
* - @p size is a multiple of @ref kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size size was not a multiple of @ref kBlockSize.
*/
void encrypt(byte_t* dst, const byte_t* src, size_t size)
{
mImpl.encrypt(dst, src, size);
}
/**
* @brief Decrypt data.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
*
* @pre
* - @p size is a multiple of @ref kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size size was not a multiple of @ref kBlockSize.
*/
void decrypt(byte_t* dst, const byte_t* src, size_t size)
{
mImpl.decrypt(dst, src, size);
}
private:
detail::CbcModeImpl<BlockCipher> mImpl;
};
}} // namespace tc::crypto
+57
View File
@@ -0,0 +1,57 @@
/**
* @file CryptoException.h
* @brief Declaration of tc::crypto::CryptoException
* @author Jack (jakcron)
* @version 0.1
* @date 2020/01/22
**/
#pragma once
#include <tc/Exception.h>
namespace tc { namespace crypto {
/**
* @class CryptoException
* @brief The exception that is thrown when an cryptography error occurs.
**/
class CryptoException : public tc::Exception
{
public:
/// Default Constructor
CryptoException() noexcept :
tc::Exception()
{
}
/**
* @brief Basic Parameterized Constructor
*
* @param[in] what Explanation for exception
*
* @post
* - what() == what
* - module() == ""
* - error() == what
**/
CryptoException(const std::string& what) noexcept :
tc::Exception(what)
{}
/**
* @brief Parameterized Constructor
*
* @param[in] module Name of module that threw the exception
* @param[in] what Explanation for exception
*
* @post
* - what() == "[" + module + " ERROR] " + what
* - module() == module
* - error() == what
**/
CryptoException(const std::string& module, const std::string& what) noexcept :
tc::Exception(module, what)
{
}
};
}} // namespace tc::crypto
+154
View File
@@ -0,0 +1,154 @@
/**
* @file CtrEncryptor.h
* @brief Declaration of tc::crypto::CtrEncryptor
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/CtrModeImpl.h>
namespace tc { namespace crypto {
/**
* @class CtrEncryptor
* @brief Class for CTR mode encryption/decryption.
*
* @tparam BlockCipher The class that implements the block cipher used for CTR mode encryption/decryption.
*
* @details
* Counter (CTR) mode encrypts blocks of data independently (and uniquely) of each other, acting as a psuedo stream cipher. Random access supported by CTR mode.
* Encryption and decryption operations are identical.
*
* This class is a template class that takes a block cipher implementation class as template parameter.
* See @ref Aes128CtrEncryptor or similar for supplied realizations of this template class.
*
* The implementation of @a BlockCipher must satisfies the following conditions.
* See @ref AesEncryptor or similar class, for more information including parameters to each function.
*
* -# Has a @p kBlockSize constant that defines the size of the block to process.
* -# Has a @p kKeySize constant that defines the required key size to initialize the block cipher.
* -# Has an @p initialize method that initializes the state of the block cipher.
* -# Has an @p encrypt method that encrypts a block of input data.
* -# Has a @p decrypt method that decrypts a block of input data.
*
* This class has two states:
* - None : Not ready
* - Initialized : Ready to process data
*
* General usage of this class is as follows:
* - Initialize CTR state with @ref initialize().
* - Encrypt or decrypt data using @ref encrypt() or @ref decrypt().
*/
template <class BlockCipher>
class CtrEncryptor
{
public:
static const size_t kKeySize = BlockCipher::kKeySize; /**< CTR mode key size. */
static const size_t kBlockSize = BlockCipher::kBlockSize; /**< CTR mode block processing size. */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
CtrEncryptor() :
mImpl()
{}
/**
* @brief Initializes the CTR encryption state.
*
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
* @param[in] iv Pointer to initialization vector.
* @param[in] iv_size Size in bytes of initialization vector.
*
* @pre
* - @p key_size == @ref kKeySize.
* - @p iv_size == @ref kBlockSize.
*
* @post
* - Instance is now in a Initialized state.
*
* @details
* This resets the CTR state, initializing the key schedule and initialization vector.
*
* @note
* - This must be called before performing encryption/decryption.
*
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal kKeySize.
* @throw tc::ArgumentNullException @p iv was null.
* @throw tc::ArgumentOutOfRangeException @p iv_size did not equal kBlockSize.
*/
void initialize(const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
mImpl.initialize(key, key_size, iv, iv_size);
}
/**
* @brief Encrypt data.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] block_number Block number of initial block to encrypt.
*
* @pre
* - @p size > 0.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size size was 0.
*/
void encrypt(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number)
{
mImpl.crypt(dst, src, size, block_number);
}
/**
* @brief Decrypt data.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] block_number Block number of initial block to encrypt.
*
* @pre
* - @p size > 0.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size size was 0.
*/
void decrypt(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number)
{
mImpl.crypt(dst, src, size, block_number);
}
private:
detail::CtrModeImpl<BlockCipher> mImpl;
};
}} // namespace tc::crypto
+146
View File
@@ -0,0 +1,146 @@
/**
* @file EcbEncryptor.h
* @brief Declaration of tc::crypto::EcbEncryptor
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/EcbModeImpl.h>
namespace tc { namespace crypto {
/**
* @class EcbEncryptor
* @brief Class for ECB mode encryption/decryption.
*
* @tparam BlockCipher The class that implements the block cipher used for ECB mode encryption/decryption.
*
* @details
* Electronic Codebook (ECB) mode is akin to using a block cipher in raw mode.
*
* This class is a template class that takes a block cipher implementation class as template parameter.
* See @ref Aes128EcbEncryptor or similar for supplied realizations of this template class.
*
* The implementation of @a BlockCipher must satisfies the following conditions.
* See @ref AesEncryptor or similar class, for more information including parameters to each function.
*
* -# Has a @p kBlockSize constant that defines the size of the block to process.
* -# Has a @p kKeySize constant that defines the required key size to initialize the block cipher.
* -# Has an @p initialize method that initializes the state of the block cipher.
* -# Has an @p encrypt method that encrypts a block of input data.
* -# Has a @p decrypt method that decrypts a block of input data.
*
* This class has two states:
* - None : Not ready
* - Initialized : Ready to process data
*
* General usage of this class is as follows:
* - Initialize ECB state with @ref initialize().
* - Encrypt or decrypt data using @ref encrypt() or @ref decrypt().
*/
template <class BlockCipher>
class EcbEncryptor
{
public:
static const size_t kKeySize = BlockCipher::kKeySize; /**< ECB mode key size. */
static const size_t kBlockSize = BlockCipher::kBlockSize; /**< ECB mode block processing size. */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
EcbEncryptor() :
mImpl()
{}
/**
* @brief Initializes the ECB encryption state.
*
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - @p key_size == @ref kKeySize.
*
* @post
* - Instance is now in a Initialized state.
*
* @details
* This resets the ECB state, initializing the key schedule.
*
* @note
* - This must be called before performing encryption/decryption.
*
* @throw tc::ArgumentNullException @p key was null.
* @throw tc::ArgumentOutOfRangeException @p key_size did not equal kKeySize.
*/
void initialize(const byte_t* key, size_t key_size)
{
mImpl.initialize(key, key_size);
}
/**
* @brief Encrypt data.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
*
* @pre
* - @p size >= @ref kBlockSize.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref kBlockSize.
*/
void encrypt(byte_t* dst, const byte_t* src, size_t size)
{
mImpl.encrypt(dst, src, size);
}
/**
* @brief Decrypt data.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
*
* @pre
* - @p size >= @ref kBlockSize.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was less than @ref kBlockSize.
*/
void decrypt(byte_t* dst, const byte_t* src, size_t size)
{
mImpl.decrypt(dst, src, size);
}
private:
detail::EcbModeImpl<BlockCipher> mImpl;
};
}} // namespace tc::crypto
+219
View File
@@ -0,0 +1,219 @@
/**
* @file HmacGenerator.h
* @brief Declaration of tc::crypto::HmacGenerator
* @author Jack (jakcron)
* @version 0.1
* @date 2020/05/30
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/HmacImpl.h>
namespace tc { namespace crypto {
/**
* @class HmacGenerator
* @brief Class for calculating an HMAC.
*
* @tparam HashFunction The class that implements the hash function for generating HMAC.
*
* @details
* This class is a template class that takes a hash function implementation class as template parameter.
* See @ref HmacSha256Generator or similar for supplied realizations of this template class.
*
* The implementation of <var>HashFunction</var> must satisfies the following conditions.
* See @ref Sha256Generator or similar class, for more information including parameters to each function.
*
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
* -# Has a <tt>kHashSize</tt> constant that defines the output size of the hash value.
* -# Has an <tt>initialize</tt> method that begins processing.
* -# Has an <tt>update</tt> method that updates the hash value on input.
* -# Has a <tt>getHash</tt> method that gets the final hash value.
*
* This class has three states:
* - None : Not ready
* - Initialized : Ready to process input data
* - Done : MAC is calculated
*
* General usage of this class is as follows:
* - Initialize MAC Generator state with @ref initialize().
* - Update MAC with input data with @ref update().
* - Complete MAC calculation and export MAC with @ref getMac().
*
* Below is code sample for calculating MAC with one call to @ref update():
* @code
* std::string key = "i am an hmac key";
*
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create array to store MAC
* std::array<byte_t, tc::crypto::HmacGenerator<HashFunction>::kMacSize> mac;
*
* // initialize generator. HmacGenerator<HashFunction> is now in a ready state.
* tc::crypto::HmacGenerator<HashFunction> impl;
* impl.initialize((const byte_t*)key.c_str(), key.size());
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // read whole file into memory. This is unsafe for large file sizes especially on 32-bit systems.
* tc::ByteData data = tc::ByteData((size_t)stream.length());
* stream.read(data.data(), data.size());
*
* // update generator state with stream data
* impl.update(data.data(), data.size());
*
* // complete generator state and write MAC to mac
* impl.getMac(mac.data());
* @endcode
*
* Below is code sample for calculating MAC with sequential calls to @ref update():
* @code
* std::string key = "i am an hmac key";
*
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create read block (size 512)
* static const size_t kReadBlockSize = 0x200;
* std::array<byte_t, kReadBlockSize> block;
*
* // create array to store MAC
* std::array<byte_t, tc::crypto::HmacGenerator<HashFunction>::kMacSize> mac;
*
* // initialize generator. HmacGenerator<HashFunction> is now in a ready state.
* tc::crypto::HmacGenerator<HashFunction> impl;
* impl.initialize((const byte_t*)key.c_str(), key.size());
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // iterate over blocks in stream until no more data can be read
* size_t read_count = 0;
* while ( 0 != (read_count = tc::io::IOUtil::getReadableCount(stream.position(), stream.length(), block.size())) )
* {
* // read block from stream
* stream.read(block.data(), read_count);
*
* // update generator state with stream data
* impl.update(block.data(), read_count);
* }
*
* // complete generator state and write MAC to mac
* impl.getMac(mac.data());
* @endcode
*/
template <class HashFunction>
class HmacGenerator
{
public:
static const size_t kMacSize = HashFunction::kHashSize; /**< HMAC MAC size */
static const size_t kBlockSize = HashFunction::kBlockSize; /**< HMAC block processing size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
HmacGenerator() :
mImpl()
{}
/**
* @brief Initializes the MAC calculation.
*
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the MAC calculation state to the begin state.
*
* @note
* - This must be called before calculating a new MAC.
*/
void initialize(const byte_t* key, size_t key_size)
{
mImpl.initialize(key, key_size);
}
/**
* @brief Update MAC with specified data.
*
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @details
* Data can be input to the generator in one @ref update() call or split across multiple sequential calls.
*
* For example the following scenarios all generate the same MAC.
* @code
* std::string key = "i am an hmac key";
*
* // generate data to be calculate MAC from
* tc::ByteData data = tc::ByteData(0x30);
* memset(data.data(), 0xff, data.size());
*
* // create generator instance
* tc::crypto::HmacGenerator<HashFunction> impl;
*
* // scenario 1 (one call to update() 0x30 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::HmacGenerator<HashFunction>::kMacSize> mac1;
* impl.initialize((const byte_t*)key.c_str(), key.size());
* impl.update(data.data(), data.size());
* impl.getMac(mac1.data());
*
* // scenario 2 (three calls to update() 0x10 bytes each, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::HmacGenerator<HashFunction>::kMacSize> mac2;
* impl.initialize((const byte_t*)key.c_str(), key.size());
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x10);
* impl.update(data.data() + 0x20, 0x10);
* impl.getMac(mac2.data());
*
* // scenario 3 (two calls to update() one 0x10 bytes, the second 0x20 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::HmacGenerator<HashFunction>::kMacSize> mac3;
* impl.initialize((const byte_t*)key.c_str(), key.size());
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x20);
* impl.getMac(mac3.data());
* @endcode
*
* @note
* - If input data is broken up into blocks and supplied via multiple @ref update() calls, the order must be consistent with the original input data.
*/
void update(const byte_t* data, size_t data_size)
{
mImpl.update(data, data_size);
}
/**
* @brief Completes MAC calculation and output MAC.
*
* @param[out] mac Pointer to buffer storing MAC.
*
* @pre
* - Instance is in either Initialized or Done state.
* - The size of the <tt><var>mac</var></tt> buffer must be >= @ref kMacSize.
*
* @post
* - Instance is now in a Done state.
* - The calculated MAC is written to <tt><var>mac</var></tt>.
*
* @note
* - If the instance is in a None state, then this call does nothing.
*/
void getMac(byte_t* mac)
{
mImpl.getMac(mac);
}
private:
detail::HmacImpl<HashFunction> mImpl;
};
}} // namespace tc::crypto
+45
View File
@@ -0,0 +1,45 @@
/**
* @file HmacMd5Generator.h
* @brief Declarations for API resources for HMAC-MD5 calculations.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Md5Generator.h>
#include <tc/crypto/HmacGenerator.h>
namespace tc { namespace crypto {
/**
* @typedef HmacMd5Generator
* @brief Class for calculating HMAC-MD5.
*
* @details This class calcualtes MAC using MD5.
* For more information refer to @ref HmacGenerator.
*/
using HmacMd5Generator = HmacGenerator<Md5Generator>;
/**
* @brief Utility function for calculating HMAC-MD5.
*
* @param[out] mac Pointer to the buffer storing the MAC.
* @param[in] data Pointer to input data.
* @param[in] data_size Size in bytes of input data.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - Size of the MAC buffer must >= <tt>HmacMd5Generator::kMacSize</tt>.
*
* @post
* - The MAC is written to <tt><var>mac</var></tt>.
*
* @details
* This function calculates a MAC for the passed in data array.
* To calculate a MAC for data split into multiple arrays, use the @ref HmacMd5Generator class.
*/
void GenerateHmacMd5Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size);
}} // namespace tc::crypto
+45
View File
@@ -0,0 +1,45 @@
/**
* @file HmacSha1Generator.h
* @brief Declarations for API resources for HMAC-SHA1 calculations.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/05/30
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha1Generator.h>
#include <tc/crypto/HmacGenerator.h>
namespace tc { namespace crypto {
/**
* @typedef HmacSha1Generator
* @brief Class for calculating HMAC-SHA1.
*
* @details This class calcualtes MAC using SHA1.
* For more information refer to @ref HmacGenerator.
*/
using HmacSha1Generator = HmacGenerator<Sha1Generator>;
/**
* @brief Utility function for calculating HMAC-SHA1.
*
* @param[out] mac Pointer to the buffer storing the MAC.
* @param[in] data Pointer to input data.
* @param[in] data_size Size in bytes of input data.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - Size of the MAC buffer must >= <tt>HmacSha1Generator::kMacSize</tt>.
*
* @post
* - The MAC is written to <tt><var>mac</var></tt>.
*
* @details
* This function calculates a MAC for the passed in data array.
* To calculate a MAC for data split into multiple arrays, use the @ref HmacSha1Generator class.
*/
void GenerateHmacSha1Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size);
}} // namespace tc::crypto
@@ -0,0 +1,45 @@
/**
* @file HmacSha256Generator.h
* @brief Declarations for API resources for HMAC-SHA2-256 calculations.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha256Generator.h>
#include <tc/crypto/HmacGenerator.h>
namespace tc { namespace crypto {
/**
* @typedef HmacSha256Generator
* @brief Class for calculating HMAC-SHA2-256.
*
* @details This class calcualtes MAC using SHA2-256.
* For more information refer to @ref HmacGenerator.
*/
using HmacSha256Generator = HmacGenerator<Sha256Generator>;
/**
* @brief Utility function for calculating HMAC-SHA2-256.
*
* @param[out] mac Pointer to the buffer storing the MAC.
* @param[in] data Pointer to input data.
* @param[in] data_size Size in bytes of input data.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - Size of the MAC buffer must >= <tt>HmacSha256Generator::kMacSize</tt>.
*
* @post
* - The MAC is written to <tt><var>mac</var></tt>.
*
* @details
* This function calculates a MAC for the passed in data array.
* To calculate a MAC for data split into multiple arrays, use the @ref HmacSha256Generator class.
*/
void GenerateHmacSha256Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size);
}} // namespace tc::crypto
@@ -0,0 +1,45 @@
/**
* @file HmacSha512Generator.h
* @brief Declarations for API resources for HMAC-SHA2-512 calculations.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha512Generator.h>
#include <tc/crypto/HmacGenerator.h>
namespace tc { namespace crypto {
/**
* @typedef HmacSha512Generator
* @brief Class for calculating HMAC-SHA2-512.
*
* @details This class calcualtes MAC using SHA2-512.
* For more information refer to @ref HmacGenerator.
*/
using HmacSha512Generator = HmacGenerator<Sha512Generator>;
/**
* @brief Utility function for calculating HMAC-SHA2-512.
*
* @param[out] mac Pointer to the buffer storing the MAC.
* @param[in] data Pointer to input data.
* @param[in] data_size Size in bytes of input data.
* @param[in] key Pointer to key data.
* @param[in] key_size Size in bytes of key data.
*
* @pre
* - Size of the MAC buffer must >= <tt>HmacSha512Generator::kMacSize</tt>.
*
* @post
* - The MAC is written to <tt><var>mac</var></tt>.
*
* @details
* This function calculates a MAC for the passed in data array.
* To calculate a MAC for data split into multiple arrays, use the @ref HmacSha512Generator class.
*/
void GenerateHmacSha512Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size);
}} // namespace tc::crypto
+221
View File
@@ -0,0 +1,221 @@
/**
* @file Md5Generator.h
* @brief Declarations for API resources for MD5 calculations.
* @author Jack (jakcron)
* @version 0.2
* @date 2020/06/01
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/Md5Impl.h>
namespace tc { namespace crypto {
/**
* @class Md5Generator
* @brief Class for calculating MD5 hash.
*
* @warning MD5 is considered a weak message digest and its use constitutes a security risk. It should only be used to maintain compatibility with legacy systems.
*
* @details
* This class has three states:
* - None : Not ready
* - Initialized : Ready to process input data
* - Done : Hash value is calculated
*
* General usage of this class is as follows:
* - Initialize Hash Generator state with @ref initialize().
* - Update hash value with input data with @ref update().
* - Complete hash calculation and export hash value with @ref getHash().
*
* Below is code sample for calculating hash value with one call to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Md5Generator::kHashSize> hash;
*
* // initialize generator. Md5Generator is now in a ready state.
* tc::crypto::Md5Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // read whole file into memory. This is unsafe for large file sizes especially on 32-bit systems.
* tc::ByteData data = tc::ByteData((size_t)stream.length());
* stream.read(data.data(), data.size());
*
* // update generator state with stream data
* impl.update(data.data(), data.size());
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*
* Below is code sample for calculating hash value with sequential calls to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create read block (size 512)
* static const size_t kReadBlockSize = 0x200;
* std::array<byte_t, kReadBlockSize> block;
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Md5Generator::kHashSize> hash;
*
* // initialize generator. Md5Generator is now in a ready state.
* tc::crypto::Md5Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // iterate over blocks in stream until no more data can be read
* size_t read_count = 0;
* while ( 0 != (read_count = tc::io::IOUtil::getReadableCount(stream.position(), stream.length(), block.size())) )
* {
* // read block from stream
* stream.read(block.data(), read_count);
*
* // update generator state with stream data
* impl.update(block.data(), read_count);
* }
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*/
class Md5Generator
{
public:
static const size_t kAsn1OidDataSize = 18; /**< MD5 ASN.1 Encoded OID length */
static const std::array<byte_t, kAsn1OidDataSize> kAsn1OidData; /**< MD5 ASN.1 Encoded OID */
static const size_t kHashSize = 16; /**< MD5 hash size */
static const size_t kBlockSize = 64; /**< MD5 processing block size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
Md5Generator() :
mImpl()
{}
/**
* @brief Initializes the hash calculation.
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the hash calculation state to the begin state.
*
* @note
* - This must be called before calculating a new hash.
*/
void initialize()
{
mImpl.initialize();
}
/**
* @brief Update hash value with specified data.
*
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @details
* Data can be input to the generator in one @ref update() call or split across multiple sequential calls.
*
* For example the following scenarios all generate the same hash value.
* @code
* // generate data to be hashed
* tc::ByteData data = tc::ByteData(0x30);
* memset(data.data(), 0xff, data.size());
*
* // create generator instance
* tc::crypto::Md5Generator impl;
*
* // scenario 1 (one call to update() 0x30 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Md5Generator::kHashSize> hash1;
* impl.initialize();
* impl.update(data.data(), data.size());
* impl.getHash(hash1.data());
*
* // scenario 2 (three calls to update() 0x10 bytes each, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Md5Generator::kHashSize> hash2;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x10);
* impl.update(data.data() + 0x20, 0x10);
* impl.getHash(hash2.data());
*
* // scenario 3 (two calls to update() one 0x10 bytes, the second 0x20 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Md5Generator::kHashSize> hash3;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x20);
* impl.getHash(hash3.data());
* @endcode
*
* @note
* - If input data is broken up into blocks and supplied via multiple @ref update() calls, the order must be consistent with the original input data.
*/
void update(const byte_t* data, size_t data_size)
{
mImpl.update(data, data_size);
}
/**
* @brief Completes hash calculation and output hash value.
*
* @param[out] hash Pointer to buffer storing hash value.
*
* @pre
* - Instance is in either Initialized or Done state.
* - The size of the <tt><var>hash</var></tt> buffer must be >= @ref kHashSize.
*
* @post
* - Instance is now in a Done state.
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @note
* - If the instance is in a None state, then this call does nothing.
*/
void getHash(byte_t* hash)
{
mImpl.getHash(hash);
}
private:
detail::Md5Impl mImpl;
};
/**
* @brief Utility function for calculating the MD5 hash.
*
* @warning MD5 is considered a weak message digest and its use constitutes a security risk. It should only be used to maintain compatibility with legacy systems.
*
* @param[out] hash Pointer to buffer storing hash value.
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @pre
* - The size of the <tt><var>hash</var></tt> buffer must be >= @ref Md5Generator::kHashSize.
*
* @post
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @details
* This function calculates the hash value for input passed in the <tt><var>data</var></tt> array.
* To calculate the hash value for input split across multiple arrays, use the @ref Md5Generator class.
*/
void GenerateMd5Hash(byte_t* hash, const byte_t* data, size_t data_size);
}} // namespace tc::crypto
+116
View File
@@ -0,0 +1,116 @@
/**
* @file Pbkdf1KeyDeriver.h
* @brief Declaration of tc::crypto::Pbkdf1KeyDeriver
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/Pbkdf1Impl.h>
namespace tc { namespace crypto {
/**
* @class Pbkdf1KeyDeriver
* @brief Class for deriving a key using 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.
* As such this template class requires @p HashFunction to implement one of the following hash functions to be compliant with RFC 8018.
* -# MD4
* -# MD5 (see @ref Md5Generator)
* -# SHA-1 (see @ref Sha1Generator)
*
* The implementation of <var>HashFunction</var> must satisfies the following conditions.
* See @ref Sha1Generator or similar class, for more information including parameters to each function.
*
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
* -# Has a <tt>kHashSize</tt> constant that defines the output size of the hash value.
* -# Has an <tt>initialize</tt> method that begins processing.
* -# Has an <tt>update</tt> method that updates the hash value on input.
* -# Has a <tt>getHash</tt> method that gets the final hash value.
*
* This class has three states:
* - None : Not ready
* - Initialized : Ready to derive key data
*
* General usage of this class is as follows:
* - Initialize PBKDF1 calculation with @ref initialize().
* - Derive key data with @ref getBytes().
*/
template <class HashFunction>
class Pbkdf1KeyDeriver
{
public:
static const uint64_t kMaxDerivableSize = HashFunction::kHashSize; /**< Maximum total key data that can be derived */
/**
* @brief Default constructor
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
Pbkdf1KeyDeriver() :
mImpl()
{}
/**
* @brief Initializes the PBKDF1 calculation.
*
* @param[in] password Pointer to password.
* @param[in] password_size Size in bytes of password.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size in bytes of salt.
* @param[in] n_rounds Number of PBKDF1 rounds.
*
* @pre
* - @p n_rounds >= 1
* - @p salt is optional however the strength of the derived key is reduced if the salt is not sufficently random.
*
* @post
* - Instance is now in an Initialized state.
*
* @throw tc::crypto::CryptoException @p n_rounds was < 1
*
* @details
* Resets the PBKDF1 calculation state to the begin state.
*
* @note
* - This must be called before deriving new key data.
*/
void initialize(const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
{
mImpl.initialize(password, password_size, salt, salt_size, n_rounds);
}
/**
* @brief Performs PBKDF1 calculation, deriving key data.
*
* @param[out] key Pointer to the buffer storing the derived key.
* @param[in] key_size Size of key to derive.
*
* @pre
* - Instance is in an Initialized state.
*
* @post
* - The derived key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::CryptoException @p key_size was too large.
*
* @note
* - This method can be called successively to continue deriving key data for up to @ref kMaxDerivableSize bytes.
* - If the instance is in a None state, then this call does nothing.
*/
void getBytes(byte_t* key, size_t key_size)
{
mImpl.getBytes(key, key_size);
}
private:
detail::Pbkdf1Impl<HashFunction> mImpl;
};
}} // namespace tc::crypto
@@ -0,0 +1,47 @@
/**
* @file Pbkdf1Md5KeyDeriver.h
* @brief Declarations for API resources for PBKDF1-MD5 key derivation.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Md5Generator.h>
#include <tc/crypto/Pbkdf1KeyDeriver.h>
namespace tc { namespace crypto {
/**
* @typedef Pbkdf1Md5KeyDeriver
* @brief Class for deriving a key using PBKDF1-MD5.
*
* @details This class derives a key using PBKDF1-MD5.
* For more information refer to @ref Pbkdf1KeyDeriver.
*/
using Pbkdf1Md5KeyDeriver = Pbkdf1KeyDeriver<Md5Generator>;
/**
* @brief Utility function for deriving a key using PBKDF1-MD5.
*
* @param[out] key Pointer to the buffer storing the derived key.
* @param[in] key_size Size of key to derive.
* @param[in] password Pointer to password.
* @param[in] password_size Size in bytes of password.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size in bytes of salt.
* @param[in] n_rounds Number of PBKDF1 rounds.
*
* @pre
* - @p n_rounds >= 1
* - @p salt is optional however the strength of the derived key is reduced if the salt is not sufficently random.
*
* @post
* - The derived key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::CryptoException @p n_rounds was < 1
* @throw tc::crypto::CryptoException @p key_size was too large.
*/
void DeriveKeyPbkdf1Md5(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds);
}} // namespace tc::crypto
@@ -0,0 +1,47 @@
/**
* @file Pbkdf1Sha1KeyDeriver.h
* @brief Declarations for API resources for PBKDF1-SHA1 key derivation.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha1Generator.h>
#include <tc/crypto/Pbkdf1KeyDeriver.h>
namespace tc { namespace crypto {
/**
* @typedef Pbkdf1Sha1KeyDeriver
* @brief Class for deriving a key using PBKDF1-SHA1.
*
* @details This class derives a key using PBKDF1-SHA1.
* For more information refer to @ref Pbkdf1KeyDeriver.
*/
using Pbkdf1Sha1KeyDeriver = Pbkdf1KeyDeriver<Sha1Generator>;
/**
* @brief Utility function for deriving a key using PBKDF1-SHA1.
*
* @param[out] key Pointer to the buffer storing the derived key.
* @param[in] key_size Size of key to derive.
* @param[in] password Pointer to password.
* @param[in] password_size Size in bytes of password.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size in bytes of salt.
* @param[in] n_rounds Number of PBKDF1 rounds.
*
* @pre
* - @p n_round >= 1
* - @p salt is optional however the strength of the derived key is reduced if the salt is not sufficently random.
*
* @post
* - The derived key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::CryptoException @p n_round was < 1
* @throw tc::crypto::CryptoException @p key_size was too large.
*/
void DeriveKeyPbkdf1Sha1(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds);
}} // namespace tc::crypto
+118
View File
@@ -0,0 +1,118 @@
/**
* @file Pbkdf2KeyDeriver.h
* @brief Declaration of tc::crypto::Pbkdf2KeyDeriver
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/Pbkdf2Impl.h>
namespace tc { namespace crypto {
/**
* @class Pbkdf2KeyDeriver
* @brief Class for deriving a key using 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.
* As such this template class requires @p HashFunction to implement one of the following hash functions to be compliant with RFC 8018.
* -# SHA-1 (see @ref Sha1Generator)
* -# SHA-224
* -# SHA-256 (see @ref Sha256Generator)
* -# SHA-384
* -# SHA-512 (see @ref Sha512Generator)
*
* The implementation of <var>HashFunction</var> must satisfies the following conditions.
* See @ref Sha256Generator or similar class, for more information including parameters to each function.
*
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
* -# Has a <tt>kHashSize</tt> constant that defines the output size of the hash value.
* -# Has an <tt>initialize</tt> method that begins processing.
* -# Has an <tt>update</tt> method that updates the hash value on input.
* -# Has a <tt>getHash</tt> method that gets the final hash value.
*
* This class has three states:
* - None : Not ready
* - Initialized : Ready to derive key data
*
* General usage of this class is as follows:
* - Initialize PBKDF2 calculation with @ref initialize().
* - Derive key data with @ref getBytes().
*/
template <class HashFunction>
class Pbkdf2KeyDeriver
{
public:
static const uint64_t kMaxDerivableSize = uint64_t(0xffffffff) * uint64_t(HashFunction::kHashSize); /**< Maximum total key data that can be derived */
/**
* @brief Default constructor
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
Pbkdf2KeyDeriver() :
mImpl()
{}
/**
* @brief Initializes the PBKDF2 calculation.
*
* @param[in] password Pointer to password.
* @param[in] password_size Size in bytes of password.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size in bytes of salt.
* @param[in] n_rounds Number of PBKDF2 rounds.
*
* @pre
* - @p n_rounds >= 1.
* - @p salt is optional however the strength of the derived key is reduced if the salt is not sufficently random.
*
* @post
* - Instance is now in an Initialized state.
*
* @throw tc::crypto::CryptoException @p n_rounds was < 1.
*
* @details
* Resets the PBKDF2 calculation state to the begin state.
*
* @note
* - This must be called before deriving new key data.
*/
void initialize(const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
{
mImpl.initialize(password, password_size, salt, salt_size, n_rounds);
}
/**
* @brief Performs PBKDF2 calculation, deriving key data.
*
* @param[out] key Pointer to the buffer storing the derived key.
* @param[in] key_size Size of key to derive.
*
* @pre
* - Instance is in an Initialized state.
*
* @post
* - The derived key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::CryptoException @p key_size was too large.
*
* @note
* - This method can be called successively to continue deriving key data for up to @ref kMaxDerivableSize bytes.
* - If the instance is in a None state, then this call does nothing.
*/
void getBytes(byte_t* key, size_t key_size)
{
mImpl.getBytes(key, key_size);
}
private:
detail::Pbkdf2Impl<HashFunction> mImpl;
};
}} // namespace tc::crypto
@@ -0,0 +1,47 @@
/**
* @file Pbkdf2Sha1KeyDeriver.h
* @brief Declarations for API resources for PBKDF2-SHA1 key derivation.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha1Generator.h>
#include <tc/crypto/Pbkdf2KeyDeriver.h>
namespace tc { namespace crypto {
/**
* @typedef Pbkdf2Sha1KeyDeriver
* @brief Class for deriving a key using PBKDF2-SHA1.
*
* @details This class derives a key using PBKDF2-SHA1.
* For more information refer to @ref Pbkdf2KeyDeriver.
*/
using Pbkdf2Sha1KeyDeriver = Pbkdf2KeyDeriver<Sha1Generator>;
/**
* @brief Utility function for deriving a key using PBKDF2-SHA1.
*
* @param[out] key Pointer to the buffer storing the derived key.
* @param[in] key_size Size of key to derive.
* @param[in] password Pointer to password.
* @param[in] password_size Size in bytes of password.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size in bytes of salt.
* @param[in] n_rounds Number of PBKDF2 rounds.
*
* @pre
* - @p n_rounds >= 1
* - @p salt is optional however the strength of the derived key is reduced if the salt is not sufficently random.
*
* @post
* - The derived key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::CryptoException @p n_rounds was < 1.
* @throw tc::crypto::CryptoException @p key_size was too large.
*/
void DeriveKeyPbkdf2Sha1(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds);
}} // namespace tc::crypto
@@ -0,0 +1,47 @@
/**
* @file Pbkdf2Sha256KeyDeriver.h
* @brief Declarations for API resources for PBKDF2-SHA2-256 key derivation.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha256Generator.h>
#include <tc/crypto/Pbkdf2KeyDeriver.h>
namespace tc { namespace crypto {
/**
* @typedef Pbkdf2Sha256KeyDeriver
* @brief Class for deriving a key using PBKDF2-SHA2-256.
*
* @details This class derives a key using PBKDF2-SHA2-256.
* For more information refer to @ref Pbkdf2KeyDeriver.
*/
using Pbkdf2Sha256KeyDeriver = Pbkdf2KeyDeriver<Sha256Generator>;
/**
* @brief Utility function for deriving a key using PBKDF2-SHA2-256.
*
* @param[out] key Pointer to the buffer storing the derived key.
* @param[in] key_size Size of key to derive.
* @param[in] password Pointer to password.
* @param[in] password_size Size in bytes of password.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size in bytes of salt.
* @param[in] n_rounds Number of PBKDF2 rounds.
*
* @pre
* - @p n_rounds >= 1.
* - @p salt is optional however the strength of the derived key is reduced if the salt is not sufficently random.
*
* @post
* - The derived key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::CryptoException @p n_rounds was < 1.
* @throw tc::crypto::CryptoException @p key_size was too large.
*/
void DeriveKeyPbkdf2Sha256(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds);
}} // namespace tc::crypto
@@ -0,0 +1,47 @@
/**
* @file Pbkdf2Sha512KeyDeriver.h
* @brief Declarations for API resources for PBKDF2-SHA2-512 key derivation.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/06
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha512Generator.h>
#include <tc/crypto/Pbkdf2KeyDeriver.h>
namespace tc { namespace crypto {
/**
* @typedef Pbkdf2Sha512KeyDeriver
* @brief Class for deriving a key using PBKDF2-SHA2-512.
*
* @details This class derives a key using PBKDF2-SHA2-512.
* For more information refer to @ref Pbkdf2KeyDeriver.
*/
using Pbkdf2Sha512KeyDeriver = Pbkdf2KeyDeriver<Sha512Generator>;
/**
* @brief Utility function for deriving a key using PBKDF2-SHA2-512.
*
* @param[out] key Pointer to the buffer storing the derived key.
* @param[in] key_size Size of key to derive.
* @param[in] password Pointer to password.
* @param[in] password_size Size in bytes of password.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size in bytes of salt.
* @param[in] n_rounds Number of PBKDF2 rounds.
*
* @pre
* - @p n_rounds >= 1.
* - @p salt is optional however the strength of the derived key is reduced if the salt is not sufficently random.
*
* @post
* - The derived key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::CryptoException @p n_rounds was < 1.
* @throw tc::crypto::CryptoException @p key_size was too large.
*/
void DeriveKeyPbkdf2Sha512(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds);
}} // namespace tc::crypto
@@ -0,0 +1,65 @@
/**
* @file PseudoRandomByteGenerator.h
* @brief Declarations for API resources for generating pseudo-random data.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/06/12
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/PrbgImpl.h>
namespace tc { namespace crypto {
/**
* @class PseudoRandomByteGenerator
* @brief Class for generating random data.
*
* @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 PseudoRandomByteGenerator
{
public:
/**
* @brief Default constructor.
*/
PseudoRandomByteGenerator() :
mImpl()
{}
/**
* @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)
{
mImpl.getBytes(data, data_size);
}
private:
detail::PrbgImpl mImpl;
};
/**
* @brief Utility function for generating pseudo-random data.
*
* @param[out] data Pointer to buffer storing pseudo-random data.
* @param[in] data_size Size of pseudo-random data to generate.
*
* @post
* - The generated pseudo-random data is written to <tt><var>data</var></tt>.
*/
void GeneratePseudoRandomBytes(byte_t* data, size_t data_size);
}} // namespace tc::crypto
+75
View File
@@ -0,0 +1,75 @@
/**
* @file RsaKey.h
* @brief Declarations for structures to store RSA keys.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/08/27
**/
#pragma once
#include <tc/types.h>
#include <tc/ByteData.h>
namespace tc { namespace crypto {
/**
* @struct RsaKey
* @brief Struct for storing a RSA key. For use with RSA calculations.
*/
struct RsaKey
{
tc::ByteData n; /**< Modulus */
tc::ByteData d; /**< Private exponent */
tc::ByteData e; /**< Public exponent */
};
/**
* @struct RsaPublicKey
* @brief This extends RsaKey, exposing a constructor to create a RSA public key from a modulus.
*/
struct RsaPublicKey : public RsaKey
{
/**
* @brief This constructs a @ref RsaKey from a modulus.
*
* @param[in] modulus Buffer containing big-endian modulus.
* @param[in] modulus_size Size in bytes of modulus.
*
* @pre @p modulus != nullptr
* @pre @p modulus_size != 0
*
* @details Supplying a public exponent is not required, as this is the same for all RSA keys and is initialized internally by this constructor.
*/
RsaPublicKey(const byte_t* modulus, size_t modulus_size);
};
/**
* @struct RsaPrivateKey
* @brief This extends RsaKey, exposing a constructor to create a RSA private key from a modulus and private exponent.
*/
struct RsaPrivateKey : public RsaKey
{
/**
* @brief This constructs a @ref RsaKey from a modulus and private exponent.
*
* @param[in] modulus Buffer containing big-endian modulus.
* @param[in] modulus_size Size in bytes of modulus.
* @param[in] private_exponent Buffer containing big-endian private exponent.
* @param[in] private_exponent_size Size in bytes of private exponent.
*
* @pre @p modulus != nullptr
* @pre @p modulus_size != 0
* @pre @p private_exponent != nullptr
* @pre @p private_exponent_size != 0
*/
RsaPrivateKey(const byte_t* modulus, size_t modulus_size, const byte_t* private_exponent, size_t private_exponent_size);
/**
* @brief Generate public key from this private key.
*
* @return RsaKey containing the public key.
*/
RsaKey getPublicKey();
};
}} // namespace tc::crypto
+71
View File
@@ -0,0 +1,71 @@
/**
* @file RsaKeyGenerator.h
* @brief Declarations for API resources for generating RSA keys.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/09/12
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/RsaKeyGeneratorImpl.h>
#include <tc/crypto/RsaKey.h>
namespace tc { namespace crypto {
/**
* @class RsaKeyGenerator
* @brief Class for generating RSA keys.
*
* @details
* The underlying PRNG algorithm is CTR_DBRG.
*/
class RsaKeyGenerator
{
public:
/**
* @brief Default constructor.
*/
RsaKeyGenerator() :
mImpl()
{}
/**
* @brief Generate an RSA key.
*
* @param[out] key Buffer to generated RSA key.
* @param[in] key_bit_size Size in bits of RSA key to generate.
*
* @post
* - The generated key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::ArgumentException @p key_bit_size was not a multiple of 8.
*/
void generateKey(RsaKey& key, size_t key_bit_size)
{
if (key_bit_size == 0 || (key_bit_size % 8) != 0) throw tc::ArgumentException("tc::crypto::RsaKeyGenerator::generateKey()", "key_bit_size was not a multiple of 8.");
key.n = tc::ByteData(key_bit_size/8);
key.d = tc::ByteData(key_bit_size/8);
key.e = tc::ByteData(4);
mImpl.generateKey(key_bit_size, key.n.data(), key.n.size(), nullptr, 0, nullptr, 0, key.d.data(), key.d.size(), key.e.data(), key.e.size());
}
private:
detail::RsaKeyGeneratorImpl mImpl;
};
/**
* @brief Utility function for generating an RSA key.
*
* @param[out] key Buffer to generated RSA key.
* @param[in] key_bit_size Size in bits of RSA key to generate.
*
* @post
* - The generated key is written to <tt><var>key</var></tt>.
*
* @throw tc::crypto::ArgumentException @p key_bit_size was not a multiple of 8.
*/
void GenerateRsaKey(RsaKey& key, size_t key_bit_size);
}} // namespace tc::crypto
+246
View File
@@ -0,0 +1,246 @@
/**
* @file RsaOaepEncryptor.h
* @brief Declaration of tc::crypto::RsaOaepEncryptor
* @author Jack (jakcron)
* @version 0.1
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/RsaImpl.h>
#include <tc/crypto/detail/PrbgImpl.h>
#include <tc/crypto/detail/RsaOaepPadding.h>
#include <tc/crypto/RsaKey.h>
namespace tc { namespace crypto {
/**
* @class RsaOaepEncryptor
* @brief Class for RSA-OAEP encryption/decryption.
*
* @tparam KeyBitSize RSA key size in bits.
* @tparam HashFunction The class that implements the hash function used with RSA-OAEP.
*
* @details
* This class is a template class that takes a key size and a hash function implementation class as template parameter.
* See @ref Rsa2048OaepSha256Encryptor or similar for supplied realizations of this template class.
*
* The <var>KeyBitSize</var> is the size in bits of the RSA key, this only supports key sizes aligned to 8 bits.
*
* The implementation of <var>HashFunction</var> must satisfies the following conditions.
* See @ref Sha256Generator or similar class, for more information including parameters to each function.
*
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
* -# Has a <tt>kHashSize</tt> constant that defines the output size of the hash value.
* -# Has an <tt>initialize</tt> method that begins processing.
* -# Has an <tt>update</tt> method that updates the hash value on input.
* -# Has a <tt>getHash</tt> method that gets the final hash value.
*
* This class has two states:
* - None : Not ready
* - Initialized : Ready to process input data
*
* General usage of this class is as follows:
* - Initialize RSA-OAEP Encryptor state with @ref initialize().
* - Encrypt/Decrypt message with @ref encrypt() / @ref decrypt().
*/
template <size_t KeyBitSize, class HashFunction>
class RsaOaepEncryptor
{
public:
static_assert((KeyBitSize % 8) == 0, "KeyBitSize must be 8 bit aligned.");
static const size_t kBlockSize = KeyBitSize >> 3; /**< RSA-OAEP block size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
RsaOaepEncryptor() :
mState(State::None),
mLabelDigest(HashFunction::kHashSize),
mRsaImpl(),
mPrbgImpl(),
mPadImpl()
{}
/**
* @brief Initializes the encryption state.
*
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the RSA calculation state with an RSA key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
*/
void initialize(const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false)
{
if (key.n.size() == 0 || (key.d.size() == 0 && key.e.size() == 0))
{
throw tc::ArgumentNullException("RsaOaepEncryptor::initialize()", "key does not have minimal required key-data.");
}
mRsaImpl.initialize(KeyBitSize, key.n.data(), key.n.size(), nullptr, 0, nullptr, 0, key.d.data(), key.d.size(), key.e.data(), key.e.size());
if (((label == nullptr) ^ (label_size == 0)))
{
throw tc::ArgumentNullException("RsaOaepEncryptor::initialize()", "label was null when label_size was non-zero or vice-versa.");
}
if (isLabelDigested == true)
{
if (label_size != HashFunction::kHashSize)
throw tc::ArgumentOutOfRangeException("RsaOaepEncryptor::initialize()", "predigested label must be the size of HashFunction::kHashSize.");
memcpy(mLabelDigest.data(), label, mLabelDigest.size());
}
else
{
HashFunction hash_impl;
hash_impl.initialize();
hash_impl.update(label, label_size);
hash_impl.getHash(mLabelDigest.data());
}
mState = State::Initialized;
}
/**
* @brief Encode and encrypt a message into an RSA-OAEP block.
*
* @param[out] block Pointer to the buffer storing the encrypted RSA block.
* @param[in] message Pointer to message.
* @param[in] message_size Size of message.
* @return true if encryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>RsaOaepEncryptor::kBlockSize</tt>.
* - The maximum size for @p message_size is <tt>RsaOaepEncryptor::kBlockSize</tt> - (2 * <tt>HashFunction::kHashSize</tt>) - 2.
*
* @post
* - The encrypted block is written to <tt><var>block</var></tt>.
*
* @details
* This method encrypts a message using RSA-OAEP, using an RSA public key.
* OAEP encoding uses a random seed, this overload of @ref encrypt() generates the seed internally. To manually specify the seed, please use the alternative @ref encrypt() method.
*/
bool encrypt(byte_t* block, const byte_t* message, size_t message_size)
{
if (mState != State::Initialized) { return false; }
std::array<byte_t, HashFunction::kHashSize> seed;
mPrbgImpl.getBytes(seed.data(), seed.size());
return encrypt(block, message, message_size, seed.data(), seed.size());
}
/**
* @brief Encode and encrypt a message into an RSA-OAEP block.
*
* @param[out] block Pointer to the buffer storing the encrypted RSA block.
* @param[in] message Pointer to message.
* @param[in] message_size Size of message.
* @param[in] seed Pointer to random seed.
* @param[in] seed_size Size of random seed.
* @return true if encryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>RsaOaepEncryptor::kBlockSize</tt>.
* - The maximum size for @p message_size is <tt>RsaOaepEncryptor::kBlockSize</tt> - (2 * <tt>HashFunction::kHashSize</tt>) - 2.
* - Size of the @p seed buffer must be == <tt>HashFunction::kHashSize</tt>.
* - The seed should be random or the security of the encryption is reduced.
*
* @post
* - The encrypted block is written to <tt><var>block</var></tt>.
*
* @details
* This method encrypts a message using RSA-OAEP, using an RSA public key.
*/
bool encrypt(byte_t* block, const byte_t* message, size_t message_size, const byte_t* seed, size_t seed_size)
{
if (mState != State::Initialized) { return false; }
if (message_size > (kBlockSize - (2 * HashFunction::kBlockSize) - 2)) { return false; }
if (block == nullptr) { return false; }
if (message == nullptr || message_size == 0) { return false; }
if (seed == nullptr || seed_size == 0) { return false; }
std::array<byte_t, kBlockSize> encoded_message;
//memset(encoded_message.data(), 0, encoded_message.size());
if (mPadImpl.BuildPad(encoded_message.data(), encoded_message.size(), mLabelDigest.data(), mLabelDigest.size(), message, message_size, seed, seed_size) != detail::RsaOaepPadding<HashFunction>::Result::kSuccess)
{
return false;
}
try {
mRsaImpl.publicTransform(block, encoded_message.data());
}
catch (...) {
return false;
}
return true;
}
/**
* @brief Decrypt & decode message from an RSA-OAEP block.
*
* @param[out] message Pointer to the buffer storing the decrypted message.
* @param[out] message_size Size of decrypted @p message.
* @param[in] message_capacity Capacity of @p message buffer.
* @param[in] block Pointer to encrypted RSA-OAEP block.
* @return true if decryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>RsaOaepEncryptor::kBlockSize</tt>.
* - @p message_capacity >= (<tt>RsaOaepEncryptor::kBlockSize</tt> - (2 * <tt>HashFunction::kHashSize</tt>) - 2)
*
* @post
* - The decrypted message is written to <tt><var>message</var></tt>.
* - The size of the decrypted message is written to <tt><var>message_size</var></tt>.
*
* @details
* This method decrypts a RSA-OAEP encrypted message, using an RSA private key.
*/
bool decrypt(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block)
{
if (mState != State::Initialized) { return false; }
if (block == nullptr) { return false; }
if (message == nullptr || message_capacity == 0) { return false; }
std::array<byte_t, kBlockSize> decrypted_block;
try {
mRsaImpl.privateTransform(decrypted_block.data(), block);
} catch (...) {
return false;
}
return (mPadImpl.RecoverFromPad(message, message_capacity, message_size, mLabelDigest.data(), mLabelDigest.size(), decrypted_block.data(), decrypted_block.size()) == detail::RsaOaepPadding<HashFunction>::Result::kSuccess);
}
private:
enum class State
{
None,
Initialized
};
State mState;
tc::ByteData mLabelDigest;
detail::RsaImpl mRsaImpl;
detail::PrbgImpl mPrbgImpl;
detail::RsaOaepPadding<HashFunction> mPadImpl;
};
}} // namespace tc::crypto
@@ -0,0 +1,201 @@
/**
* @file RsaOaepSha256Encryptor.h
* @brief Declarations for API resources for RSA-OAEP-SHA2-256 calculations.
* @author Jack (jakcron)
* @version 0.1
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha256Generator.h>
#include <tc/crypto/RsaOaepEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa1024OaepSha256Encryptor
* @brief Class for RSA1024-OAEP-SHA2-256 encryption/decryption.
*
* @details This class encrypts/decrypts data using RSA1024-OAEP-SHA2-256.
* For more information refer to @ref RsaOaepEncryptor.
*/
using Rsa1024OaepSha256Encryptor = RsaOaepEncryptor<1024,Sha256Generator>;
/**
* @typedef Rsa2048OaepSha256Encryptor
* @brief Class for RSA2048-OAEP-SHA2-256 encryption/decryption.
*
* @details This class encrypts/decrypts data using RSA2048-OAEP-SHA2-256.
* For more information refer to @ref RsaOaepEncryptor.
*/
using Rsa2048OaepSha256Encryptor = RsaOaepEncryptor<2048,Sha256Generator>;
/**
* @typedef Rsa4096OaepSha256Encryptor
* @brief Class for RSA4096-OAEP-SHA2-256 encryption/decryption.
*
* @details This class encrypts/decrypts data using RSA4096-OAEP-SHA2-256.
* For more information refer to @ref RsaOaepEncryptor.
*/
using Rsa4096OaepSha256Encryptor = RsaOaepEncryptor<4096,Sha256Generator>;
/**
* @brief Utility function for encrypting a message using RSA1024-OAEP-SHA2-256.
*
* @param[out] block Pointer to the buffer storing the encrypted RSA block.
* @param[in] message Pointer to message.
* @param[in] message_size Size of message.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if encryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa1024OaepSha256Encryptor::kBlockSize</tt>.
* - The maximum size for @p message_size is <tt>Rsa1024OaepSha256Encryptor::kBlockSize</tt> - (2 * <tt>Sha256Generator::kHashSize</tt>) - 2
*
* @post
* - The encrypted block is written to <tt><var>block</var></tt>.
*
* @details
* This function encrypts a message using RSA-OAEP, using an RSA public key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
* OAEP encoding uses a random seed, this function generates the seed internally. To manually specify the seed, please use the @ref Rsa1024OaepSha256Encryptor class directly.
*/
bool EncryptRsa1024OaepSha256(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility for decrypting a RSA1024-OAEP-SHA2-256 encrypted message.
*
* @param[out] message Pointer to the buffer storing the decrypted message.
* @param[out] message_size Size of decrypted @p message.
* @param[in] message_capacity Capacity of @p message buffer.
* @param[in] block Pointer to encrypted RSA-OAEP block.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if decryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa1024OaepSha256Encryptor::kBlockSize</tt>.
* - @p message_capacity >= (<tt>Rsa1024OaepSha256Encryptor::kBlockSize</tt> - (2 * <tt>Sha256Generator::kHashSize</tt>) - 2)
*
* @post
* - The decrypted message is written to <tt><var>message</var></tt>.
* - The size of the decrypted message is written to <tt><var>message_size</var></tt>.
*
* @details
* This function decrypts a RSA-OAEP encrypted message, using an RSA private key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
*/
bool DecryptRsa1024OaepSha256(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility function for encrypting a message using RSA2048-OAEP-SHA2-256.
*
* @param[out] block Pointer to the buffer storing the encrypted RSA block.
* @param[in] message Pointer to message.
* @param[in] message_size Size of message.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if encryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa2048OaepSha256Encryptor::kBlockSize</tt>.
* - The maximum size for @p message_size is <tt>Rsa2048OaepSha256Encryptor::kBlockSize</tt> - (2 * <tt>Sha256Generator::kHashSize</tt>) - 2
*
* @post
* - The encrypted block is written to <tt><var>block</var></tt>.
*
* @details
* This function encrypts a message using RSA-OAEP, using an RSA public key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
* OAEP encoding uses a random seed, this function generates the seed internally. To manually specify the seed, please use the @ref Rsa2048OaepSha256Encryptor class directly.
*/
bool EncryptRsa2048OaepSha256(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility for decrypting a RSA2048-OAEP-SHA2-256 encrypted message.
*
* @param[out] message Pointer to the buffer storing the decrypted message.
* @param[out] message_size Size of decrypted @p message.
* @param[in] message_capacity Capacity of @p message buffer.
* @param[in] block Pointer to encrypted RSA-OAEP block.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if decryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa2048OaepSha256Encryptor::kBlockSize</tt>.
* - @p message_capacity >= (<tt>Rsa2048OaepSha256Encryptor::kBlockSize</tt> - (2 * <tt>Sha256Generator::kHashSize</tt>) - 2)
*
* @post
* - The decrypted message is written to <tt><var>message</var></tt>.
* - The size of the decrypted message is written to <tt><var>message_size</var></tt>.
*
* @details
* This function decrypts a RSA-OAEP encrypted message, using an RSA private key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
*/
bool DecryptRsa2048OaepSha256(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility function for encrypting a message using RSA4096-OAEP-SHA2-256.
*
* @param[out] block Pointer to the buffer storing the encrypted RSA block.
* @param[in] message Pointer to message.
* @param[in] message_size Size of message.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if encryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa4096OaepSha256Encryptor::kBlockSize</tt>.
* - The maximum size for @p message_size is <tt>Rsa4096OaepSha256Encryptor::kBlockSize</tt> - (2 * <tt>Sha256Generator::kHashSize</tt>) - 2
*
* @post
* - The encrypted block is written to <tt><var>block</var></tt>.
*
* @details
* This function encrypts a message using RSA-OAEP, using an RSA public key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
* OAEP encoding uses a random seed, this function generates the seed internally. To manually specify the seed, please use the @ref Rsa4096OaepSha256Encryptor class directly.
*/
bool EncryptRsa4096OaepSha256(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility for decrypting a RSA4096-OAEP-SHA2-256 encrypted message.
*
* @param[out] message Pointer to the buffer storing the decrypted message.
* @param[out] message_size Size of decrypted @p message.
* @param[in] message_capacity Capacity of @p message buffer.
* @param[in] block Pointer to encrypted RSA-OAEP block.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if decryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa4096OaepSha256Encryptor::kBlockSize</tt>.
* - @p message_capacity >= (<tt>Rsa4096OaepSha256Encryptor::kBlockSize</tt> - (2 * <tt>Sha256Generator::kHashSize</tt>) - 2)
*
* @post
* - The decrypted message is written to <tt><var>message</var></tt>.
* - The size of the decrypted message is written to <tt><var>message_size</var></tt>.
*
* @details
* This function decrypts a RSA-OAEP encrypted message, using an RSA private key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
*/
bool DecryptRsa4096OaepSha256(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
}} // namespace tc::crypto
@@ -0,0 +1,139 @@
/**
* @file RsaOaepSha512Encryptor.h
* @brief Declarations for API resources for RSA-OAEP-SHA2-512 calculations.
* @author Jack (jakcron)
* @version 0.2
* @date 2020/10/17
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha512Generator.h>
#include <tc/crypto/RsaOaepEncryptor.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa2048OaepSha512Encryptor
* @brief Class for RSA2048-OAEP-SHA2-512 encryption/decryption.
*
* @details This class encrypts/decrypts data using RSA2048-OAEP-SHA2-512.
* For more information refer to @ref RsaOaepEncryptor.
*/
using Rsa2048OaepSha512Encryptor = RsaOaepEncryptor<2048,Sha512Generator>;
/**
* @typedef Rsa4096OaepSha512Encryptor
* @brief Class for RSA4096-OAEP-SHA2-512 encryption/decryption.
*
* @details This class encrypts/decrypts data using RSA4096-OAEP-SHA2-512.
* For more information refer to @ref RsaOaepEncryptor.
*/
using Rsa4096OaepSha512Encryptor = RsaOaepEncryptor<4096,Sha512Generator>;
/**
* @brief Utility function for encrypting a message using RSA2048-OAEP-SHA2-512.
*
* @param[out] block Pointer to the buffer storing the encrypted RSA block.
* @param[in] message Pointer to message.
* @param[in] message_size Size of message.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if encryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa2048OaepSha512Encryptor::kBlockSize</tt>.
* - The maximum size for @p message_size is <tt>Rsa2048OaepSha512Encryptor::kBlockSize</tt> - (2 * <tt>Sha512Generator::kHashSize</tt>) - 2
*
* @post
* - The encrypted block is written to <tt><var>block</var></tt>.
*
* @details
* This function encrypts a message using RSA-OAEP, using an RSA public key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
* OAEP encoding uses a random seed, this function generates the seed internally. To manually specify the seed, please use the @ref Rsa2048OaepSha512Encryptor class directly.
*/
bool EncryptRsa2048OaepSha512(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility for decrypting a RSA2048-OAEP-SHA2-512 encrypted message.
*
* @param[out] message Pointer to the buffer storing the decrypted message.
* @param[out] message_size Size of decrypted @p message.
* @param[in] message_capacity Capacity of @p message buffer.
* @param[in] block Pointer to encrypted RSA-OAEP block.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if decryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa2048OaepSha512Encryptor::kBlockSize</tt>.
* - @p message_capacity >= (<tt>Rsa2048OaepSha512Encryptor::kBlockSize</tt> - (2 * <tt>Sha512Generator::kHashSize</tt>) - 2)
*
* @post
* - The decrypted message is written to <tt><var>message</var></tt>.
* - The size of the decrypted message is written to <tt><var>message_size</var></tt>.
*
* @details
* This function decrypts a RSA-OAEP encrypted message, using an RSA private key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
*/
bool DecryptRsa2048OaepSha512(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility function for encrypting a message using RSA4096-OAEP-SHA2-512.
*
* @param[out] block Pointer to the buffer storing the encrypted RSA block.
* @param[in] message Pointer to message.
* @param[in] message_size Size of message.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if encryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa4096OaepSha512Encryptor::kBlockSize</tt>.
* - The maximum size for @p message_size is <tt>Rsa4096OaepSha512Encryptor::kBlockSize</tt> - (2 * <tt>Sha512Generator::kHashSize</tt>) - 2
*
* @post
* - The encrypted block is written to <tt><var>block</var></tt>.
*
* @details
* This function encrypts a message using RSA-OAEP, using an RSA public key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
* OAEP encoding uses a random seed, this function generates the seed internally. To manually specify the seed, please use the @ref Rsa4096OaepSha512Encryptor class directly.
*/
bool EncryptRsa4096OaepSha512(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
/**
* @brief Utility for decrypting a RSA4096-OAEP-SHA2-512 encrypted message.
*
* @param[out] message Pointer to the buffer storing the decrypted message.
* @param[out] message_size Size of decrypted @p message.
* @param[in] message_capacity Capacity of @p message buffer.
* @param[in] block Pointer to encrypted RSA-OAEP block.
* @param[in] key RSA key data.
* @param[in] label OAEP label data.
* @param[in] label_size Size in bytes of OAEP label data.
* @param[in] isLabelDigested Boolean indicating if label data has already been digested. False is the default (label is in raw form).
* @return true if decryption was successful.
*
* @pre
* - Size of the @p block buffer must >= <tt>Rsa4096OaepSha512Encryptor::kBlockSize</tt>.
* - @p message_capacity >= (<tt>Rsa4096OaepSha512Encryptor::kBlockSize</tt> - (2 * <tt>Sha512Generator::kHashSize</tt>) - 2)
*
* @post
* - The decrypted message is written to <tt><var>message</var></tt>.
* - The size of the decrypted message is written to <tt><var>message_size</var></tt>.
*
* @details
* This function decrypts a RSA-OAEP encrypted message, using an RSA private key.
* OAEP encoding uses a label (which is digested using a hash algorithm) as part of the MGF1 masking process. It is possible to specify a pre-digested label instead, in which case set @p isLabelDigested to true.
*/
bool DecryptRsa4096OaepSha512(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested = false);
}} // namespace tc::crypto
+144
View File
@@ -0,0 +1,144 @@
/**
* @file RsaPkcs1Md5Signer.h
* @brief Declarations for API resources for RSA-PKCS1-MD5 calculations.
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Md5Generator.h>
#include <tc/crypto/RsaPkcs1Signer.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa1024Pkcs1Md5Signer
* @brief Class for generating and verifying RSA1024-PKCS1-MD5 signatures.
*
* @details This class uses RSA1024-PKCS1 to sign/validate MD5 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa1024Pkcs1Md5Signer = RsaPkcs1Signer<1024,Md5Generator>;
/**
* @typedef Rsa2048Pkcs1Md5Signer
* @brief Class for generating and verifying RSA2048-PKCS1-MD5 signatures.
*
* @details This class uses RSA2048-PKCS1 to sign/validate MD5 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa2048Pkcs1Md5Signer = RsaPkcs1Signer<2048,Md5Generator>;
/**
* @typedef Rsa4096Pkcs1Md5Signer
* @brief Class for generating and verifying RSA4096-PKCS1-MD5 signatures.
*
* @details This class uses RSA4096-PKCS1 to sign/validate MD5 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa4096Pkcs1Md5Signer = RsaPkcs1Signer<4096,Md5Generator>;
/**
* @brief Utility function for calculating a RSA1024-PKCS1-MD5 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024Pkcs1Md5Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Md5Generator class.
*/
bool SignRsa1024Pkcs1Md5(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA1024-PKCS1-MD5 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Md5Generator class.
*/
bool VerifyRsa1024Pkcs1Md5(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA2048-PKCS1-MD5 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa2048Pkcs1Md5Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Md5Generator class.
*/
bool SignRsa2048Pkcs1Md5(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA2048-PKCS1-MD5 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Md5Generator class.
*/
bool VerifyRsa2048Pkcs1Md5(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA4096-PKCS1-MD5 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa4096Pkcs1Md5Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Md5Generator class.
*/
bool SignRsa4096Pkcs1Md5(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA4096-PKCS1-MD5 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Md5Generator class.
*/
bool VerifyRsa4096Pkcs1Md5(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
}} // namespace tc::crypto
+144
View File
@@ -0,0 +1,144 @@
/**
* @file RsaPkcs1Sha1Signer.h
* @brief Declarations for API resources for RSA-PKCS1-SHA1 calculations.
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha1Generator.h>
#include <tc/crypto/RsaPkcs1Signer.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa1024Pkcs1Sha1Signer
* @brief Class for generating and verifying RSA1024-PKCS1-SHA1 signatures.
*
* @details This class uses RSA1024-PKCS1 to sign/validate SHA1 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa1024Pkcs1Sha1Signer = RsaPkcs1Signer<1024,Sha1Generator>;
/**
* @typedef Rsa2048Pkcs1Sha1Signer
* @brief Class for generating and verifying RSA2048-PKCS1-SHA1 signatures.
*
* @details This class uses RSA2048-PKCS1 to sign/validate SHA1 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa2048Pkcs1Sha1Signer = RsaPkcs1Signer<2048,Sha1Generator>;
/**
* @typedef Rsa4096Pkcs1Sha1Signer
* @brief Class for generating and verifying RSA4096-PKCS1-SHA1 signatures.
*
* @details This class uses RSA4096-PKCS1 to sign/validate SHA1 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa4096Pkcs1Sha1Signer = RsaPkcs1Signer<4096,Sha1Generator>;
/**
* @brief Utility function for calculating a RSA1024-PKCS1-SHA1 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024Pkcs1Sha1Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha1Generator class.
*/
bool SignRsa1024Pkcs1Sha1(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA1024-PKCS1-SHA1 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha1Generator class.
*/
bool VerifyRsa1024Pkcs1Sha1(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA2048-PKCS1-SHA1 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa2048Pkcs1Sha1Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha1Generator class.
*/
bool SignRsa2048Pkcs1Sha1(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA2048-PKCS1-SHA1 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha1Generator class.
*/
bool VerifyRsa2048Pkcs1Sha1(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA4096-PKCS1-SHA1 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa4096Pkcs1Sha1Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha1Generator class.
*/
bool SignRsa4096Pkcs1Sha1(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA4096-PKCS1-SHA1 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha1Generator class.
*/
bool VerifyRsa4096Pkcs1Sha1(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
}} // namespace tc::crypto
@@ -0,0 +1,144 @@
/**
* @file RsaPkcs1Sha256Signer.h
* @brief Declarations for API resources for RSA-PKCS1-SHA2-256 calculations.
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha256Generator.h>
#include <tc/crypto/RsaPkcs1Signer.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa1024Pkcs1Sha256Signer
* @brief Class for generating and verifying RSA1024-PKCS1-SHA2-256 signatures.
*
* @details This class uses RSA1024-PKCS1 to sign/validate SHA2-256 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa1024Pkcs1Sha256Signer = RsaPkcs1Signer<1024,Sha256Generator>;
/**
* @typedef Rsa2048Pkcs1Sha256Signer
* @brief Class for generating and verifying RSA2048-PKCS1-SHA2-256 signatures.
*
* @details This class uses RSA2048-PKCS1 to sign/validate SHA2-256 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa2048Pkcs1Sha256Signer = RsaPkcs1Signer<2048,Sha256Generator>;
/**
* @typedef Rsa4096Pkcs1Sha256Signer
* @brief Class for generating and verifying RSA4096-PKCS1-SHA2-256 signatures.
*
* @details This class uses RSA4096-PKCS1 to sign/validate SHA2-256 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa4096Pkcs1Sha256Signer = RsaPkcs1Signer<4096,Sha256Generator>;
/**
* @brief Utility function for calculating a RSA1024-PKCS1-SHA2-256 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024Pkcs1Sha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool SignRsa1024Pkcs1Sha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA1024-PKCS1-SHA2-256 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool VerifyRsa1024Pkcs1Sha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA2048-PKCS1-SHA2-256 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa2048Pkcs1Sha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool SignRsa2048Pkcs1Sha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA2048-PKCS1-SHA2-256 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool VerifyRsa2048Pkcs1Sha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA4096-PKCS1-SHA2-256 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa4096Pkcs1Sha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool SignRsa4096Pkcs1Sha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA4096-PKCS1-SHA2-256 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool VerifyRsa4096Pkcs1Sha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
}} // namespace tc::crypto
@@ -0,0 +1,144 @@
/**
* @file RsaPkcs1Sha512Signer.h
* @brief Declarations for API resources for RSA-PKCS1-SHA2-512 calculations.
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha512Generator.h>
#include <tc/crypto/RsaPkcs1Signer.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa1024Pkcs1Sha512Signer
* @brief Class for generating and verifying RSA1024-PKCS1-SHA2-512 signatures.
*
* @details This class uses RSA1024-PKCS1 to sign/validate SHA2-512 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa1024Pkcs1Sha512Signer = RsaPkcs1Signer<1024,Sha512Generator>;
/**
* @typedef Rsa2048Pkcs1Sha512Signer
* @brief Class for generating and verifying RSA2048-PKCS1-SHA2-512 signatures.
*
* @details This class uses RSA2048-PKCS1 to sign/validate SHA2-512 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa2048Pkcs1Sha512Signer = RsaPkcs1Signer<2048,Sha512Generator>;
/**
* @typedef Rsa4096Pkcs1Sha512Signer
* @brief Class for generating and verifying RSA4096-PKCS1-SHA2-512 signatures.
*
* @details This class uses RSA4096-PKCS1 to sign/validate SHA2-512 message digests.
* For more information refer to @ref RsaPkcs1Signer.
*/
using Rsa4096Pkcs1Sha512Signer = RsaPkcs1Signer<4096,Sha512Generator>;
/**
* @brief Utility function for calculating a RSA1024-PKCS1-SHA2-512 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024Pkcs1Sha512Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool SignRsa1024Pkcs1Sha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA1024-PKCS1-SHA2-512 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool VerifyRsa1024Pkcs1Sha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA2048-PKCS1-SHA2-512 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa2048Pkcs1Sha512Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool SignRsa2048Pkcs1Sha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA2048-PKCS1-SHA2-512 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool VerifyRsa2048Pkcs1Sha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA4096-PKCS1-SHA2-512 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa4096Pkcs1Sha512Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool SignRsa4096Pkcs1Sha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA4096-PKCS1-SHA2-512 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool VerifyRsa4096Pkcs1Sha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
}} // namespace tc::crypto
+172
View File
@@ -0,0 +1,172 @@
/**
* @file RsaPkcs1Signer.h
* @brief Declaration of tc::crypto::RsaPkcs1Signer
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/RsaImpl.h>
#include <tc/crypto/detail/RsaPkcs1Padding.h>
#include <tc/crypto/RsaKey.h>
namespace tc { namespace crypto {
/**
* @class RsaPkcs1Signer
* @brief Class for calculating an RSA-PKCS1 signature.
*
* @tparam KeyBitSize RSA key size in bits.
* @tparam HashFunction The class that implements the hash function used with RSA-PKCS1.
*
* @details
* This class is a template class that takes a hash function implementation class as template parameter.
* See @ref Rsa2048Pkcs1Sha256Signer or similar for supplied realizations of this template class.
*
* The <var>KeyBitSize</var> is the size in bits of the RSA key, this only supports key sizes aligned to 8 bits.
*
* The implementation of <var>HashFunction</var> must satisfies the following conditions.
* See @ref Sha256Generator or similar class, for more information including parameters to each function.
*
* -# Has a <tt>kAsn1OidDataSize</tt> constant that defines the size of the ASN.1 encoded OID for the hash algorithm
* -# Has a <tt>kAsn1OidData</tt> constant that defines the ASN.1 encoded OID for the hash algorithm
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
* -# Has a <tt>kHashSize</tt> constant that defines the output size of the hash value.
* -# Has an <tt>initialize</tt> method that begins processing.
* -# Has an <tt>update</tt> method that updates the hash value on input.
* -# Has a <tt>getHash</tt> method that gets the final hash value.
*
* This class has two states:
* - None : Not ready
* - Initialized : Ready to process input data
*
* General usage of this class is as follows:
* - Initialize RSA Signer state with @ref initialize().
* - Sign/Verify message digest with @ref sign() / @ref verify().
*/
template <size_t KeyBitSize, class HashFunction>
class RsaPkcs1Signer
{
public:
static_assert((KeyBitSize % 8) == 0, "KeyBitSize must be 8 bit aligned.");
static const size_t kSignatureSize = KeyBitSize >> 3; /**< RSA-PKCS1 signature size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
RsaPkcs1Signer() :
mState(State::None),
mRsaImpl(),
mPadImpl()
{}
/**
* @brief Initializes the signature calculation.
*
* @param[in] key RSA key data.
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the RSA calculation state with an RSA key.
*/
void initialize(const RsaKey& key)
{
if (key.n.size() == 0 || (key.d.size() == 0 && key.e.size() == 0))
{
throw tc::ArgumentNullException("RsaPkcs1Signer::initialize()", "key does not have minimal required key-data.");
}
mRsaImpl.initialize(KeyBitSize, key.n.data(), key.n.size(), nullptr, 0, nullptr, 0, key.d.data(), key.d.size(), key.e.data(), key.e.size());
mState = State::Initialized;
}
/**
* @brief Calculate RSA-PKCS1 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024Pkcs1Sha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
*/
bool sign(byte_t* signature, const byte_t* message_digest)
{
if (mState != State::Initialized) { return false; }
if (signature == nullptr) { return false; }
if (message_digest == nullptr) { return false; }
std::array<byte_t, kSignatureSize> block;
memset(block.data(), 0, block.size());
if (mPadImpl.BuildPad(block.data(), block.size(), message_digest, HashFunction::kHashSize) != detail::RsaPkcs1Padding<HashFunction>::Result::kSuccess)
{
return false;
}
try{
mRsaImpl.privateTransform(signature, block.data());
}
catch (...) {
return false;
}
return true;
}
/**
* @brief Verify RSA-PKCS1 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
*/
bool verify(const byte_t* signature, const byte_t* message_digest)
{
if (mState != State::Initialized) { return false; }
if (signature == nullptr) { return false; }
if (message_digest == nullptr) { return false; }
std::array<byte_t, kSignatureSize> block;
memcpy(block.data(), signature, block.size());
try {
mRsaImpl.publicTransform(block.data(), signature);
} catch (...) {
return false;
}
return (mPadImpl.CheckPad(message_digest, HashFunction::kHashSize, block.data(), block.size()) == detail::RsaPkcs1Padding<HashFunction>::Result::kSuccess);
}
private:
enum class State
{
None,
Initialized
};
State mState;
detail::RsaImpl mRsaImpl;
detail::RsaPkcs1Padding<HashFunction> mPadImpl;
};
}} // namespace tc::crypto
+144
View File
@@ -0,0 +1,144 @@
/**
* @file RsaPssSha256Signer.h
* @brief Declarations for API resources for RSA-PSS-SHA2-256 calculations.
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha256Generator.h>
#include <tc/crypto/RsaPssSigner.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa1024PssSha256Signer
* @brief Class for generating and verifying RSA1024-PSS-SHA2-256 signatures.
*
* @details This class uses RSA1024-PSS to sign/validate SHA2-256 message digests.
* For more information refer to @ref RsaPssSigner.
*/
using Rsa1024PssSha256Signer = RsaPssSigner<1024,Sha256Generator>;
/**
* @typedef Rsa2048PssSha256Signer
* @brief Class for generating and verifying RSA2048-PSS-SHA2-256 signatures.
*
* @details This class uses RSA2048-PSS to sign/validate SHA2-256 message digests.
* For more information refer to @ref RsaPssSigner.
*/
using Rsa2048PssSha256Signer = RsaPssSigner<2048,Sha256Generator>;
/**
* @typedef Rsa4096PssSha256Signer
* @brief Class for generating and verifying RSA4096-PSS-SHA2-256 signatures.
*
* @details This class uses RSA4096-PSS to sign/validate SHA2-256 message digests.
* For more information refer to @ref RsaPssSigner.
*/
using Rsa4096PssSha256Signer = RsaPssSigner<4096,Sha256Generator>;
/**
* @brief Utility function for calculating a RSA1024-PSS-SHA2-256 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024PssSha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool SignRsa1024PssSha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA1024-PSS-SHA2-256 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool VerifyRsa1024PssSha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA2048-PSS-SHA2-256 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa2048PssSha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool SignRsa2048PssSha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA2048-PSS-SHA2-256 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool VerifyRsa2048PssSha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA4096-PSS-SHA2-256 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa4096PssSha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool SignRsa4096PssSha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA4096-PSS-SHA2-256 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha256Generator class.
*/
bool VerifyRsa4096PssSha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
}} // namespace tc::crypto
+144
View File
@@ -0,0 +1,144 @@
/**
* @file RsaPssSha512Signer.h
* @brief Declarations for API resources for RSA-PSS-SHA2-512 calculations.
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/Sha512Generator.h>
#include <tc/crypto/RsaPssSigner.h>
namespace tc { namespace crypto {
/**
* @typedef Rsa1024PssSha512Signer
* @brief Class for generating and verifying RSA1024-PSS-SHA2-512 signatures.
*
* @details This class uses RSA1024-PSS to sign/validate SHA2-512 message digests.
* For more information refer to @ref RsaPssSigner.
*/
using Rsa1024PssSha512Signer = RsaPssSigner<1024,Sha512Generator>;
/**
* @typedef Rsa2048PssSha512Signer
* @brief Class for generating and verifying RSA2048-PSS-SHA2-512 signatures.
*
* @details This class uses RSA2048-PSS to sign/validate SHA2-512 message digests.
* For more information refer to @ref RsaPssSigner.
*/
using Rsa2048PssSha512Signer = RsaPssSigner<2048,Sha512Generator>;
/**
* @typedef Rsa4096PssSha512Signer
* @brief Class for generating and verifying RSA4096-PSS-SHA2-512 signatures.
*
* @details This class uses RSA4096-PSS to sign/validate SHA2-512 message digests.
* For more information refer to @ref RsaPssSigner.
*/
using Rsa4096PssSha512Signer = RsaPssSigner<4096,Sha512Generator>;
/**
* @brief Utility function for calculating a RSA1024-PSS-SHA2-512 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024PssSha512Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool SignRsa1024PssSha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA1024-PSS-SHA2-512 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool VerifyRsa1024PssSha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA2048-PSS-SHA2-512 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa2048PssSha512Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool SignRsa2048PssSha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA2048-PSS-SHA2-512 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool VerifyRsa2048PssSha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for calculating a RSA4096-PSS-SHA2-512 signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA private key.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa4096PssSha512Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool SignRsa4096PssSha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key);
/**
* @brief Utility function for verfifying a RSA4096-PSS-SHA2-512 signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] key Reference to RSA public key.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
* To calculate a message digest use the @ref Sha512Generator class.
*/
bool VerifyRsa4096PssSha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key);
}} // namespace tc::crypto
+208
View File
@@ -0,0 +1,208 @@
/**
* @file RsaPssSigner.h
* @brief Declaration of tc::crypto::RsaPssSigner
* @author Jack (jakcron)
* @version 0.3
* @date 2020/09/28
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/RsaImpl.h>
#include <tc/crypto/detail/PrbgImpl.h>
#include <tc/crypto/detail/RsaPssPadding.h>
#include <tc/crypto/RsaKey.h>
namespace tc { namespace crypto {
/**
* @class RsaPssSigner
* @brief Class for calculating an RSA-PSS signature.
*
* @tparam KeyBitSize RSA key size in bits.
* @tparam HashFunction The class that implements the hash function used with RSA-PSS.
*
* @details
* This class is a template class that takes a hash function implementation class as template parameter.
* See @ref Rsa2048PssSha256Signer or similar for supplied realizations of this template class.
*
* The <var>KeyBitSize</var> is the size in bits of the RSA key, this only supports key sizes aligned to 8 bits.
*
* The implementation of <var>HashFunction</var> must satisfies the following conditions.
* See @ref Sha256Generator or similar class, for more information including parameters to each function.
*
* -# Has a <tt>kBlockSize</tt> constant that defines the size of the block to process.
* -# Has a <tt>kHashSize</tt> constant that defines the output size of the hash value.
* -# Has an <tt>initialize</tt> method that begins processing.
* -# Has an <tt>update</tt> method that updates the hash value on input.
* -# Has a <tt>getHash</tt> method that gets the final hash value.
*
* This class has two states:
* - None : Not ready
* - Initialized : Ready to process input data
*
* General usage of this class is as follows:
* - Initialize RSA Signer state with @ref initialize().
* - Sign/Verify message digest with @ref sign() / @ref verify().
*/
template <size_t KeyBitSize, class HashFunction>
class RsaPssSigner
{
public:
static_assert((KeyBitSize % 8) == 0, "KeyBitSize must be 8 bit aligned.");
static const size_t kSignatureSize = KeyBitSize >> 3; /**< RSA-PSS signature size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
RsaPssSigner() :
mState(State::None),
mRsaImpl(),
mPrbgImpl(),
mPadImpl()
{}
/**
* @brief Initializes the signature calculation.
*
* @param[in] key RSA key data.
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the RSA calculation state with an RSA key.
*/
void initialize(const RsaKey& key)
{
if (key.n.size() == 0 || (key.d.size() == 0 && key.e.size() == 0))
{
throw tc::ArgumentNullException("RsaPssSigner::initialize()", "key does not have minimal required key-data.");
}
mRsaImpl.initialize(KeyBitSize, key.n.data(), key.n.size(), nullptr, 0, nullptr, 0, key.d.data(), key.d.size(), key.e.data(), key.e.size());
mState = State::Initialized;
}
/**
* @brief Calculate RSA-PSS signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024PssSha256Signer::kSignatureSize</tt>.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
* This generates the salt internally. To manually specify the salt, please use the alternative @ref sign() method.
*/
bool sign(byte_t* signature, const byte_t* message_digest)
{
if (mState != State::Initialized) { return false; }
std::array<byte_t, HashFunction::kHashSize> salt;
mPrbgImpl.getBytes(salt.data(), salt.size());
// usable_salt_size: salt.size(), but if the blocksize isn't big enough, then its = KeySize - (HashFunction::kHashSize + 2)
// this may produce an illegal salt size (salt_size < HashFunction::kHashSize - 2), but this will be caught by BuildPad()
size_t usable_salt_size = std::min<size_t>(salt.size(), kSignatureSize - (HashFunction::kHashSize + 2));
return sign(signature, message_digest, salt.data(), usable_salt_size);
}
/**
* @brief Calculate RSA-PSS signature.
*
* @param[out] signature Pointer to the buffer storing the signature.
* @param[in] message_digest Pointer to message digest.
* @param[in] salt Pointer to salt.
* @param[in] salt_size Size of @p salt.
* @return true if signature calculation was successful.
*
* @pre
* - Size of the signature buffer must >= <tt>Rsa1024PssSha256Signer::kSignatureSize</tt>.
* - The data in @p salt should be random, otherwise the signature strength is reduced.
* - Where KeySize >= (HashCalculator::kHashSize * 2 + 2) @p salt_size = HashCalculator::kHashSize. Otherwise @p salt_size = KeySize - (HashCalculator::kHashSize + 2). However the minimum legal salt size is (HashCalculator::kHashSize - 2), if the salt_size falls below this consider a larger KeySize as this operation will not complete successfully.
*
* @post
* - The signature is written to <tt><var>signature</var></tt>.
*
* @details
* This function calculates a signature for a message digest.
*/
bool sign(byte_t* signature, const byte_t* message_digest, const byte_t* salt, size_t salt_size)
{
if (mState != State::Initialized) { return false; }
if (signature == nullptr) { return false; }
if (message_digest == nullptr) { return false; }
if (salt == nullptr || salt_size == 0) { return false; }
std::array<byte_t, kSignatureSize> block;
memset(block.data(), 0, block.size());
if (mPadImpl.BuildPad(block.data(), block.size(), message_digest, HashFunction::kHashSize, salt, salt_size, KeyBitSize - 1) != detail::RsaPssPadding<HashFunction>::Result::kSuccess)
{
return false;
}
try {
mRsaImpl.privateTransform(signature, block.data());
}
catch (...) {
return false;
}
return true;
}
/**
* @brief Verify RSA-PSS signature.
*
* @param[in] signature Pointer to signature.
* @param[in] message_digest Pointer to message digest.
* @return true if the signature is valid, otherwise false.
*
* @details
* This function verifies a signature for a message digest.
*/
bool verify(const byte_t* signature, const byte_t* message_digest)
{
if (mState != State::Initialized) { return false; }
if (signature == nullptr) { return false; }
if (message_digest == nullptr) { return false; }
std::array<byte_t, kSignatureSize> block;
memcpy(block.data(), signature, block.size());
try {
mRsaImpl.publicTransform(block.data(), signature);
} catch (...) {
return false;
}
return (mPadImpl.CheckPad(message_digest, HashFunction::kHashSize, block.data(), block.size(), kSignatureSize - 1) == detail::RsaPssPadding<HashFunction>::Result::kSuccess);
}
private:
enum class State
{
None,
Initialized
};
State mState;
detail::RsaImpl mRsaImpl;
detail::PrbgImpl mPrbgImpl;
detail::RsaPssPadding<HashFunction> mPadImpl;
};
}} // namespace tc::crypto
+221
View File
@@ -0,0 +1,221 @@
/**
* @file Sha1Generator.h
* @brief Declarations for API resources for SHA1 calculations.
* @author Jack (jakcron)
* @version 0.3
* @date 2020/06/01
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/Sha1Impl.h>
namespace tc { namespace crypto {
/**
* @class Sha1Generator
* @brief Class for calculating SHA1 hash.
*
* @warning SHA1 is considered a weak message digest and its use constitutes a security risk. It should only be used to maintain compatibility with legacy systems.
*
* @details
* This class has three states:
* - None : Not ready
* - Initialized : Ready to process input data
* - Done : Hash value is calculated
*
* General usage of this class is as follows:
* - Initialize Hash Generator state with @ref initialize().
* - Update hash value with input data with @ref update().
* - Complete hash calculation and export hash value with @ref getHash().
*
* Below is code sample for calculating hash value with one call to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Sha1Generator::kHashSize> hash;
*
* // initialize generator. Sha1Generator is now in a ready state.
* tc::crypto::Sha1Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // read whole file into memory. This is unsafe for large file sizes especially on 32-bit systems.
* tc::ByteData data = tc::ByteData((size_t)stream.length());
* stream.read(data.data(), data.size());
*
* // update generator state with stream data
* impl.update(data.data(), data.size());
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*
* Below is code sample for calculating hash value with sequential calls to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create read block (size 512)
* static const size_t kReadBlockSize = 0x200;
* std::array<byte_t, kReadBlockSize> block;
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Sha1Generator::kHashSize> hash;
*
* // initialize generator. Sha1Generator is now in a ready state.
* tc::crypto::Sha1Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // iterate over blocks in stream until no more data can be read
* size_t read_count = 0;
* while ( 0 != (read_count = tc::io::IOUtil::getReadableCount(stream.position(), stream.length(), block.size())) )
* {
* // read block from stream
* stream.read(block.data(), read_count);
*
* // update generator state with stream data
* impl.update(block.data(), read_count);
* }
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*/
class Sha1Generator
{
public:
static const size_t kAsn1OidDataSize = 15; /**< SHA1 ASN.1 Encoded OID length */
static const std::array<byte_t, kAsn1OidDataSize> kAsn1OidData; /**< SHA1 ASN.1 Encoded OID */
static const size_t kHashSize = 20; /**< SHA1 hash size */
static const size_t kBlockSize = 64; /**< SHA1 processing block size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
Sha1Generator() :
mImpl()
{}
/**
* @brief Initializes the hash calculation.
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the hash calculation state to the begin state.
*
* @note
* - This must be called before calculating a new hash.
*/
void initialize()
{
mImpl.initialize();
}
/**
* @brief Update hash value with specified data.
*
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @details
* Data can be input to the generator in one @ref update() call or split across multiple sequential calls.
*
* For example the following scenarios all generate the same hash value.
* @code
* // generate data to be hashed
* tc::ByteData data = tc::ByteData(0x30);
* memset(data.data(), 0xff, data.size());
*
* // create generator instance
* tc::crypto::Sha1Generator impl;
*
* // scenario 1 (one call to update() 0x30 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha1Generator::kHashSize> hash1;
* impl.initialize();
* impl.update(data.data(), data.size());
* impl.getHash(hash1.data());
*
* // scenario 2 (three calls to update() 0x10 bytes each, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha1Generator::kHashSize> hash2;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x10);
* impl.update(data.data() + 0x20, 0x10);
* impl.getHash(hash2.data());
*
* // scenario 3 (two calls to update() one 0x10 bytes, the second 0x20 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha1Generator::kHashSize> hash3;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x20);
* impl.getHash(hash3.data());
* @endcode
*
* @note
* - If input data is broken up into blocks and supplied via multiple @ref update() calls, the order must be consistent with the original input data.
*/
void update(const byte_t* data, size_t data_size)
{
mImpl.update(data, data_size);
}
/**
* @brief Completes hash calculation and output hash value.
*
* @param[out] hash Pointer to buffer storing hash value.
*
* @pre
* - Instance is in either Initialized or Done state.
* - The size of the <tt><var>hash</var></tt> buffer must be >= @ref kHashSize.
*
* @post
* - Instance is now in a Done state.
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @note
* - If the instance is in a None state, then this call does nothing.
*/
void getHash(byte_t* hash)
{
mImpl.getHash(hash);
}
private:
detail::Sha1Impl mImpl;
};
/**
* @brief Utility function for calculating the SHA1 hash.
*
* @warning SHA1 is considered a weak message digest and its use constitutes a security risk. It should only be used to maintain compatibility with legacy systems.
*
* @param[out] hash Pointer to buffer storing hash value.
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @pre
* - The size of the <tt><var>hash</var></tt> buffer must be >= @ref Sha1Generator::kHashSize.
*
* @post
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @details
* This function calculates the hash value for input passed in the <tt><var>data</var></tt> array.
* To calculate the hash value for input split across multiple arrays, use the @ref Sha1Generator class.
*/
void GenerateSha1Hash(byte_t* hash, const byte_t* data, size_t data_size);
}} // namespace tc::crypto
+216
View File
@@ -0,0 +1,216 @@
/**
* @file Sha256Generator.h
* @brief Declarations for API resources for SHA2-256 calculations.
* @author Jack (jakcron)
* @version 0.2
* @date 2020/06/01
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/Sha2Impl.h>
namespace tc { namespace crypto {
/**
* @class Sha256Generator
* @brief Class for calculating SHA2-256 hash.
*
* @details
* This class has three states:
* - None : Not ready
* - Initialized : Ready to process input data
* - Done : Hash value is calculated
*
* General usage of this class is as follows:
* - Initialize Hash Generator state with @ref initialize().
* - Update hash value with input data with @ref update().
* - Complete hash calculation and export hash value with @ref getHash().
*
* Below is code sample for calculating hash value with one call to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Sha256Generator::kHashSize> hash;
*
* // initialize generator. Sha256Generator is now in a ready state.
* tc::crypto::Sha256Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // read whole file into memory. This is unsafe for large file sizes especially on 32-bit systems.
* tc::ByteData data = tc::ByteData((size_t)stream.length());
* stream.read(data.data(), data.size());
*
* // update generator state with stream data
* impl.update(data.data(), data.size());
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*
* Below is code sample for calculating hash value with sequential calls to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create read block (size 512)
* static const size_t kReadBlockSize = 0x200;
* std::array<byte_t, kReadBlockSize> block;
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Sha256Generator::kHashSize> hash;
*
* // initialize generator. Sha256Generator is now in a ready state.
* tc::crypto::Sha256Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // iterate over blocks in stream until no more data can be read
* size_t read_count = 0;
* while ( 0 != (read_count = tc::io::IOUtil::getReadableCount(stream.position(), stream.length(), block.size())) )
* {
* // read block from stream
* stream.read(block.data(), read_count);
*
* // update generator state with stream data
* impl.update(block.data(), read_count);
* }
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*/
class Sha256Generator
{
public:
static const size_t kAsn1OidDataSize = 19; /**< SHA2-256 ASN.1 Encoded OID length */
static const std::array<byte_t, kAsn1OidDataSize> kAsn1OidData; /**< SHA2-256 ASN.1 Encoded OID */
static const size_t kHashSize = 32; /**< SHA2-256 hash size */
static const size_t kBlockSize = 64; /**< SHA2-256 processing block size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
Sha256Generator() :
mImpl(detail::Sha2Impl::SHA2BitSize_256)
{}
/**
* @brief Initializes the hash calculation.
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the hash calculation state to the begin state.
*
* @note
* - This must be called before calculating a new hash.
*/
void initialize()
{
mImpl.initialize();
}
/**
* @brief Update hash value with specified data.
*
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @details
* Data can be input to the generator in one @ref update() call or split across multiple sequential calls.
*
* For example the following scenarios all generate the same hash value.
* @code
* // generate data to be hashed
* tc::ByteData data = tc::ByteData(0x30);
* memset(data.data(), 0xff, data.size());
*
* // create generator instance
* tc::crypto::Sha256Generator impl;
*
* // scenario 1 (one call to update() 0x30 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha256Generator::kHashSize> hash1;
* impl.initialize();
* impl.update(data.data(), data.size());
* impl.getHash(hash1.data());
*
* // scenario 2 (three calls to update() 0x10 bytes each, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha256Generator::kHashSize> hash2;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x10);
* impl.update(data.data() + 0x20, 0x10);
* impl.getHash(hash2.data());
*
* // scenario 3 (two calls to update() one 0x10 bytes, the second 0x20 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha256Generator::kHashSize> hash3;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x20);
* impl.getHash(hash3.data());
* @endcode
*
* @note
* - If input data is broken up into blocks and supplied via multiple @ref update() calls, the order must be consistent with the original input data.
*/
void update(const byte_t* data, size_t data_size)
{
mImpl.update(data, data_size);
}
/**
* @brief Completes hash calculation and output hash value.
*
* @param[out] hash Pointer to buffer storing hash value.
*
* @pre
* - Instance is in either Initialized or Done state.
*
* @post
* - Instance is now in a Done state.
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @note
* - If the instance is in a None state, then this call does nothing.
*/
void getHash(byte_t* hash)
{
mImpl.getHash(hash);
}
private:
detail::Sha2Impl mImpl;
};
/**
* @brief Utility function for calculating the SHA2-256 hash.
*
* @param[out] hash Pointer to buffer storing hash value.
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @pre
* - The size of the <tt><var>hash</var></tt> buffer must be >= @ref Sha256Generator::kHashSize.
*
* @post
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @details
* This function calculates the hash value for input passed in the <tt><var>data</var></tt> array.
* To calculate the hash value for input split across multiple arrays, use the @ref Sha256Generator class.
*/
void GenerateSha256Hash(byte_t* hash, const byte_t* data, size_t data_size);
}} // namespace tc::crypto
+217
View File
@@ -0,0 +1,217 @@
/**
* @file Sha512Generator.h
* @brief Declarations for API resources for SHA2-512 calculations.
* @author Jack (jakcron)
* @version 0.2
* @date 2020/06/01
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/Sha2Impl.h>
namespace tc { namespace crypto {
/**
* @class Sha512Generator
* @brief Class for calculating SHA2-512 hash.
*
* @details
* This class has three states:
* - None : Not ready
* - Initialized : Ready to process input data
* - Done : Hash value is calculated
*
* General usage of this class is as follows:
* - Initialize Hash Generator state with @ref initialize().
* - Update hash value with input data with @ref update().
* - Complete hash calculation and export hash value with @ref getHash().
*
* Below is code sample for calculating hash value with one call to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Sha512Generator::kHashSize> hash;
*
* // initialize generator. Sha512Generator is now in a ready state.
* tc::crypto::Sha512Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // read whole file into memory. This is unsafe for large file sizes especially on 32-bit systems.
* tc::ByteData data = tc::ByteData((size_t)stream.length());
* stream.read(data.data(), data.size());
*
* // update generator state with stream data
* impl.update(data.data(), data.size());
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*
* Below is code sample for calculating hash value with sequential calls to @ref update():
* @code
* // open file stream
* auto stream = tc::io::FileStream("a_file.bin", tc::io::FileMode::Open, tc::io::FileAccess::Read);
*
* // create read block (size 512)
* static const size_t kReadBlockSize = 0x200;
* std::array<byte_t, kReadBlockSize> block;
*
* // create array to store hash value
* std::array<byte_t, tc::crypto::Sha512Generator::kHashSize> hash;
*
* // initialize generator. Sha512Generator is now in a ready state.
* tc::crypto::Sha512Generator impl;
* impl.initialize();
*
* // reset stream position to beginning (not strictly necessary for an unused tc::io::FileStream)
* stream.seek(0, tc::io::SeekOrigin::Begin);
*
* // iterate over blocks in stream until no more data can be read
* size_t read_count = 0;
* while ( 0 != (read_count = tc::io::IOUtil::getReadableCount(stream.position(), stream.length(), block.size())) )
* {
* // read block from stream
* stream.read(block.data(), read_count);
*
* // update generator state with stream data
* impl.update(block.data(), read_count);
* }
*
* // complete generator state and write hash value to hash
* impl.getHash(hash.data());
* @endcode
*/
class Sha512Generator
{
public:
static const size_t kAsn1OidDataSize = 19; /**< SHA2-512 ASN.1 Encoded OID length */
static const std::array<byte_t, kAsn1OidDataSize> kAsn1OidData; /**< SHA2-512 ASN.1 Encoded OID */
static const size_t kHashSize = 64; /**< SHA2-512 hash size */
static const size_t kBlockSize = 128; /**< SHA2-512 processing block size */
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
Sha512Generator() :
mImpl(detail::Sha2Impl::SHA2BitSize_512)
{}
/**
* @brief Initializes the hash calculation.
*
* @post
* - Instance is now in a Initialized state
*
* @details
* Resets the hash calculation state to the begin state.
*
* @note
* - This must be called before calculating a new hash.
*/
void initialize()
{
mImpl.initialize();
}
/**
* @brief Update hash value with specified data.
*
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @details
* Data can be input to the generator in one @ref update() call or split across multiple sequential calls.
*
* For example the following scenarios all generate the same hash value.
* @code
* // generate data to be hashed
* tc::ByteData data = tc::ByteData(0x30);
* memset(data.data(), 0xff, data.size());
*
* // create generator instance
* tc::crypto::Sha512Generator impl;
*
* // scenario 1 (one call to update() 0x30 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha512Generator::kHashSize> hash1;
* impl.initialize();
* impl.update(data.data(), data.size());
* impl.getHash(hash1.data());
*
* // scenario 2 (three calls to update() 0x10 bytes each, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha512Generator::kHashSize> hash2;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x10);
* impl.update(data.data() + 0x20, 0x10);
* impl.getHash(hash2.data());
*
* // scenario 3 (two calls to update() one 0x10 bytes, the second 0x20 bytes, totaling 0x30 bytes inputted)
* std::array<byte_t, tc::crypto::Sha512Generator::kHashSize> hash3;
* impl.initialize();
* impl.update(data.data() + 0x00, 0x10);
* impl.update(data.data() + 0x10, 0x20);
* impl.getHash(hash3.data());
* @endcode
*
* @note
* - If input data is broken up into blocks and supplied via multiple @ref update() calls, the order must be consistent with the original input data.
*/
void update(const byte_t* data, size_t data_size)
{
mImpl.update(data, data_size);
}
/**
* @brief Completes hash calculation and output hash value.
*
* @param[out] hash Pointer to buffer storing hash value.
*
* @pre
* - Instance is in either Initialized or Done state.
* - The size of the <tt><var>hash</var></tt> buffer must be >= @ref kHashSize.
*
* @post
* - Instance is now in a Done state.
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @note
* - If the instance is in a None state, then this call does nothing.
*/
void getHash(byte_t* hash)
{
mImpl.getHash(hash);
}
private:
detail::Sha2Impl mImpl;
};
/**
* @brief Utility function for calculating the SHA2-512 hash.
*
* @param[out] hash Pointer to buffer storing hash value.
* @param[in] data Pointer to input data.
* @param[in] data_size Size of input data.
*
* @pre
* - The size of the <tt><var>hash</var></tt> buffer must be >= @ref Sha512Generator::kHashSize.
*
* @post
* - The calculated hash value is written to <tt><var>hash</var></tt>.
*
* @details
* This function calculates the hash value for input passed in the <tt><var>data</var></tt> array.
* To calculate the hash value for input split across multiple arrays, use the @ref Sha512Generator class.
*/
void GenerateSha512Hash(byte_t* hash, const byte_t* data, size_t data_size);
}} // namespace tc::crypto
+167
View File
@@ -0,0 +1,167 @@
/**
* @file XtsEncryptor.h
* @brief Declaration of tc::crypto::XtsEncryptor
* @author Jack (jakcron)
* @version 0.1
* @date 2020/07/04
**/
#pragma once
#include <tc/types.h>
#include <tc/crypto/detail/XtsModeImpl.h>
namespace tc { namespace crypto {
/**
* @class XtsEncryptor
* @brief Class for XTS mode encryption/decryption.
*
* @tparam BlockCipher The class that implements the block cipher used for XTS mode encryption/decryption.
*
* @details
* XTS (<b>X</b>EX mode with cipher<b>t</b>ext <b>s</b>tealing) mode is designed for disk encryption, and as such operates on sectors of data rather than blocks.
* Unlike XEX (<b>X</b>OR <b>e</b>ncrypt <b>X</b>OR) mode the sector size does not have to be a multiple of the block size.
*
* This class is a template class that takes a block cipher implementation class as template parameter.
* See @ref Aes128XtsEncryptor or similar for supplied realizations of this template class.
*
* The implementation of @a BlockCipher must satisfies the following conditions.
* See @ref AesEncryptor or similar class, for more information including parameters to each function.
*
* -# Has a @p kBlockSize constant that defines the size of the block to process.
* -# Has a @p kKeySize constant that defines the required key size to initialize the block cipher.
* -# Has an @p initialize method that initializes the state of the block cipher.
* -# Has an @p encrypt method that encrypts a block of input data.
* -# Has a @p decrypt method that decrypts a block of input data.
*
* This class has two states:
* - None : Not ready
* - Initialized : Ready to process data
*
* General usage of this class is as follows:
* - Initialize XTS state with @ref initialize().
* - Encrypt or decrypt sector(s) using @ref encrypt() or @ref decrypt().
*/
template <class BlockCipher>
class XtsEncryptor
{
public:
static const size_t kKeySize = BlockCipher::kKeySize; /**< XTS mode key size. */
static const size_t kBlockSize = BlockCipher::kBlockSize; /**< XTS mode block processing size. */
/**
* @brief Get specified sector size.
*/
size_t sector_size() const
{
return mImpl.sector_size();
}
/**
* @brief Default constructor.
*
* @post
* - State is None. @ref initialize() must be called before use.
*/
XtsEncryptor() :
mImpl()
{}
/**
* @brief Initializes the XTS encryption state.
*
* @param[in] key1 Pointer to key1 data.
* @param[in] key1_size Size in bytes of key1 data.
* @param[in] key2 Pointer to key2 data.
* @param[in] key2_size Size in bytes of key2 data.
* @param[in] sector_size Size in bytes of the XTS data unit.
* @param[in] tweak_word_order Boolean to determine word order of tweak. True = LittleEndian, False = BigEndian.
*
* @pre
* - @p key1_size == @ref kKeySize.
* - @p key2_size == @ref kKeySize.
* - @p sector_size >= @ref kBlockSize.
*
* @post
* - Instance is now in a Initialized state.
*
* @details
* This resets the XTS state, initializes the two key schedules and the initialization vector (IV).
* The IV should be the IV for sector 0. Using @ref encrypt() / @ref decrypt() will update the IV as required.
*
* @note
* - This must be called before performing encryption/decryption.
*
* @throw tc::ArgumentNullException @p key1 was null.
* @throw tc::ArgumentOutOfRangeException @p key1_size did not equal kKeySize.
* @throw tc::ArgumentNullException @p key2 was null.
* @throw tc::ArgumentOutOfRangeException @p key2_size did not equal kKeySize.
* @throw tc::ArgumentOutOfRangeException @p sector_size was less than kBlockSize.
*/
void initialize(const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order)
{
mImpl.initialize(key1, key1_size, key2, key2_size, sector_size, tweak_word_order);
}
/**
* @brief Encrypts data in multiples of the sector size.
*
* @param[out] dst Buffer where encrypted data will be written.
* @param[in] src Pointer to data to encrypt.
* @param[in] size Size in bytes of data to encrypt.
* @param[in] sector_number Initial sector number of sector to encrypt.
*
* @pre
* - @p size is a multiple of the sector size.
*
* @post
* - Encrypted data is written to @p dst.
*
* @details
* This encrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of the sector size.
*/
void encrypt(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number)
{
mImpl.encrypt(dst, src, size, sector_number);
}
/**
* @brief Decrypts data in multiples of the sector size.
*
* @param[out] dst Buffer where decrypted data will be written.
* @param[in] src Pointer to data to decrypt.
* @param[in] size Size in bytes of data to decrypt.
* @param[in] sector_number Initial sector number of sector to decrypt.
*
* @pre
* - @p size is a multiple of the sector size.
*
* @post
* - Decrypted data is written to @p dst.
*
* @details
* This decrypts the data in @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.
* @throw tc::ArgumentOutOfRangeException @p size was not a multiple of the sector size.
*/
void decrypt(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number)
{
mImpl.decrypt(dst, src, size, sector_number);
}
private:
detail::XtsModeImpl<BlockCipher> mImpl;
};
}} // namespace tc::crypto
+102
View File
@@ -0,0 +1,102 @@
/**
* @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
@@ -0,0 +1,69 @@
/**
* @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
+130
View File
@@ -0,0 +1,130 @@
/**
* @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
+113
View File
@@ -0,0 +1,113 @@
/**
* @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
+147
View File
@@ -0,0 +1,147 @@
/**
* @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
+107
View File
@@ -0,0 +1,107 @@
/**
* @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
+44
View File
@@ -0,0 +1,44 @@
/**
* @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
+159
View File
@@ -0,0 +1,159 @@
/**
* @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
+179
View File
@@ -0,0 +1,179 @@
/**
* @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
+61
View File
@@ -0,0 +1,61 @@
/**
* @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
+119
View File
@@ -0,0 +1,119 @@
/**
* @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
@@ -0,0 +1,79 @@
/**
* @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
@@ -0,0 +1,169 @@
/**
* @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
@@ -0,0 +1,117 @@
/**
* @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
@@ -0,0 +1,260 @@
/**
* @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
+44
View File
@@ -0,0 +1,44 @@
/**
* @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
+57
View File
@@ -0,0 +1,57 @@
/**
* @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
+330
View File
@@ -0,0 +1,330 @@
/**
* @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