mirror of
https://github.com/DarkStore-3DS/Project_CTR.git
synced 2026-07-04 00:39:03 +00:00
Move dependencies to the top level.
This commit is contained in:
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @file tc.h
|
||||
* @brief Declaration of the libtoolchain namespace
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
/**
|
||||
* @namespace tc
|
||||
* @brief Root namespace for libtoolchain
|
||||
**/
|
||||
// classes
|
||||
#include <tc/ByteData.h>
|
||||
#include <tc/Optional.h>
|
||||
|
||||
// sub namespaces
|
||||
#include <tc/string.h>
|
||||
#include <tc/io.h>
|
||||
#include <tc/os.h>
|
||||
#include <tc/crypto.h>
|
||||
#include <tc/cli.h>
|
||||
#include <tc/bn.h>
|
||||
|
||||
// exceptions
|
||||
#include <tc/Exception.h>
|
||||
#include <tc/AccessViolationException.h>
|
||||
#include <tc/ArgumentException.h>
|
||||
#include <tc/ArgumentNullException.h>
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/ArithmeticException.h>
|
||||
#include <tc/InvalidOperationException.h>
|
||||
#include <tc/NotImplementedException.h>
|
||||
#include <tc/NotSupportedException.h>
|
||||
#include <tc/ObjectDisposedException.h>
|
||||
#include <tc/OutOfMemoryException.h>
|
||||
#include <tc/OverflowException.h>
|
||||
#include <tc/UnauthorisedAccessException.h>
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file AccessViolationException.h
|
||||
* @brief Declaration of tc::AccessViolationException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class AccessViolationException
|
||||
* @brief The exception that is thrown when there is an attempt to read or write protected memory.
|
||||
**/
|
||||
class AccessViolationException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
AccessViolationException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
AccessViolationException(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
|
||||
**/
|
||||
AccessViolationException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ArgumentException.h
|
||||
* @brief Declaration of tc::ArgumentException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class ArgumentException
|
||||
* @brief The exception that is thrown when one of the arguments provided to a method is not valid.
|
||||
**/
|
||||
class ArgumentException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
ArgumentException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
ArgumentException(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
|
||||
**/
|
||||
ArgumentException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ArgumentNullException.h
|
||||
* @brief Declaration of tc::ArgumentNullException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/ArgumentException.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class ArgumentNullException
|
||||
* @brief The exception that is thrown when a null reference is passed to a method that does not accept it as a valid argument.
|
||||
**/
|
||||
class ArgumentNullException : public tc::ArgumentException
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
ArgumentNullException() noexcept :
|
||||
tc::ArgumentException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
ArgumentNullException(const std::string& what) noexcept :
|
||||
tc::ArgumentException(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
|
||||
**/
|
||||
ArgumentNullException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::ArgumentException(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ArgumentOutOfRangeException.h
|
||||
* @brief Declaration of tc::ArgumentOutOfRangeException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/ArgumentException.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class ArgumentOutOfRangeException
|
||||
* @brief The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the invoked method.
|
||||
**/
|
||||
class ArgumentOutOfRangeException : public tc::ArgumentException
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
ArgumentOutOfRangeException() noexcept :
|
||||
tc::ArgumentException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
ArgumentOutOfRangeException(const std::string& what) noexcept :
|
||||
tc::ArgumentException(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
|
||||
**/
|
||||
ArgumentOutOfRangeException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::ArgumentException(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ArithmeticException.h
|
||||
* @brief Declaration of tc::ArithmeticException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class ArithmeticException
|
||||
* @brief The exception that is thrown for errors in an arithmetic, casting, or conversion operation.
|
||||
**/
|
||||
class ArithmeticException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
ArithmeticException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
ArithmeticException(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
|
||||
**/
|
||||
ArithmeticException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @file ByteData.h
|
||||
* @brief Declaration of tc::ByteData
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.5
|
||||
* @date 2020/10/31
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#include <tc/OutOfMemoryException.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class ByteData
|
||||
* @brief A container of linear memory, used to hold raw data.
|
||||
**/
|
||||
class ByteData
|
||||
{
|
||||
public:
|
||||
/// Create empty ByteData
|
||||
ByteData();
|
||||
|
||||
/// Copy constructor
|
||||
ByteData(const ByteData& other);
|
||||
|
||||
/// Move constructor
|
||||
ByteData(ByteData&& other);
|
||||
|
||||
/// Create from byte_t initalizer list
|
||||
ByteData(std::initializer_list<byte_t> l);
|
||||
|
||||
/**
|
||||
* @brief Create linear memory block
|
||||
*
|
||||
* @param[in] size Size in bytes of the memory block.
|
||||
* @param[in] clear_memory Clear memory after allocation. Default is true.
|
||||
*
|
||||
* @throw tc::OutOfMemoryException Insuffient memory available.
|
||||
**/
|
||||
ByteData(size_t size, bool clear_memory = true);
|
||||
|
||||
/**
|
||||
* @brief Create ByteData from existing memory.
|
||||
*
|
||||
* @param[in] data Pointer to memory to copy.
|
||||
* @param[in] size Size of memory to copy.
|
||||
*
|
||||
* @throw tc::OutOfMemoryException Insuffient memory available.
|
||||
**/
|
||||
ByteData(const byte_t* data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator (deep copy)
|
||||
**/
|
||||
ByteData& operator=(const ByteData& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment
|
||||
**/
|
||||
ByteData& operator=(ByteData&& other);
|
||||
|
||||
/**
|
||||
* @brief Element access operator
|
||||
**/
|
||||
byte_t& operator[](size_t index);
|
||||
|
||||
/**
|
||||
* @brief Const Element access operator
|
||||
**/
|
||||
byte_t operator[](size_t index) const;
|
||||
|
||||
/**
|
||||
* @brief Equality operator
|
||||
*/
|
||||
bool operator==(const ByteData& other) const;
|
||||
|
||||
/**
|
||||
* @brief Inequality operator
|
||||
*/
|
||||
bool operator!=(const ByteData& other) const;
|
||||
|
||||
/**
|
||||
* @brief Get data pointer
|
||||
*
|
||||
* @return nullptr if @ref size() == 0
|
||||
**/
|
||||
byte_t* data() const;
|
||||
|
||||
/**
|
||||
* @brief Get data size
|
||||
**/
|
||||
size_t size() const;
|
||||
private:
|
||||
static const std::string kClassName;
|
||||
|
||||
size_t mSize;
|
||||
std::unique_ptr<byte_t> mPtr;
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file Exception.h
|
||||
* @brief Declaration of tc::Exception
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2019/01/15
|
||||
**/
|
||||
#pragma once
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class Exception
|
||||
* @brief An extension of std::exception that allows optionally specifying a module name
|
||||
**/
|
||||
class Exception : public std::exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
Exception() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* Inherited from std::exception
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
Exception(const std::string& what) noexcept;
|
||||
|
||||
/**
|
||||
* @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
|
||||
**/
|
||||
Exception(const std::string& module, const std::string& what) noexcept;
|
||||
|
||||
/// Get explanation for exception (inherited from std::exception)
|
||||
const char* what() const noexcept;
|
||||
|
||||
/// Get module tag
|
||||
const char* module() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get explanation for exception
|
||||
*
|
||||
* Omits the module tag from the description
|
||||
*
|
||||
* @returns exception description
|
||||
**/
|
||||
const char* error() const noexcept;
|
||||
private:
|
||||
std::string what_;
|
||||
std::string module_;
|
||||
std::string error_;
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file InvalidOperationException.h
|
||||
* @brief Declaration of tc::InvalidOperationException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class InvalidOperationException
|
||||
* @brief The exception that is thrown when a method call is invalid for the object's current state.
|
||||
**/
|
||||
class InvalidOperationException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
InvalidOperationException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
InvalidOperationException(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
|
||||
**/
|
||||
InvalidOperationException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file NotImplementedException.h
|
||||
* @brief Declaration of tc::NotImplementedException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class NotImplementedException
|
||||
* @brief The exception that is thrown when a requested method or operation is not implemented.
|
||||
**/
|
||||
class NotImplementedException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
NotImplementedException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
NotImplementedException(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
|
||||
**/
|
||||
NotImplementedException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file NotSupportedException.h
|
||||
* @brief Declaration of tc::NotSupportedException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class NotSupportedException
|
||||
* @brief The exception that is thrown when an invoked method is not supported, or when there is an attempt to read, seek, or write to a stream that does not support the invoked functionality.
|
||||
**/
|
||||
class NotSupportedException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
NotSupportedException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
NotSupportedException(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
|
||||
**/
|
||||
NotSupportedException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ObjectDisposedException.h
|
||||
* @brief Declaration of tc::ObjectDisposedException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/InvalidOperationException.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class ObjectDisposedException
|
||||
* @brief The exception that is thrown when an operation is performed on a disposed object.
|
||||
**/
|
||||
class ObjectDisposedException : public tc::InvalidOperationException
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
ObjectDisposedException() noexcept :
|
||||
tc::InvalidOperationException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
ObjectDisposedException(const std::string& what) noexcept :
|
||||
tc::InvalidOperationException(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
|
||||
**/
|
||||
ObjectDisposedException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::InvalidOperationException(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @file Optional.h
|
||||
* @brief Declaration of tc::Optional
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2019/01/06
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class Optional
|
||||
* @brief A wrapper class, where the existence of the wrapped value is optional.
|
||||
**/
|
||||
template <class T>
|
||||
class Optional
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*
|
||||
* This Optional shall be null initially.
|
||||
**/
|
||||
Optional();
|
||||
|
||||
/**
|
||||
* @brief Initialising constructor with value to wrap
|
||||
* @param[in] value const T& Reference to value to wrap
|
||||
*
|
||||
* This Optional shall be not null initially.
|
||||
**/
|
||||
Optional(const T& value);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param[in] other const Optional<T>& Reference to Optional object to copy
|
||||
*
|
||||
* This Optional shall be not null initially.
|
||||
**/
|
||||
Optional(const Optional<T>& other);
|
||||
|
||||
/// Operator to wrap a value
|
||||
void operator=(const T& value);
|
||||
|
||||
/// Operator to duplicate another Optional
|
||||
void operator=(const Optional<T>& other);
|
||||
|
||||
/**
|
||||
* @brief Access the wrapped value
|
||||
* @return T& reference to value
|
||||
**/
|
||||
T& get() const;
|
||||
|
||||
/**
|
||||
* @brief Determine if the Optional value doesn't exist
|
||||
* @return bool true if the value does not exist.
|
||||
**/
|
||||
bool isNull() const;
|
||||
|
||||
/**
|
||||
* @brief Determine if the Optional value exists
|
||||
* @return bool true if the value exists.
|
||||
**/
|
||||
bool isSet() const;
|
||||
|
||||
/**
|
||||
* @brief Release the wrapped value
|
||||
*
|
||||
* This will destroy the wrapped value and make this Optional null.
|
||||
* If this Optional is already null, this does nothing.
|
||||
**/
|
||||
void makeNull();
|
||||
private:
|
||||
std::shared_ptr<T> mValue;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline Optional<T>::Optional() :
|
||||
mValue()
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline Optional<T>::Optional(const T& value) :
|
||||
Optional()
|
||||
{
|
||||
*this = value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline Optional<T>::Optional(const Optional<T>& other) :
|
||||
Optional()
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void Optional<T>::operator=(const T& value)
|
||||
{
|
||||
// if mValue is null we need to allocate memory for it
|
||||
if (mValue == nullptr)
|
||||
{
|
||||
mValue = std::shared_ptr<T>(new T);
|
||||
}
|
||||
|
||||
// assign the value
|
||||
*mValue = value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void Optional<T>::operator=(const Optional<T>& other)
|
||||
{
|
||||
// if the other is null, then we make this null
|
||||
if (other.isNull())
|
||||
{
|
||||
this->makeNull();
|
||||
}
|
||||
// otherwise we have to assign this with the unwrapped mValue of other
|
||||
else
|
||||
{
|
||||
*this = other.get();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T& Optional<T>::get() const
|
||||
{
|
||||
return *mValue;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool Optional<T>::isNull() const
|
||||
{
|
||||
return mValue == nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool Optional<T>::isSet() const
|
||||
{
|
||||
return mValue != nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void Optional<T>::makeNull()
|
||||
{
|
||||
mValue.reset();
|
||||
}
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file OutOfMemoryException.h
|
||||
* @brief Declaration of tc::OutOfMemoryException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class OutOfMemoryException
|
||||
* @brief The exception that is thrown when there is not enough memory to continue the execution of a program.
|
||||
**/
|
||||
class OutOfMemoryException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
OutOfMemoryException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
OutOfMemoryException(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
|
||||
**/
|
||||
OutOfMemoryException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file OverflowException.h
|
||||
* @brief Declaration of tc::OverflowException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/ArithmeticException.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class OverflowException
|
||||
* @brief The exception that is thrown when an arithmetic, casting, or conversion operation in a checked context results in an overflow.
|
||||
**/
|
||||
class OverflowException : public tc::ArithmeticException
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
OverflowException() noexcept :
|
||||
tc::ArithmeticException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
OverflowException(const std::string& what) noexcept :
|
||||
tc::ArithmeticException(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
|
||||
**/
|
||||
OverflowException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::ArithmeticException(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file PlatformErrorHandlingUtil.h
|
||||
* @brief Declaration of tc::PlatformErrorHandlingUtil
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/04/09
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace tc
|
||||
{
|
||||
/**
|
||||
* @class PlatformErrorHandlingUtil
|
||||
* @brief Platform specific error handling utilities.
|
||||
**/
|
||||
class PlatformErrorHandlingUtil
|
||||
{
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief Create a string from Win32 error code.
|
||||
*
|
||||
* @param[in] error Error code, returned from GetLastError().
|
||||
*
|
||||
* @return Error as a localised string.
|
||||
**/
|
||||
static std::string GetLastErrorString(DWORD error);
|
||||
#else
|
||||
/**
|
||||
* @brief Create a string from GNU error number.
|
||||
*
|
||||
* @param[in] errnum Error code, returned from @a errno macro.
|
||||
*
|
||||
* @return Error as a localised string.
|
||||
**/
|
||||
static std::string GetGnuErrorNumString(int errnum);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file ResourceStatus.h
|
||||
* @brief Declaration of tc::ResourceStatus
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2019/01/16
|
||||
**/
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @enum ResourceStatusFlag
|
||||
* @brief Flags for ResourceStatus
|
||||
**/
|
||||
enum ResourceStatusFlag
|
||||
{
|
||||
RESFLAG_READY, /**< Resource is ready for use */
|
||||
RESFLAG_ERROR, /**< Resource encountered an error */
|
||||
RESFLAG_NOINIT, /**< Resource is not initialized */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Bitset indicating resource state information (see @ref ResourceStatusFlag)
|
||||
**/
|
||||
using ResourceStatus = std::bitset<32>;
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file SecurityException.h
|
||||
* @brief Declaration of tc::SecurityException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2022/02/06
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class SecurityException
|
||||
* @brief The exception that is thrown when a security error is detected.
|
||||
**/
|
||||
class SecurityException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
SecurityException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
SecurityException(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
|
||||
**/
|
||||
SecurityException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file UnauthorisedAccessException.h
|
||||
* @brief Declaration of tc::UnauthorisedAccessException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/Exception.h>
|
||||
|
||||
namespace tc {
|
||||
|
||||
/**
|
||||
* @class UnauthorisedAccessException
|
||||
* @brief The exception that is thrown when the operating system denies access because of an I/O error or a specific type of security error.
|
||||
**/
|
||||
class UnauthorisedAccessException : public tc::Exception
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
UnauthorisedAccessException() noexcept :
|
||||
tc::Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
UnauthorisedAccessException(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
|
||||
**/
|
||||
UnauthorisedAccessException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::Exception(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tc
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @file bn.h
|
||||
* @brief Declaration of the binary literals library
|
||||
*/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/Exception.h>
|
||||
|
||||
/**
|
||||
* @namespace tc::bn
|
||||
* @brief Namespace of the binary literals library
|
||||
*/
|
||||
#include <tc/bn/binary_utils.h>
|
||||
#include <tc/bn/endian_types.h>
|
||||
#include <tc/bn/bitarray.h>
|
||||
#include <tc/bn/string.h>
|
||||
#include <tc/bn/pad.h>
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file binary_utils.h
|
||||
* @brief Declaration of inlines and classes for literal bit manipulation and other low-level operations.
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/12/20
|
||||
*/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc { namespace bn {
|
||||
|
||||
/**
|
||||
* @brief Generate struct magic 32bit number.
|
||||
* @details This generates a little endian 32bit integer from char[4].
|
||||
*
|
||||
* @param[in] magic Pointer to array of magic bytes.
|
||||
*
|
||||
* @return Little endian magic uint32_t.
|
||||
*/
|
||||
constexpr uint32_t make_struct_magic_uint32(const char magic[4])
|
||||
{
|
||||
return uint32_t((uint32_t)(magic[3]) << 24 | (uint32_t)(magic[2]) << 16 | (uint32_t)(magic[1]) << 8 | (uint32_t)(magic[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate struct magic 64bit number.
|
||||
* @details This generates a little endian 64bit integer from char[8].
|
||||
*
|
||||
* @param[in] magic Pointer to array of magic bytes.
|
||||
*
|
||||
* @return Little endian magic uint64_t.
|
||||
*/
|
||||
constexpr uint64_t make_struct_magic_uint64(const char magic[8])
|
||||
{
|
||||
return uint64_t((uint64_t)(magic[7]) << 56 | (uint64_t)(magic[6]) << 48 | (uint64_t)(magic[5]) << 40 | (uint64_t)(magic[4]) << 32 | (uint64_t)(magic[3]) << 24 | (uint64_t)(magic[2]) << 16 | (uint64_t)(magic[1]) << 8 | (uint64_t)(magic[0]));
|
||||
}
|
||||
|
||||
}} // namespace tc::bn
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file bitarray.h
|
||||
* @brief Declaration of tc::bn::bitarray
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2021/02/27
|
||||
*/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc { namespace bn {
|
||||
|
||||
/**
|
||||
* @struct bitarray
|
||||
* @brief This struct is a literal bitarray, with configurable byte and bit endianness.
|
||||
*
|
||||
* @tparam T size in bytes of the bitarray.
|
||||
* @tparam byte_order_le Boolean, true: byte order is little endian, false: byte order is big endian.
|
||||
* @tparam bit_order_le Boolean, true: bit order is little endian, false: bit order is big endian.
|
||||
*
|
||||
* @details
|
||||
* This struct is meant to be used when defining written-to-disk structures, like file headers.
|
||||
*/
|
||||
template <size_t T, bool byte_order_le = true, bool bit_order_le = true>
|
||||
struct bitarray
|
||||
{
|
||||
public:
|
||||
#define __BITARRAY_BYTE_INDEX_MATH(x) (byte_order_le? (x / 8) : (T - 1 - (x / 8)))
|
||||
#define __BITARRAY_BIT_INDEX_MATH(x) (bit_order_le? (1 << (x % 8)) : (1 << (7 - (x % 8))))
|
||||
|
||||
/// Returns the size in bits of this bitarray
|
||||
size_t bit_size() const { return T * 8; }
|
||||
|
||||
/// Sets a given bit in this bitarray
|
||||
void set(size_t bit)
|
||||
{
|
||||
bit %= (T*8);
|
||||
mArray[__BITARRAY_BYTE_INDEX_MATH(bit)] |= __BITARRAY_BIT_INDEX_MATH(bit);
|
||||
}
|
||||
|
||||
/// Clears a given bit in this bitarray
|
||||
void reset(size_t bit)
|
||||
{
|
||||
bit %= (T*8);
|
||||
mArray[__BITARRAY_BYTE_INDEX_MATH(bit)] &= ~(uint8_t(__BITARRAY_BIT_INDEX_MATH(bit)));
|
||||
}
|
||||
|
||||
/// Flips a given bit in this bitarray
|
||||
void flip(size_t bit)
|
||||
{
|
||||
bit %= (T*8);
|
||||
test(bit) ? reset(bit) : set(bit);
|
||||
}
|
||||
|
||||
/// Checks a given bit in this bitarray
|
||||
bool test(size_t bit) const
|
||||
{
|
||||
bit %= (T*8);
|
||||
return (mArray[__BITARRAY_BYTE_INDEX_MATH(bit)] & (__BITARRAY_BIT_INDEX_MATH(bit))) != 0;
|
||||
}
|
||||
|
||||
#undef __BITARRAY_BYTE_INDEX_MATH
|
||||
#undef __BITARRAY_BIT_INDEX_MATH
|
||||
|
||||
private:
|
||||
std::array<uint8_t, T> mArray;
|
||||
};
|
||||
|
||||
}} // namespace tc::bn
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
/**
|
||||
* @file endian_types.h
|
||||
* @brief Declaration of macros and classes to unwrap primatives in an endian agnostic way.
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/12/05
|
||||
**/
|
||||
#pragma once
|
||||
#include <cinttypes>
|
||||
#include <type_traits>
|
||||
|
||||
namespace tc { namespace bn { namespace detail {
|
||||
|
||||
static inline uint16_t __local_bswap16(uint16_t x) {
|
||||
return ((x << 8) & 0xff00) | ((x >> 8) & 0x00ff);
|
||||
}
|
||||
|
||||
static inline void __local_bswap16(void* x) {
|
||||
uint16_t tmp = *((uint16_t*)x);
|
||||
*((uint16_t*)x) = ((tmp << 8) & 0xff00) | ((tmp >> 8) & 0x00ff);
|
||||
}
|
||||
|
||||
static inline uint32_t __local_bswap32(uint32_t x) {
|
||||
return ((x << 24) & 0xff000000 ) |
|
||||
((x << 8) & 0x00ff0000 ) |
|
||||
((x >> 8) & 0x0000ff00 ) |
|
||||
((x >> 24) & 0x000000ff );
|
||||
}
|
||||
|
||||
static inline void __local_bswap32(void* x) {
|
||||
uint32_t tmp = *((uint32_t*)x);
|
||||
*((uint32_t*)x) = ((tmp << 24) & 0xff000000 ) |
|
||||
((tmp << 8) & 0x00ff0000 ) |
|
||||
((tmp >> 8) & 0x0000ff00 ) |
|
||||
((tmp >> 24) & 0x000000ff );
|
||||
}
|
||||
|
||||
static inline uint64_t __local_bswap64(uint64_t x)
|
||||
{
|
||||
return (uint64_t)__local_bswap32(x>>32) |
|
||||
((uint64_t)__local_bswap32(x&0xFFFFFFFF) << 32);
|
||||
}
|
||||
|
||||
static inline void __local_bswap64(void* x) {
|
||||
uint64_t tmp = *((uint64_t*)x);
|
||||
*((uint64_t*)x) = ((uint64_t)(tmp << 56) & (uint64_t)0xff00000000000000ULL ) |
|
||||
((uint64_t)(tmp << 40) & (uint64_t)0x00ff000000000000ULL ) |
|
||||
((uint64_t)(tmp << 24) & (uint64_t)0x0000ff0000000000ULL ) |
|
||||
((uint64_t)(tmp << 8) & (uint64_t)0x000000ff00000000ULL ) |
|
||||
((uint64_t)(tmp >> 8) & (uint64_t)0x00000000ff000000ULL ) |
|
||||
((uint64_t)(tmp >> 24) & (uint64_t)0x0000000000ff0000ULL ) |
|
||||
((uint64_t)(tmp >> 40) & (uint64_t)0x000000000000ff00ULL ) |
|
||||
((uint64_t)(tmp >> 56) & (uint64_t)0x00000000000000ffULL );
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
static inline uint64_t __be_uint64(uint64_t a) { return __local_bswap64(a); }
|
||||
static inline uint32_t __be_uint32(uint32_t a) { return __local_bswap32(a); }
|
||||
static inline uint16_t __be_uint16(uint16_t a) { return __local_bswap16(a); }
|
||||
static inline uint64_t __le_uint64(uint64_t a) { return a; }
|
||||
static inline uint32_t __le_uint32(uint32_t a) { return a; }
|
||||
static inline uint16_t __le_uint16(uint16_t a) { return a; }
|
||||
|
||||
static inline void __be_swap64(void* a) { __local_bswap64(a); }
|
||||
static inline void __be_swap32(void* a) { __local_bswap32(a); }
|
||||
static inline void __be_swap16(void* a) { __local_bswap16(a); }
|
||||
static inline void __le_swap64(void* a) { return; }
|
||||
static inline void __le_swap32(void* a) { return; }
|
||||
static inline void __le_swap16(void* a) { return; }
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
static inline uint64_t __be_uint64(uint64_t a) { return a; }
|
||||
static inline uint32_t __be_uint32(uint32_t a) { return a; }
|
||||
static inline uint16_t __be_uint16(uint16_t a) { return a; }
|
||||
static inline uint64_t __le_uint64(uint64_t a) { return __local_bswap64(a); }
|
||||
static inline uint32_t __le_uint32(uint32_t a) { return __local_bswap32(a); }
|
||||
static inline uint16_t __le_uint16(uint16_t a) { return __local_bswap16(a); }
|
||||
|
||||
static inline void __be_swap64(void* a) { return; }
|
||||
static inline void __be_swap32(void* a) { return; }
|
||||
static inline void __be_swap16(void* a) { return; }
|
||||
static inline void __le_swap64(void* a) { __local_bswap64(a); }
|
||||
static inline void __le_swap32(void* a) { __local_bswap32(a); }
|
||||
static inline void __le_swap16(void* a) { __local_bswap16(a); }
|
||||
#endif
|
||||
|
||||
}}} // namespace tc::bn::detail
|
||||
|
||||
namespace tc { namespace bn {
|
||||
|
||||
/**
|
||||
* @struct le16
|
||||
* @brief Wrapper that allows accessing a little-endian 16-bit POD regardless of processor endianness
|
||||
**/
|
||||
template <typename T>
|
||||
struct le16 {
|
||||
public:
|
||||
static_assert(sizeof(T) == sizeof(uint16_t), "le16 requires T to be 16 bit.");
|
||||
static_assert(std::is_pod<T>::value, "le16 requires T to be a POD.");
|
||||
|
||||
/// Unwrap value (Implicit)
|
||||
operator T() const { return unwrap(); }
|
||||
/// Wrap value (Implicit)
|
||||
le16& operator=(const T& var) { wrap(var); return *this; }
|
||||
|
||||
/// Unwrap value
|
||||
inline T unwrap() const { T tmp = mVar; detail::__le_swap16(&tmp); return tmp; }
|
||||
/// Wrap value
|
||||
inline void wrap(const T& var) { mVar = var; detail::__le_swap16(&mVar); }
|
||||
private:
|
||||
T mVar;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct be16
|
||||
* @brief Wrapper that allows accessing a big-endian 16-bit POD regardless of processor endianness
|
||||
**/
|
||||
template <typename T>
|
||||
struct be16 {
|
||||
public:
|
||||
static_assert(sizeof(T) == sizeof(uint16_t), "be16 requires T to be 16 bit.");
|
||||
static_assert(std::is_pod<T>::value, "be16 requires T to be a POD.");
|
||||
|
||||
/// Unwrap value (Implicit)
|
||||
operator T() const { return unwrap(); }
|
||||
/// Wrap value (Implicit)
|
||||
be16& operator=(const T& var) { wrap(var); return *this; }
|
||||
|
||||
/// Unwrap value
|
||||
inline T unwrap() const { T tmp = mVar; detail::__be_swap16(&tmp); return tmp; }
|
||||
/// Wrap value
|
||||
inline void wrap(const T& var) { mVar = var; detail::__be_swap16(&mVar); }
|
||||
private:
|
||||
T mVar;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct le32
|
||||
* @brief Wrapper that allows accessing a little-endian 32-bit POD regardless of processor endianness
|
||||
**/
|
||||
template <typename T>
|
||||
struct le32 {
|
||||
public:
|
||||
static_assert(sizeof(T) == sizeof(uint32_t), "le32 requires T to be 32 bit.");
|
||||
static_assert(std::is_pod<T>::value, "le32 requires T to be a POD.");
|
||||
|
||||
/// Unwrap value (Implicit)
|
||||
operator T() const { return unwrap(); }
|
||||
/// Wrap value (Implicit)
|
||||
le32& operator=(const T& var) { wrap(var); return *this; }
|
||||
|
||||
/// Unwrap value
|
||||
inline T unwrap() const { T tmp = mVar; detail::__le_swap32(&tmp); return tmp; }
|
||||
/// Wrap value
|
||||
inline void wrap(const T& var) { mVar = var; detail::__le_swap32(&mVar); }
|
||||
private:
|
||||
T mVar;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct be32
|
||||
* @brief Wrapper that allows accessing a big-endian 32-bit POD regardless of processor endianness
|
||||
**/
|
||||
template <typename T>
|
||||
struct be32 {
|
||||
public:
|
||||
static_assert(sizeof(T) == sizeof(uint32_t), "be32 requires T to be 32 bit.");
|
||||
static_assert(std::is_pod<T>::value, "be32 requires T to be a POD.");
|
||||
|
||||
/// Unwrap value (Implicit)
|
||||
operator T() const { return unwrap(); }
|
||||
/// Wrap value (Implicit)
|
||||
be32& operator=(const T& var) { wrap(var); return *this; }
|
||||
|
||||
/// Unwrap value
|
||||
inline T unwrap() const { T tmp = mVar; detail::__be_swap32(&tmp); return tmp; }
|
||||
/// Wrap value
|
||||
inline void wrap(const T& var) { mVar = var; detail::__be_swap32(&mVar); }
|
||||
private:
|
||||
T mVar;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct le64
|
||||
* @brief Wrapper that allows accessing a little-endian 64-bit POD regardless of processor endianness
|
||||
**/
|
||||
template <typename T>
|
||||
struct le64 {
|
||||
public:
|
||||
static_assert(sizeof(T) == sizeof(uint64_t), "le64 requires T to be 64 bit.");
|
||||
static_assert(std::is_pod<T>::value, "le64 requires T to be a POD.");
|
||||
|
||||
/// Unwrap value (Implicit)
|
||||
operator T() const { return unwrap(); }
|
||||
/// Wrap value (Implicit)
|
||||
le64& operator=(const T& var) { wrap(var); return *this; }
|
||||
|
||||
/// Unwrap value
|
||||
inline T unwrap() const { T tmp = mVar; detail::__le_swap64(&tmp); return tmp; }
|
||||
/// Wrap value
|
||||
inline void wrap(const T& var) { mVar = var; detail::__le_swap64(&mVar); }
|
||||
private:
|
||||
T mVar;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct be64
|
||||
* @brief Wrapper that allows accessing a big-endian 64-bit POD regardless of processor endianness
|
||||
**/
|
||||
template <typename T>
|
||||
struct be64 {
|
||||
public:
|
||||
static_assert(sizeof(T) == sizeof(uint64_t), "be64 requires T to be 64 bit.");
|
||||
static_assert(std::is_pod<T>::value, "be64 requires T to be a POD.");
|
||||
|
||||
/// Unwrap value (Implicit)
|
||||
operator T() const { return unwrap(); }
|
||||
/// Wrap value (Implicit)
|
||||
be64& operator=(const T& var) { wrap(var); return *this; }
|
||||
|
||||
/// Unwrap value
|
||||
inline T unwrap() const { T tmp = mVar; detail::__be_swap64(&tmp); return tmp; }
|
||||
/// Wrap value
|
||||
inline void wrap(const T& var) { mVar = var; detail::__be_swap64(&mVar); }
|
||||
private:
|
||||
T mVar;
|
||||
};
|
||||
|
||||
}} // namespace tc::bn
|
||||
|
||||
namespace tc { namespace bn {
|
||||
|
||||
|
||||
}} // namespace tc::bn
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file pad.h
|
||||
* @brief Declaration of tc::bn::pad
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2022/02/05
|
||||
*/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc { namespace bn {
|
||||
|
||||
/**
|
||||
* @class pad
|
||||
* @brief This class creates padding.
|
||||
*
|
||||
* @tparam T size in bytes of the padding.
|
||||
*/
|
||||
template <size_t T>
|
||||
class pad
|
||||
{
|
||||
public:
|
||||
/// Returns size of padding in bytes
|
||||
size_t size() const { return mArray.size(); }
|
||||
private:
|
||||
std::array<uint8_t, T> mArray;
|
||||
};
|
||||
|
||||
}} // namespace tc::bn
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @file string.h
|
||||
* @brief Declaration of tc::bn::string
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.3
|
||||
* @date 2022/02/05
|
||||
*/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
|
||||
namespace tc { namespace bn {
|
||||
|
||||
/**
|
||||
* @class string
|
||||
* @brief This class represents a literal char array.
|
||||
*
|
||||
* @tparam ENCODED_SIZE Literal size of the string structure. sizeof() will return this size.
|
||||
* @tparam LOGICAL_SIZE Logical maximum size of the string, LOGICAL_SIZE <= ENCODED_SIZE.
|
||||
*
|
||||
* @details The intended for use is for defining structures read from files.
|
||||
*
|
||||
* Consider this structure read from a file with some comments from the spec:
|
||||
* @code
|
||||
* struct MyStruct
|
||||
* {
|
||||
* uint32_t version;
|
||||
* char product_sku[16]; // ASCII but not NULL terminated, so 16 usable characters
|
||||
* char product_title[32]; // ASCII but must be NULL terminated, so only 31 usable chars
|
||||
* uint32_t product_version;
|
||||
* };
|
||||
* @endcode
|
||||
* The member @c product_sku according to specification can have all 16 chars populated, and if all 16 chars
|
||||
* are populated it isn't guarenteed to be null terminated. The member @c product_title according to specification
|
||||
* must be null terminated, reserving one byte for the null byte. This isn't the same behaviour as @c product_sku,
|
||||
* requiring different string logic specific to this one struct. But these constraints can be enforced into the
|
||||
* defintion of MyStruct using @ref tc::bn::string.
|
||||
*
|
||||
* Consider this revised struct using tc::bn::string :
|
||||
* @code
|
||||
* struct MyStruct
|
||||
* {
|
||||
* uint32_t version;
|
||||
* tc::bn::string<16> product_sku; // this has a ENCODED_SIZE & LOGICAL_SIZE of 16 bytes which mean's the size on disk is 16 bytes and there are 16 usable characters
|
||||
* tc::bn::string<32,31> product_title; // this has a ENCODED_SIZE of 32 bytes & LOGICAL_SIZE of 31 bytes which mean's the size on disk is 32 bytes and there are 31 usable characters
|
||||
* uint32_t product_version;
|
||||
* };
|
||||
* @endcode
|
||||
* In the above struct the correct size of @c product_sku and @c product_title are preserved while also enforcing the logical size of the string.
|
||||
*
|
||||
* To get the maximum length a string can be for a given tc::bn::string, use @ref max_size():
|
||||
* @code
|
||||
* MyStruct st;
|
||||
* size_t product_sku_max_size = st.product_sku.max_size(); // 16
|
||||
* size_t product_title_max_size = st.product_title.max_size(); // 31
|
||||
* @endcode
|
||||
*
|
||||
* To get the current string length for a given tc::bn::string, use @ref size():
|
||||
* @code
|
||||
* MyStruct st;
|
||||
* size_t product_sku_str_size = st.product_sku.size();
|
||||
* size_t product_title_str_size = st.product_title.size();
|
||||
* @endcode
|
||||
*
|
||||
* To decode the data in a tc::bn::string to a std::string, use @ref decode():
|
||||
* @code
|
||||
* MyStruct st;
|
||||
* std::string product_sku = st.product_sku.decode();
|
||||
* std::string product_title = st.product_title.decode();
|
||||
* @endcode
|
||||
*
|
||||
* To encode a std::string into a tc::bn::string, use @ref encode():
|
||||
* @code
|
||||
* MyStruct st;
|
||||
* st.product_sku.encode("SKU-1234-X");
|
||||
* st.product_title.encode("MyProductTitle");
|
||||
* @endcode
|
||||
*/
|
||||
template <size_t ENCODED_SIZE, size_t LOGICAL_SIZE = ENCODED_SIZE>
|
||||
class string
|
||||
{
|
||||
public:
|
||||
static_assert(ENCODED_SIZE >= LOGICAL_SIZE, "literal string had a logical size greater than the encoded size.");
|
||||
|
||||
/// Access specific element
|
||||
const char& operator[](size_t index) const { return mRawString[index]; }
|
||||
|
||||
/// Access specific element
|
||||
char& operator[](size_t index) { return mRawString[index]; }
|
||||
|
||||
/// Direct access to the underlying array
|
||||
const char* data() const { return mRawString.data(); }
|
||||
|
||||
/// Direct access to the underlying array
|
||||
char* data() { return mRawString.data(); }
|
||||
|
||||
/// Returns maximum possible length for this string
|
||||
size_t max_size() const { return LOGICAL_SIZE; }
|
||||
|
||||
/// Returns length of string
|
||||
size_t size() const
|
||||
{
|
||||
size_t chr_count = 0;
|
||||
|
||||
for (; chr_count < LOGICAL_SIZE; chr_count++)
|
||||
{
|
||||
if (mRawString[chr_count] == 0) break;
|
||||
}
|
||||
|
||||
return chr_count;
|
||||
}
|
||||
|
||||
/// Returns a std::string created from the underlying char array
|
||||
std::string decode() const { return std::string(this->data(), this->size()); }
|
||||
|
||||
/// Encode the underlying char array from a std::string
|
||||
void encode(const std::string& source_str)
|
||||
{
|
||||
size_t chr_count = 0;
|
||||
|
||||
// copy chars from source_str
|
||||
for (; chr_count < LOGICAL_SIZE; chr_count++)
|
||||
{
|
||||
// skip if chr count exceeds the size of the string, or the string char is null byte
|
||||
if (chr_count >= source_str.size()) break;
|
||||
if (source_str[chr_count] == 0) break;
|
||||
|
||||
mRawString[chr_count] = source_str[chr_count];
|
||||
}
|
||||
|
||||
// clear remaining chars
|
||||
for (; chr_count < LOGICAL_SIZE; chr_count++)
|
||||
{
|
||||
mRawString[chr_count] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<char, ENCODED_SIZE> mRawString;
|
||||
};
|
||||
|
||||
}} // namespace tc::bn
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file cli.h
|
||||
* @brief Declaration of the command-line interface (CLI) library
|
||||
*/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/Exception.h>
|
||||
|
||||
/**
|
||||
* @namespace tc::cli
|
||||
* @brief Namespace of the command-line interface (CLI) library
|
||||
*/
|
||||
#include <tc/cli/FormatUtil.h>
|
||||
#include <tc/cli/OptionParser.h>
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @file FormatUtil.h
|
||||
* @brief Declaration of tc::cli::FormatUtil
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.2
|
||||
* @date 2020/12/31
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/ByteData.h>
|
||||
|
||||
namespace tc { namespace cli {
|
||||
|
||||
/**
|
||||
* @class FormatUtil
|
||||
* @brief A collection of utilities to format binary data as strings and vice-versa.
|
||||
**/
|
||||
class FormatUtil
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Convert a hexadecimal string to bytes.
|
||||
*
|
||||
* @param[in] str Hexadecimal string to convert.
|
||||
*
|
||||
* @return Converted string as bytes.
|
||||
*
|
||||
* @post ByteData returned will be empty if the string has encoding errors.
|
||||
**/
|
||||
static tc::ByteData hexStringToBytes(const std::string& str);
|
||||
|
||||
/**
|
||||
* @brief Format raw bytes as a hexadecimal string.
|
||||
*
|
||||
* @param[in] data Pointer to bytes to format.
|
||||
* @param[in] size Size of data to format.
|
||||
* @param[in] is_upper_case Format bytes in upper case. If false the bytes will be formatted in lower case.
|
||||
* @param[in] delimiter String to separate formated bytes with.
|
||||
*
|
||||
* @return Formatted string
|
||||
**/
|
||||
static std::string formatBytesAsString(const byte_t* data, size_t size, bool is_upper_case, const std::string& delimiter);
|
||||
|
||||
/**
|
||||
* @brief Format tc::ByteData as a hexadecimal string.
|
||||
*
|
||||
* @param[in] data Reference to tc::ByteData object to format.
|
||||
* @param[in] is_upper_case Format bytes in upper case. If false the bytes will be formatted in lower case.
|
||||
* @param[in] delimiter String to separate formated bytes with.
|
||||
*
|
||||
* @return Formatted string
|
||||
**/
|
||||
static std::string formatBytesAsString(const tc::ByteData& data, bool is_upper_case, const std::string& delimiter);
|
||||
|
||||
/**
|
||||
* @brief Format raw bytes as a hexadecimal string. Introducing a new-line to keep each row within a certain size.
|
||||
*
|
||||
* @param[in] data Pointer to bytes to format.
|
||||
* @param[in] size Size of data to format.
|
||||
* @param[in] is_upper_case Format bytes in upper case. If false the bytes will be formatted in lower case.
|
||||
* @param[in] delimiter String to separate formated bytes with.
|
||||
* @param[in] row_len Maximum length each row can be before a newline is introduced.
|
||||
* @param[in] indent_len Length of spaces each new line should be indented.
|
||||
* @param[in] print_first_indent Print the indent for the first line, default is true.
|
||||
*
|
||||
* @return Formatted string
|
||||
**/
|
||||
static std::string formatBytesAsStringWithLineLimit(const byte_t* data, size_t size, bool is_upper_case, const std::string& delimiter, size_t row_len, size_t indent_len, bool print_first_indent = true);
|
||||
|
||||
/**
|
||||
* @brief Format a list of strings as comma delimited. Introducing a new-line to keep each row within a certain size.
|
||||
*
|
||||
* @param[in] str_list List of strings to print.
|
||||
* @param[in] row_len Maximum length each row can be before a newline is introduced.
|
||||
* @param[in] indent_len Length of spaces each new line should be indented.
|
||||
* @param[in] print_first_indent Print the indent for the first line, default is true.
|
||||
*
|
||||
* @return Formatted string
|
||||
**/
|
||||
static std::string formatListWithLineLimit(const std::vector<std::string>& str_list, size_t row_len, size_t indent_len, bool print_first_indent = true);
|
||||
|
||||
/**
|
||||
* @brief Format raw bytes in the style of HxD editor hex view.
|
||||
*
|
||||
* @param[in] data Pointer to bytes to format.
|
||||
* @param[in] size Size of data to format.
|
||||
* @param[in] bytes_per_row Number of bytes to print on each row.
|
||||
* @param[in] byte_group_size Size of each byte group.
|
||||
*
|
||||
* @return Formatted string
|
||||
**/
|
||||
static std::string formatBytesAsHxdHexString(const byte_t* data, size_t size, size_t bytes_per_row, size_t byte_group_size);
|
||||
|
||||
/**
|
||||
* @brief Format raw bytes in the style of HxD editor hex view.
|
||||
*
|
||||
* @param[in] data Pointer to bytes to format.
|
||||
* @param[in] size Size of data to format.
|
||||
*
|
||||
* @return Formatted string
|
||||
**/
|
||||
static std::string formatBytesAsHxdHexString(const byte_t* data, size_t size);
|
||||
};
|
||||
|
||||
}} // namespace tc::cli
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* @file OptionParser.h
|
||||
* @brief Declaration of tc::cli::OptionParser
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.3
|
||||
* @date 2022/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <memory>
|
||||
#include <tc/ArgumentException.h>
|
||||
#include <tc/ArgumentNullException.h>
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
|
||||
namespace tc { namespace cli {
|
||||
|
||||
/**
|
||||
* @class OptionParser
|
||||
* @brief Class for parsing command-line options.
|
||||
*
|
||||
* This class processes command-line options according to user defined implementations of @ref tc::cli::OptionParser::IOptionHandler that are registered with this class.
|
||||
*
|
||||
* The format of command-line arguments varies by system and convention. This class supports the following styles of command-line options:
|
||||
* * @b --opt : Option name prefixed by "--" with no parameters,
|
||||
* * @b --opt=var : Option name prefixed by "--" with only one parameter delimited by "=",
|
||||
* * @b --opt @b var1 @b var2 : Option name prefixed by "--" with one or more parameters delimited by white space,
|
||||
* * @b -opt : Option name prefixed by "-" with no parameters,
|
||||
* * @b -opt=var : Option name prefixed by "-" with one parameter delimited by "=",
|
||||
* * @b -opt @b var1 @b var2 : Option name prefixed by "-" with one or more parameters delimited by white space,
|
||||
*
|
||||
* When parsing options from command-line arguments, it will (in order of occurence) collect the option name and the parameters that follow in
|
||||
* accordance to the above rules, and defer to the user defined @ref tc::cli::OptionParser::IOptionHandler for this option. If none is defined
|
||||
* it will throw a @ref tc::ArgumentException, or alternatively defer to a user defined unknown option handler (also a @ref tc::cli::OptionParser::IOptionHandler).
|
||||
*
|
||||
* For example, say we have some state struct like this:
|
||||
* @code
|
||||
* struct UserOpt
|
||||
* {
|
||||
* std::string sku_code;
|
||||
* std::map<std::string, std::string> environment_vars;
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* And the command-line is intended be formatted as follows:
|
||||
* @code
|
||||
* someprogram -sku <your SKU code here> -DVAR1=<value for variable key VAR1 here> -DVAR2=<value for variable key VAR2 here>
|
||||
* @endcode
|
||||
*
|
||||
* A possible IOptionHandler for "-sku <your SKU code here>" could be implemented as follows:
|
||||
* @code
|
||||
* class SkuOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
* {
|
||||
* public:
|
||||
* // The constructor is where you link the object to the state you want to modify in the call-back
|
||||
* SkuOptionHandler(UserOpt& user_opt) :
|
||||
* mUserOpt(user_opt),
|
||||
* mOptStrings({"-sku"}), // here we define an array of literal options to match against
|
||||
* mOptRegex()
|
||||
* {}
|
||||
*
|
||||
* // OptionParser uses this to determine which IOptionHandler to use, so this should return all aliases of the option
|
||||
* const std::vector<std::string>& getOptionStrings() const
|
||||
* {
|
||||
* return mOptStrings;
|
||||
* }
|
||||
*
|
||||
* // OptionParser uses this to determine which IOptionHandler to use, so this should return all regex patterns that will match for the option
|
||||
* const std::vector<std::string>& getOptionRegexPatterns() const
|
||||
* {
|
||||
* return mOptRegex;
|
||||
* }
|
||||
*
|
||||
* // This is what is called when OptionParser defers to IOptionHandler to process the option and any arguments
|
||||
* // In your implementation this is where you validate the data and modify your linked state data accordingly
|
||||
* void processOption(const std::string& option, const std::vector<std::string>& params)
|
||||
* {
|
||||
* // validate number of paramaters (in this case you we only want 1 parameter)
|
||||
* if (params.size() != 1)
|
||||
* {
|
||||
* throw tc::ArgumentOutOfRangeException("Option \"" + option + "\" requires a parameter.");
|
||||
* }
|
||||
*
|
||||
* mUserOpt.sku_code = params[0];
|
||||
* }
|
||||
* private:
|
||||
* UserOpt& mUserOpt;
|
||||
* std::vector<std::string> mOptStrings;
|
||||
* std::vector<std::string> mOptRegex;
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* A possible IOptionHandler for generic "-DKEY=VALUE" could be implemented as follows:
|
||||
* @code
|
||||
* class KeyValueOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
* {
|
||||
* public:
|
||||
* // The constructor is where you link the object to the state you want to modify in the call-back
|
||||
* KeyValueOptionHandler(UserOpt& user_opt) :
|
||||
* mUserOpt(user_opt),
|
||||
* mOptStrings(),
|
||||
* mOptRegex({"(-D)(.+)"}) // here we define a REGEX pattern to match the beginning of the option "-D" followed by the key.
|
||||
* {}
|
||||
*
|
||||
* // OptionParser uses this to determine which IOptionHandler to use, so this should return all aliases of the option
|
||||
* const std::vector<std::string>& getOptionStrings() const
|
||||
* {
|
||||
* return mOptStrings;
|
||||
* }
|
||||
*
|
||||
* // OptionParser uses this to determine which IOptionHandler to use, so this should return all regex patterns that will match for the option
|
||||
* const std::vector<std::string>& getOptionRegexPatterns() const
|
||||
* {
|
||||
* return mOptRegex;
|
||||
* }
|
||||
*
|
||||
* // This is what is called when OptionParser defers to IOptionHandler to process the option and any arguments
|
||||
* // In your implementation this is where you validate the data and modify your linked state data accordingly
|
||||
* void processOption(const std::string& option, const std::vector<std::string>& params)
|
||||
* {
|
||||
* // validate number of paramaters (in this case you we only want 1 parameter)
|
||||
* if (params.size() != 1)
|
||||
* {
|
||||
* throw tc::ArgumentOutOfRangeException("Option \"" + option + "\" requires a parameter.");
|
||||
* }
|
||||
*
|
||||
* mUserOpt.environment_vars.insert(std::pair<std::string>(option.substr(2), params[0]));
|
||||
* }
|
||||
* private:
|
||||
* UserOpt& mUserOpt;
|
||||
* std::vector<std::string> mOptStrings;
|
||||
* std::vector<std::string> mOptRegex;
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* Defining an unknown option handler is optional, but at a minimum allows customising the exception.
|
||||
* @code
|
||||
* class UnkOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
* {
|
||||
* public:
|
||||
* UnkOptionHandler()
|
||||
* {}
|
||||
*
|
||||
* // this throws an exception as it should not be called
|
||||
* const std::vector<std::string>& getOptionStrings() const
|
||||
* {
|
||||
* throw tc::InvalidOperationException("getOptionStrings() not defined for UnkOptionHandler.");
|
||||
* }
|
||||
*
|
||||
* // this throws an exception as it should not be called
|
||||
* const std::vector<std::string>& getOptionRegexPatterns() const
|
||||
* {
|
||||
* throw tc::InvalidOperationException("getOptionRegexPatterns() not defined for UnkOptionHandler.");
|
||||
* }
|
||||
*
|
||||
* void processOption(const std::string& option, const std::vector<std::string>& params)
|
||||
* {
|
||||
* throw tc::Exception("Unrecognized option: \"" + option + "\"");
|
||||
* }
|
||||
* private:
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* Then process the command-line arguments with OptionParser::processOptions():
|
||||
* @code
|
||||
* int umain(const std::vector<std::string>& args, const std::vector<std::string>& env)
|
||||
* {
|
||||
* UserOpt user_opt;
|
||||
* tc::cli::OptionParser opt_parser;
|
||||
*
|
||||
* // register the option handler for "-sku"
|
||||
* opt_parser.registerOptionHandler(std::shared_ptr<SkuOptionHandler>(new SkuOptionHandler(user_opt)));
|
||||
*
|
||||
* // register the option handler for "-DKEY=VALUE"
|
||||
* opt_parser.registerOptionHandler(std::shared_ptr<KeyValueOptionHandler>(new KeyValueOptionHandler(user_opt)));
|
||||
*
|
||||
* // register the unknown option handler
|
||||
* opt_parser.registerUnrecognisedOptionHandler(std::shared_ptr<UnkOptionHandler>(new UnkOptionHandler()));
|
||||
*
|
||||
* // since args will include at args[0], the program executable path, use the overload of processOptions that selects a sub vector of args.
|
||||
* opt_parser.processOptions(args, 1, args.size()-1);
|
||||
*
|
||||
* // user_opt.sku_type will now be populated if it was set via command-line with "-sku"
|
||||
* // user_opt.environment_vars will now be populated if it was set via command-line with "-DKEY=VALUE" style options.
|
||||
*
|
||||
* std::cout << "SKUCODE: \"" << user_opt.sku_code << "\"" << std::endl;
|
||||
* for (auto itr = user_opt.environment_vars.begin(); itr != environment_vars.end(); itr++)
|
||||
* {
|
||||
* std::cout << "EnvVar: [" << itr->first << "] -> [" << itr->second << "]" << std::endl;
|
||||
* }
|
||||
*
|
||||
* // finish program
|
||||
* return 0;
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class OptionParser
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @class IOptionHandler
|
||||
* @brief Interface for handling command-line options and any parameters, to be used with @ref OptionParser.
|
||||
*
|
||||
* See @ref OptionParser for an example on how to implement this class.
|
||||
*/
|
||||
class IOptionHandler
|
||||
{
|
||||
public:
|
||||
virtual ~IOptionHandler() = default;
|
||||
|
||||
/**
|
||||
* @brief Returns a vector of aliases for the option this will handle.
|
||||
*/
|
||||
virtual const std::vector<std::string>& getOptionStrings() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns a vector of option regex patterns that this will handle.
|
||||
*/
|
||||
virtual const std::vector<std::string>& getOptionRegexPatterns() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Processes command-line option and any parameters.
|
||||
*
|
||||
* @param[in] option This is full option name that was used.
|
||||
* @param[in] params This is a vector of parameters that were supplied with the option name, size may be 0 or more.
|
||||
*/
|
||||
virtual void processOption(const std::string& option, const std::vector<std::string>& params) = 0;
|
||||
};
|
||||
|
||||
/// Default Constructor
|
||||
OptionParser();
|
||||
|
||||
/**
|
||||
* @brief Register an IOptionHandler to handle an option.
|
||||
*
|
||||
* @param[in] handler Shared pointer to the IOptionHandler.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p handler was null.
|
||||
* @throw tc::ArgumentOutOfRangeException @p handler had no option strings or regex patterns.
|
||||
*/
|
||||
void registerOptionHandler(const std::shared_ptr<IOptionHandler>& handler);
|
||||
|
||||
/**
|
||||
* @brief Register an IOptionHandler to handle all unrecognised options. Only use this extra processing of unrecognised options is required beyond a generic exception.
|
||||
*
|
||||
* @param[in] handler Shared pointer to the IOptionHandler.
|
||||
*
|
||||
* @throw tc::ArgumentNullException @p handler was null.
|
||||
*/
|
||||
void registerUnrecognisedOptionHandler(const std::shared_ptr<IOptionHandler>& handler);
|
||||
|
||||
/**
|
||||
* @brief Process a vector of command-line args in accordance with the registered option handlers.
|
||||
*
|
||||
* @param[in] args Command-line args to process.
|
||||
*
|
||||
* @throw tc::ArgumentException An option was not recognised, or otherwise malformed.
|
||||
*/
|
||||
void processOptions(const std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* @brief Process a vector of command-line args in accordance with the registered option handlers.
|
||||
*
|
||||
* @param[in] args Command-line args to process.
|
||||
* @param[in] pos Position in args vector to begin with.
|
||||
* @param[in] num Number of elements in the args vector to process.
|
||||
*
|
||||
* @throw tc::ArgumentException An option was not recognised, or otherwise malformed.
|
||||
*/
|
||||
void processOptions(const std::vector<std::string>& args, size_t pos, size_t num);
|
||||
|
||||
private:
|
||||
static const std::string kClassName;
|
||||
|
||||
void handleOption(const std::string& opt, const std::vector<std::string>& params);
|
||||
std::map<std::string, std::shared_ptr<IOptionHandler>> mOptionaAliasMap;
|
||||
std::list<std::pair<std::regex, std::shared_ptr<IOptionHandler>>> mOptionRegexList;
|
||||
std::shared_ptr<IOptionHandler> mUnkOptHandler;
|
||||
};
|
||||
|
||||
}} // namespace tc::cli
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file crypto.h
|
||||
* @brief Declaration of the cryptography library
|
||||
*/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/Exception.h>
|
||||
|
||||
/**
|
||||
* @namespace tc::crypto
|
||||
* @brief Namespace of the cryptography library
|
||||
*/
|
||||
// Exceptions
|
||||
#include <tc/crypto/CryptoException.h>
|
||||
|
||||
// AES Encryption & Modes
|
||||
#include <tc/crypto/AesEncryptor.h>
|
||||
|
||||
#include <tc/crypto/EcbEncryptor.h>
|
||||
#include <tc/crypto/Aes128EcbEncryptor.h>
|
||||
#include <tc/crypto/Aes192EcbEncryptor.h>
|
||||
#include <tc/crypto/Aes256EcbEncryptor.h>
|
||||
|
||||
#include <tc/crypto/CtrEncryptor.h>
|
||||
#include <tc/crypto/Aes128CtrEncryptor.h>
|
||||
#include <tc/crypto/Aes192CtrEncryptor.h>
|
||||
#include <tc/crypto/Aes256CtrEncryptor.h>
|
||||
|
||||
#include <tc/crypto/CbcEncryptor.h>
|
||||
#include <tc/crypto/Aes128CbcEncryptor.h>
|
||||
#include <tc/crypto/Aes192CbcEncryptor.h>
|
||||
#include <tc/crypto/Aes256CbcEncryptor.h>
|
||||
|
||||
#include <tc/crypto/XtsEncryptor.h>
|
||||
#include <tc/crypto/Aes128XtsEncryptor.h>
|
||||
#include <tc/crypto/Aes256XtsEncryptor.h>
|
||||
|
||||
// AES Encryption Streams
|
||||
#include <tc/crypto/Aes128CtrEncryptedStream.h>
|
||||
#include <tc/crypto/Aes128CbcEncryptedStream.h>
|
||||
|
||||
|
||||
// Hash Calculator
|
||||
#include <tc/crypto/Md5Generator.h>
|
||||
#include <tc/crypto/Sha1Generator.h>
|
||||
#include <tc/crypto/Sha256Generator.h>
|
||||
#include <tc/crypto/Sha512Generator.h>
|
||||
|
||||
// HMAC Calculator
|
||||
#include <tc/crypto/HmacGenerator.h>
|
||||
#include <tc/crypto/HmacMd5Generator.h>
|
||||
#include <tc/crypto/HmacSha1Generator.h>
|
||||
#include <tc/crypto/HmacSha256Generator.h>
|
||||
#include <tc/crypto/HmacSha512Generator.h>
|
||||
|
||||
// Password-based Key Derivation Function
|
||||
#include <tc/crypto/Pbkdf1KeyDeriver.h>
|
||||
#include <tc/crypto/Pbkdf1Md5KeyDeriver.h>
|
||||
#include <tc/crypto/Pbkdf1Sha1KeyDeriver.h>
|
||||
|
||||
#include <tc/crypto/Pbkdf2KeyDeriver.h>
|
||||
#include <tc/crypto/Pbkdf2Sha1KeyDeriver.h>
|
||||
#include <tc/crypto/Pbkdf2Sha256KeyDeriver.h>
|
||||
#include <tc/crypto/Pbkdf2Sha512KeyDeriver.h>
|
||||
|
||||
// Psuedo-random Byte Generation
|
||||
#include <tc/crypto/PseudoRandomByteGenerator.h>
|
||||
|
||||
// RSA Signing & Encryption
|
||||
#include <tc/crypto/RsaKey.h>
|
||||
#include <tc/crypto/RsaKeyGenerator.h>
|
||||
|
||||
#include <tc/crypto/RsaPkcs1Signer.h>
|
||||
#include <tc/crypto/RsaPkcs1Md5Signer.h>
|
||||
#include <tc/crypto/RsaPkcs1Sha1Signer.h>
|
||||
#include <tc/crypto/RsaPkcs1Sha256Signer.h>
|
||||
#include <tc/crypto/RsaPkcs1Sha512Signer.h>
|
||||
|
||||
#include <tc/crypto/RsaPssSigner.h>
|
||||
#include <tc/crypto/RsaPssSha256Signer.h>
|
||||
#include <tc/crypto/RsaPssSha512Signer.h>
|
||||
|
||||
#include <tc/crypto/RsaOaepEncryptor.h>
|
||||
#include <tc/crypto/RsaOaepSha256Encryptor.h>
|
||||
#include <tc/crypto/RsaOaepSha512Encryptor.h>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file io.h
|
||||
* @brief Declaration of the input/output library
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/types.h>
|
||||
#include <tc/Exception.h>
|
||||
|
||||
/**
|
||||
* @namespace tc::io
|
||||
* @brief Namespace of the input/output library
|
||||
**/
|
||||
#include <tc/io/Path.h>
|
||||
#include <tc/io/PathUtil.h>
|
||||
|
||||
#include <tc/io/IPathResolver.h>
|
||||
#include <tc/io/IPortablePathResolver.h>
|
||||
#include <tc/io/BasicPathResolver.h>
|
||||
|
||||
#include <tc/io/IStream.h>
|
||||
#include <tc/io/FileStream.h>
|
||||
#include <tc/io/SubStream.h>
|
||||
#include <tc/io/MemoryStream.h>
|
||||
#include <tc/io/ConcatenatedStream.h>
|
||||
|
||||
#include <tc/io/IFileSystem.h>
|
||||
#include <tc/io/LocalFileSystem.h>
|
||||
#include <tc/io/SubFileSystem.h>
|
||||
#include <tc/io/VirtualFileSystem.h>
|
||||
|
||||
#include <tc/io/ISink.h>
|
||||
#include <tc/io/SubSink.h>
|
||||
#include <tc/io/StreamSink.h>
|
||||
|
||||
#include <tc/io/ISource.h>
|
||||
#include <tc/io/PaddingSource.h>
|
||||
#include <tc/io/SubSource.h>
|
||||
#include <tc/io/StreamSource.h>
|
||||
#include <tc/io/MemorySource.h>
|
||||
#include <tc/io/OverlayedSource.h>
|
||||
|
||||
// Exceptions
|
||||
#include <tc/io/IOException.h>
|
||||
#include <tc/io/DirectoryNotEmptyException.h>
|
||||
#include <tc/io/DirectoryNotFoundException.h>
|
||||
#include <tc/io/FileExistsException.h>
|
||||
#include <tc/io/FileNotFoundException.h>
|
||||
#include <tc/io/PathTooLongException.h>
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @file BasicPathResolver.h
|
||||
* @brief Declaration of tc::io::BasicPathResolver
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.3
|
||||
* @date 2022/02/25
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/io/IPortablePathResolver.h>
|
||||
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
|
||||
namespace tc { namespace io {
|
||||
|
||||
/**
|
||||
* @class BasicPathResolver
|
||||
* @brief This implementation of IPortablePathResolver resolves a path and current directory to canonical path, resolving only '`.`', '`..`' and empty path elements.
|
||||
* @details
|
||||
* This does not consider the local file-system/environment, so links or '`~`' will not be resolved properly. It is intended for processing archived/portable filesystems.
|
||||
*
|
||||
* This supports custom root labels. A root label being the first element of absolute/canonical paths.
|
||||
* * For POSIX this is an empty string, e.g. the empty string prior to / in "/some/path/to/a/file"
|
||||
* * For Windows systems this is the drive letter, e.g. "C:" in "C:\some\path\to\a\file"
|
||||
*
|
||||
* BasicPathResolver maintains a list of root labels to determine if a path being resolved is absolute or relative, including:
|
||||
* * Implicit Root Label : This is the first element in the current working directory, will change if the current working directory changes.
|
||||
* * Explicit Root Labels : This is a list of root labels supplied separately via @ref setExplicitRootLabels().
|
||||
*/
|
||||
class BasicPathResolver : public tc::io::IPortablePathResolver
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default Constructor
|
||||
*
|
||||
* @post The current directory will be "/" and the list of explicit root labels will be {}.
|
||||
*/
|
||||
BasicPathResolver();
|
||||
|
||||
/**
|
||||
* @brief Create BasicPathResolver
|
||||
*
|
||||
* @param[in] current_directory_path Canonical path for the current directory.
|
||||
*
|
||||
* @post The current directory will be @p current_directory_path and the list of explicit root labels will be {}.
|
||||
*/
|
||||
BasicPathResolver(const tc::io::Path& current_directory_path);
|
||||
|
||||
/**
|
||||
* @brief Create BasicPathResolver
|
||||
*
|
||||
* @param[in] current_directory_path Canonical path for the current directory.
|
||||
* @param[in] root_labels Vector of valid root path names for this path resolver.
|
||||
*
|
||||
* @post The current directory will be @p current_directory_path and the list of explicit root labels will be @p root_labels .
|
||||
*/
|
||||
BasicPathResolver(const tc::io::Path& current_directory_path, const std::vector<std::string>& root_labels);
|
||||
|
||||
/**
|
||||
* @brief Set the current directory path
|
||||
*
|
||||
* @param path Canonical current directory path.
|
||||
*
|
||||
* @throws tc::ArgumentOutOfRangeException @p path was an empty path.
|
||||
*/
|
||||
void setCurrentDirectory(const tc::io::Path& path);
|
||||
|
||||
/**
|
||||
* @brief Get the current directory path
|
||||
*
|
||||
* @return tc::io::Path Canonical current directory path.
|
||||
*/
|
||||
const tc::io::Path& getCurrentDirectory() const;
|
||||
|
||||
/**
|
||||
* @brief Set explicit root labels
|
||||
* @details
|
||||
* This is only required where multiple root labels need to be registered.
|
||||
*
|
||||
* @param root_labels Vector of root labels
|
||||
*/
|
||||
void setExplicitRootLabels(const std::vector<std::string>& root_labels);
|
||||
|
||||
/// Get explicit root labels
|
||||
const std::vector<std::string>& getExplicitRootLabels() const;
|
||||
|
||||
/**
|
||||
* @brief Resolve path to its canonical path
|
||||
*
|
||||
* @param path Input path.
|
||||
* @param canonical_path Output path to write resolved canonical path.
|
||||
*/
|
||||
void resolveCanonicalPath(const tc::io::Path& path, tc::io::Path& canonical_path) const;
|
||||
|
||||
/**
|
||||
* @brief Resolve path to its canonical path
|
||||
*
|
||||
* @param path Input path.
|
||||
*
|
||||
* @return Resolved canonical path.
|
||||
*/
|
||||
tc::io::Path resolveCanonicalPath(const tc::io::Path& path) const;
|
||||
private:
|
||||
static const std::string kClassName;
|
||||
|
||||
tc::io::Path mCurrentDirPath;
|
||||
std::vector<std::string> mExplicitRootLabels;
|
||||
};
|
||||
|
||||
}} // namespace tc::io
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @file ConcatenatedStream.h
|
||||
* @brief Declaration of tc::io::ConcatenatedStream
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2022/02/28
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/io/IStream.h>
|
||||
#include <tc/Optional.h>
|
||||
|
||||
#include <tc/ArgumentOutOfRangeException.h>
|
||||
#include <tc/NotSupportedException.h>
|
||||
#include <tc/NotImplementedException.h>
|
||||
#include <tc/ObjectDisposedException.h>
|
||||
#include <tc/io/IOException.h>
|
||||
|
||||
namespace tc { namespace io {
|
||||
|
||||
/**
|
||||
* @class ConcatenatedStream
|
||||
* @brief A stream that concatenates multiple streams into a single stream.
|
||||
**/
|
||||
class ConcatenatedStream : public tc::io::IStream
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default Constructor
|
||||
* @post This will create an unusable ConcatenatedStream, it will have to be assigned from a valid ConcatenatedStream object to be usable.
|
||||
**/
|
||||
ConcatenatedStream();
|
||||
|
||||
/**
|
||||
* @brief Move constructor
|
||||
**/
|
||||
ConcatenatedStream(ConcatenatedStream&& other);
|
||||
|
||||
/**
|
||||
* @brief Create ConcatenatedStream
|
||||
*
|
||||
* @param[in] stream_list The list IStream objects to concatenate in this stream.
|
||||
*
|
||||
* @pre All base streams must support seeking for @ref seek() to work
|
||||
* @pre All base streams must support reading for @ref read() to work.
|
||||
* @pre All base streams must support writing for @ref write() to work.
|
||||
*
|
||||
* @throw tc::NotSupportedException List of streams did not all support either read or write.
|
||||
* @throw tc::NotSupportedException List of streams combined to a stream with no length.
|
||||
**/
|
||||
ConcatenatedStream(const std::vector<std::shared_ptr<tc::io::IStream>>& stream_list);
|
||||
|
||||
/// Destructor
|
||||
~ConcatenatedStream();
|
||||
|
||||
/**
|
||||
* @brief Move assignment
|
||||
**/
|
||||
ConcatenatedStream& operator=(ConcatenatedStream&& other);
|
||||
|
||||
/**
|
||||
* @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::io::IOException Failed to read data from an underlying stream.
|
||||
* @throw tc::NotSupportedException Stream does not support reading.
|
||||
* @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.
|
||||
*
|
||||
* @param[in] ptr Pointer to an array of bytes. This method copies @p count bytes from @p ptr to the current stream.
|
||||
* @param[in] count The number of bytes to be written to the current stream.
|
||||
*
|
||||
* @return The total number of bytes written to the stream. 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 writing for @ref write to work.
|
||||
* @note Use @ref canWrite to determine if this stream supports writing.
|
||||
* @note Exceptions thrown by the base stream are not altered/intercepted, refer to that module's documentation for those exceptions.
|
||||
*
|
||||
* @throw tc::io::IOException Failed to write data to an underlying stream.
|
||||
* @throw tc::NotSupportedException Stream does not support writing.
|
||||
* @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::io::IOException Failed to seek because underlying stream could not be determined.
|
||||
* @throw tc::ArgumentOutOfRangeException @p origin contains an invalid value.
|
||||
* @throw tc::NotSupportedException Stream does not support seeking.
|
||||
* @throw tc::ObjectDisposedException Methods were called after the stream was closed.
|
||||
**/
|
||||
int64_t seek(int64_t offset, SeekOrigin origin);
|
||||
|
||||
/**
|
||||
* @brief Sets the length of the current stream. This is not implemented for @ref ConcatenatedStream.
|
||||
* @throw tc::NotImplementedException @ref setLength is not implemented for @ref ConcatenatedStream
|
||||
* @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;
|
||||
|
||||
// delete copy constructor
|
||||
ConcatenatedStream(const ConcatenatedStream&);
|
||||
|
||||
// delete copy assignment
|
||||
ConcatenatedStream& operator=(const ConcatenatedStream&);
|
||||
|
||||
struct StreamRange
|
||||
{
|
||||
int64_t offset;
|
||||
int64_t length;
|
||||
|
||||
StreamRange() : offset(0), length(0) {}
|
||||
StreamRange(int64_t offset) : offset(offset), length(0) {}
|
||||
StreamRange(int64_t offset, int64_t length) : offset(offset), length(length) {}
|
||||
|
||||
bool operator<(const StreamRange& other) const
|
||||
{
|
||||
return (this->offset < other.offset && (this->offset + this->length) <= other.offset);
|
||||
}
|
||||
};
|
||||
|
||||
struct StreamInfo
|
||||
{
|
||||
StreamRange range;
|
||||
std::shared_ptr<tc::io::IStream> stream;
|
||||
};
|
||||
|
||||
std::vector<StreamInfo> mStreamList;
|
||||
std::map<StreamRange, size_t> mStreamListMap;
|
||||
tc::Optional<std::vector<StreamInfo>::iterator> mCurrentStream;
|
||||
|
||||
inline bool isStreamDisposed() const { return mStreamList.empty() || mCurrentStream.isNull() || mCurrentStream.get() == mStreamList.end(); }
|
||||
void updateCurrentStream(std::vector<StreamInfo>::iterator stream_itr);
|
||||
|
||||
// static stream properties
|
||||
bool mCanRead;
|
||||
bool mCanWrite;
|
||||
bool mCanSeek;
|
||||
int64_t mStreamLength;
|
||||
};
|
||||
|
||||
}} // namespace tc::io
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file DirectoryNotEmptyException.h
|
||||
* @brief Declaration of tc::io::DirectoryNotEmptyException
|
||||
* @author Jack (jakcron)
|
||||
* @version 0.1
|
||||
* @date 2020/01/22
|
||||
**/
|
||||
#pragma once
|
||||
#include <tc/io/IOException.h>
|
||||
|
||||
namespace tc { namespace io {
|
||||
|
||||
/**
|
||||
* @class DirectoryNotEmptyException
|
||||
* @brief The exception that is thrown when a directory is not empty.
|
||||
**/
|
||||
class DirectoryNotEmptyException : public tc::io::IOException
|
||||
{
|
||||
public:
|
||||
/// Default Constructor
|
||||
DirectoryNotEmptyException() noexcept :
|
||||
tc::io::IOException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Basic Parameterized Constructor
|
||||
*
|
||||
* @param[in] what Explanation for exception
|
||||
*
|
||||
* @post
|
||||
* - what() == what
|
||||
* - module() == ""
|
||||
* - error() == what
|
||||
**/
|
||||
DirectoryNotEmptyException(const std::string& what) noexcept :
|
||||
tc::io::IOException(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
|
||||
**/
|
||||
DirectoryNotEmptyException(const std::string& module, const std::string& what) noexcept :
|
||||
tc::io::IOException(module, what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace tc::io
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user