-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCore.hh
More file actions
285 lines (268 loc) · 14.9 KB
/
Core.hh
File metadata and controls
285 lines (268 loc) · 14.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/* *
* 4crypt - Memory-Hard Symmetric File Encryption Program
* Copyright (C) 2025 Stuart Calder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FOURCRYPT_CORE_HH
#define FOURCRYPT_CORE_HH
// C++ STL
#include <string>
// SSC
#include <SSC/Typedef.h>
#include <SSC/Memory.h>
#include <SSC/MemMap.h>
// TSC
#include <TSC/CSPRNG.h>
#include <TSC/Catena512.h>
#include <TSC/Threefish512.h>
#if !defined(SSC_LANG_CPP)
#error "We need C++!"
#elif SSC_LANG_CPP < SSC_CPP_20
#error "We need at least C++20!"
#endif
#define R_ SSC_RESTRICT
namespace fourcrypt
{
class Core
{
public:
//// Public constants and types.
static constexpr size_t MAX_PW_BYTES {125};
static constexpr size_t PW_BUFFER_BYTES {MAX_PW_BYTES + 1};
static_assert(SSC_ENDIAN == SSC_ENDIAN_LITTLE || SSC_ENDIAN == SSC_ENDIAN_BIG, "Only big and little endian supported!");
static constexpr bool is_little_endian = []() -> bool { return (SSC_ENDIAN == SSC_ENDIAN_LITTLE); }();
static constexpr uint8_t magic[4] { 0xe2, 0x2a, 0x1e, 0x9b };
static constexpr char extension[4] { '.', '4', 'c', '\0' };
static constexpr size_t extension_length {3}; // Only consider '.', '4', and 'c'.
static constexpr SSC_BitFlag8_t ENABLE_PHI {0b00000001}; // Enable the Phi function.
static constexpr SSC_BitFlag8_t SUPPLEMENT_ENTROPY {0b00000010}; // Supplement entropy from stdin.
static constexpr SSC_BitFlag8_t ENTER_PASS_ONCE {0b00000100}; // Don't re-enter password during encrypt.
static constexpr uint8_t MEM_FAST {21}; // 128 Mebibytes.
static constexpr uint8_t MEM_NORMAL {24}; // 1 Gibibyte.
static constexpr uint8_t MEM_STRONG {25}; // 2 Gibibytes.
static constexpr uint8_t MEM_DEFAULT {MEM_NORMAL};
static constexpr uint64_t memoryFromBitShift(uint8_t bitshift)
{
return static_cast<uint64_t>(1) << (bitshift + 6);
}
static constexpr uint64_t PAD_FACTOR {64}; // Files will always be a multiple of 64 bytes.
static constexpr uint64_t MAC_SIZE {64}; // The Message Authentication Code is 64 bytes.
// What does the user want the software to do?
enum class ExeMode
{
NONE, ENCRYPT, DECRYPT, DESCRIBE
};
// How does the user want the padding they requested to be done?
enum class PadMode
{
ADD, TARGET, AS_IF
};
// Distinguish input from output files.
enum class InOutDir
{
NONE = 0,
INPUT = 1,
OUTPUT = 2
};
// Distinguish errors that happen inside Core logic from errors that happen inside SSC_MemMap procedure calls.
enum class ErrType
{
CORE, MEMMAP
};
//// 4crypt Code Errors.
static constexpr SSC_CodeError_t ERROR_NONE { 0};
static constexpr SSC_CodeError_t ERROR_NO_INPUT_FILENAME { -1};
static constexpr SSC_CodeError_t ERROR_NO_OUTPUT_FILENAME { -2};
static constexpr SSC_CodeError_t ERROR_INPUT_MEMMAP_FAILED { -3};
static constexpr SSC_CodeError_t ERROR_OUTPUT_MEMMAP_FAILED { -4};
static constexpr SSC_CodeError_t ERROR_GETTING_INPUT_FILESIZE { -5};
static constexpr SSC_CodeError_t ERROR_INPUT_FILESIZE_TOO_SMALL { -6};
static constexpr SSC_CodeError_t ERROR_INVALID_4CRYPT_FILE { -7};
static constexpr SSC_CodeError_t ERROR_INPUT_SIZE_MISMATCH { -8};
static constexpr SSC_CodeError_t ERROR_RESERVED_BYTES_USED { -9};
static constexpr SSC_CodeError_t ERROR_OUTPUT_FILE_EXISTS {-10};
static constexpr SSC_CodeError_t ERROR_MAC_VALIDATION_FAILED {-11};
static constexpr SSC_CodeError_t ERROR_KDF_FAILED {-12};
static constexpr SSC_CodeError_t ERROR_METADATA_VALIDATION_FAILED {-13};
struct PlainOldData
{
TSC_Threefish512Ctr tf_ctr; // Threefish512 Cipher in Counter Mode.
TSC_CSPRNG rng; // Skein512-based Cryptographically Secure Pseudorandom Number Generator.
alignas(uint64_t) uint8_t hash_buffer [TSC_THREEFISH512_BLOCK_BYTES * 2]; // Enough room for two distinct 64 byte hashes in 1 buffer.
uint64_t tf_sec_key [TSC_THREEFISH512_KEY_WORDS_WITH_PARITY]; // Secret encryption key.
uint64_t tf_tweak [TSC_THREEFISH512_TWEAK_WORDS_WITH_PARITY]; // Public Threefish512 Tweak.
uint64_t mac_key [TSC_THREEFISH512_BLOCK_WORDS]; // Secret authentication key.
alignas(uint64_t) uint8_t catena_salt [TSC_CATENA512_SALT_BYTES]; // Public Catena512 salt.
uint64_t tf_ctr_iv [TSC_THREEFISH512CTR_IV_WORDS]; // Public Initialization Vector for Threefish512 in Counter Mode.
uint8_t password_buffer [PW_BUFFER_BYTES]; // Store the password here when encrypting/decrypting.
uint8_t verify_buffer [PW_BUFFER_BYTES]; // Verify @password_buffer here when encrypting.
uint8_t entropy_buffer [PW_BUFFER_BYTES]; // Store entropy characters here before hashing them into the @rng.
SSC_MemMap input_map; // Memory-map the input file.
SSC_MemMap output_map; // Memory-map the output file.
char* input_filename; // Where is the input file?
char* output_filename; // Where is the output file?
TSC_Skein512* skein512; // Point to the TSC_Skein512 internal to @rng.
uint64_t tf_ctr_idx; // The current keystream byte index for Threefish512 in Counter Mode.
uint64_t input_filename_size; // How many bytes is the input file name?
uint64_t output_filename_size; // How many bytes is the output file name?
uint64_t password_size; // How many bytes is the password?
uint64_t entropy_size; // How many entropy bytes were provided?
uint64_t padding_size; // How many bytes of padding?
uint64_t thread_count; // How many KDF threads?
uint64_t thread_batch_size; // How many KDF threads per batch? i.e. How many threads execute concurrently?
ExeMode execute_mode; // What shall we do? Encrypt? Decrypt? Describe?
PadMode padding_mode; // What context were the padding bytes specified for?
uint8_t memory_low; // What is the lower memory bound of the KDF?
uint8_t memory_high; // What is the upper memory bound of the KDF?
uint8_t iterations; // How many times will each thread of the KDF iterate?
SSC_BitFlag8_t flags; // Bit Flag parameters, such as whether to enable entropy supplementation.
static void init(PlainOldData& pod); // Initialize the values of a PlainOldData object.
static void del(PlainOldData& pod); // Destroy a PlainOldData object.
static void touchup(PlainOldData& pod); // Ensure the values inside a PlainOldData object are valid & consistent.
static void set_fast(PlainOldData& pod);
static void set_normal(PlainOldData& pod);
static void set_strong(PlainOldData& pod); //TODO
};
using StatusCallback_f = void(void* data);
//// Public methods.
/* Return a raw pointer to a PlainOldData object. */
PlainOldData* getPod();
/* Initiate counter mode encryption and subsequent MAC authentication.
* If an error occurs, return the SSC_CodeError_t and specify the
* ErrType as well as the InOutDir (whether the error occured specifically
* with input or output).
*
* When @status_callback is non-nullptr it gets called at several arbitrary intervals to allow
* external code to roughly track the status of execution.
*/
SSC_CodeError_t encrypt(ErrType* err_type, InOutDir* err_dir , StatusCallback_f* status_callback= nullptr, void* scb_data = nullptr);
/* Initiate MAC authentication and subsequent Counter Mode decryption.
* If an error occurs, return the SSC_CodeError_t and specify the
* ErrType as well as the InOutDir (whether the error occured specifically
* with input or output).
*
* @status_callback gets called at several arbitrary intervals to allow
* external code to roughly track the status of execution.
*/
SSC_CodeError_t decrypt(ErrType* err_type, InOutDir* err_dir , StatusCallback_f* status_callback = nullptr, void* scb_data = nullptr);
/* Describe the metadata of a 4crypt-encrypted file.
* If an error occurs, return the SSC_CodeError_t and specify the
* ErrType as well as the InOutDir (whether the error occured specifically
* with input or output).
*
* When @status_callback is non-nullptr it gets called at several arbitrary intervals to allow
* external code to roughly track the status of execution.
*/
SSC_CodeError_t describe(ErrType* err_type, InOutDir* err_dir, StatusCallback_f* status_callback = nullptr, void* scb_data = nullptr);
/* This function returns the size of a 4crypt-encrypted file header. */
static consteval uint64_t getHeaderSize();
/* 4crypt metadata consists of the header at the beginning of a file as well as the Message Authentication Code at the end. */
static consteval uint64_t getMetadataSize();
/* The minimum size of a 4crypt-encrypted file consists of the 4crypt metadata with a single block of PAD_FACTOR (64) bytes. */
static consteval uint64_t getMinimumOutputSize();
//// Constructors / Destructors
Core();
~Core();
private:
//// Data
PlainOldData* pod;
//// Static Data
static std::string password_prompt;
static std::string reentry_prompt;
static std::string entropy_prompt;
//// Static procedures.
/* Perform basic validity checks of the metadata of the (input or output)
* file. Return true when the metadata is valid and false otherwise.
*/
static bool verifyBasicMetadata(PlainOldData* extpod, InOutDir dir);
/* Return a std::string representation of the bitshift interpreted as a number of bytes. */
static std::string makeMemoryStringBitShift(const uint8_t mem_bitshift);
/* Return a std::string representation of the uint64_t interpreted as a number of bytes. */
static std::string makeMemoryString(const uint64_t value);
/* For systems that define SSC_HAS_GETAVAILABLESYSTEMMEMORY...
* Return a left bitwise shift that will not exceed the amount of currently available system memory.
* For other systems...
* Return a left bitwise shift that will result in a "moderate" amount of memory usage.
*/
static uint8_t getDefaultMemoryUsageBitShift(void);
//// Private methods.
/* Prompt the user for a password to be entered at a command-line terminal.
* If @enter_twice is true the user will be prompted a second time to confirm that
* they entered the password correctly.
* If @entropy is true the password will be written to a unique entropy password buffer, that
* will later get hashed into the Cryptographically Secure PseudoRandom Number Generator.
*/
void getPassword(bool enter_twice, bool entropy);
/* Given an input file's @input_filesize, as well as the number
* of padding bytes requested by the user (if any) determine how many padding
* bytes to actually add such that the resultant file will be divisible
* into even blocks of PAD_FACTOR bytes.
*/
SSC_Error_t normalizePadding(const uint64_t input_filesize);
/* Generate all the pseudorandom data required for the
* PlainOldData object pointed to inside of Core.
*/
void genRandomElements();
/* Run the key derivation function utilizing as many threads
* as were specified by the user. This necessitates a lot of dynamic
* allocation.
*/
SSC_Error_t runKDF();
/* Verify that the @size bytes starting at @begin produce the same Message Authentication
* Code as that stored at @mac.
*/
SSC_Error_t verifyMAC(const uint8_t* R_ mac, const uint8_t* R_ begin, const uint64_t size);
/* Memory-map the Input and/or Output files.
* If there's an error return the code and write the direction (input or output) to @map_err_idx.
*/
SSC_CodeError_t mapFiles(InOutDir* map_err_idx, size_t input_size = 0, size_t output_size = 0, InOutDir only_map = InOutDir::NONE);
/* Check the input and output memory maps.
* For each: if the pointer is valid synchronize the memory map.
* Fail if either operation fails.
*/
SSC_Error_t syncMaps();
/* De-initialize the input and output memory maps
* (if those pointers are non-nullptr).
*/
void unmapFiles();
/* Write a 4crypt header to the bytes starting at @to.
* Return a pointer to the byte immediately following the written header.
*/
uint8_t* writeHeader(uint8_t* to);
/* Read the plaintext portion of a 4crypt-encrypted file header's bytes @from, and store any resultant errors
* at @err. On success return a pointer just past the header's plaintext. On failure return an invalid pointer.
*/
const uint8_t* readHeaderPlaintext(const uint8_t* R_ from, SSC_CodeError_t* R_ err);
/* Read the ciphertext portion of a 4crypt-encrypted file header's bytes @from, and store any resultant errors
* at @err. On success return a pointer just past the header's ciphertext. On failure return an invalid pointer.
*/
const uint8_t* readHeaderCiphertext(const uint8_t* R_ from, SSC_CodeError_t* R_ err);
/* Encrypt the @num bytes of plaintext at @from and store the
* ciphertext at @to. Return the address immediately following the last byte
* of ciphertext written at @to.
*/
uint8_t* writeCiphertext(uint8_t* R_ to, const uint8_t* R_ from, const size_t num);
/* Decrypt the @num bytes of ciphertext at @from and store the
* plaintext at @to. Return the address immediately following the last byte
* of plaintext written at @to.
*/
void writePlaintext(uint8_t* R_ to, const uint8_t* R_ from, const size_t num);
/* Calculate the Skein512-MAC of the @num bytes beginning at @from, and store
* the resulting MAC at @to.
*/
void writeMAC(uint8_t* R_ to, const uint8_t* R_ from, const size_t num);
};
} // ! namespace fourcrypt
#undef R_
#endif