-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcipher.c
More file actions
626 lines (520 loc) · 19.8 KB
/
cipher.c
File metadata and controls
626 lines (520 loc) · 19.8 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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
#define _POSIX_C_SOURCE 199309L
#include <sodium.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#define NONCE_SIZE crypto_aead_chacha20poly1305_IETF_NPUBBYTES
#define KEY_SIZE crypto_aead_chacha20poly1305_IETF_KEYBYTES
#define MAC_SIZE crypto_aead_chacha20poly1305_IETF_ABYTES
#define SALT_SIZE crypto_pwhash_SALTBYTES
#define HEADER_SIZE (1 + SALT_SIZE + NONCE_SIZE + 8)
#define MAX_MSG_SIZE 65536
#define MAX_HEX_SIZE (MAX_MSG_SIZE + HEADER_SIZE + MAC_SIZE) * 2
#define MIN_PASSWORD_LENGTH 12
#define MAX_PASSWORD_LENGTH 1024
#define VERSION_BYTE 0x04
#define TIMESTAMP_TOLERANCE_FUTURE 300
#define TIMESTAMP_TOLERANCE_PAST (7 * 24 * 3600)
#define OPSLIMIT crypto_pwhash_OPSLIMIT_INTERACTIVE
#define MEMLIMIT crypto_pwhash_MEMLIMIT_INTERACTIVE
typedef enum {
CRYPTO_SUCCESS = 0,
CRYPTO_ERROR_INIT = -1,
CRYPTO_ERROR_WEAK_PASSWORD = -2,
CRYPTO_ERROR_KEY_DERIVATION = -3,
CRYPTO_ERROR_MESSAGE_TOO_LARGE = -4,
CRYPTO_ERROR_MEMORY_ALLOCATION = -5,
CRYPTO_ERROR_ENCRYPTION_FAILED = -6,
CRYPTO_ERROR_INVALID_INPUT = -7,
CRYPTO_ERROR_INVALID_VERSION = -8,
CRYPTO_ERROR_TIMESTAMP_INVALID = -9,
CRYPTO_ERROR_DECRYPTION_FAILED = -10,
CRYPTO_ERROR_INVALID_HEX = -11,
CRYPTO_ERROR_BUFFER_TOO_SMALL = -12
} crypto_error_t;
typedef struct {
unsigned char *data;
size_t size;
size_t capacity;
} secure_buffer_t;
static void secure_log(const char *level, const char *msg);
static void secure_wipe(void *data, size_t len);
static crypto_error_t secure_buffer_init(secure_buffer_t *buf, size_t capacity);
static void secure_buffer_free(secure_buffer_t *buf);
static crypto_error_t validate_password_strength(const char *password);
static crypto_error_t safe_hex_encode(const unsigned char *in, size_t in_len, char *out, size_t out_capacity);
static crypto_error_t safe_hex_decode(const char *hex, unsigned char *out, size_t out_capacity, size_t *decoded_len);
static crypto_error_t derive_key_secure(const char *password, const unsigned char *salt, unsigned char *key_out);
static crypto_error_t validate_timestamp(uint64_t timestamp);
static int is_valid_hex_string(const char *hex);
static const char* get_error_message(crypto_error_t error);
static void secure_log(const char *level, const char *msg) {
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char timestamp[32];
if (tm_info && strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info) > 0) {
fprintf(stderr, "[%s] %s: %s\n", timestamp, level, msg);
} else {
fprintf(stderr, "%s: %s\n", level, msg);
}
fflush(stderr);
}
static void secure_wipe(void *data, size_t len) {
if (data && len > 0) {
sodium_memzero(data, len);
}
}
static crypto_error_t secure_buffer_init(secure_buffer_t *buf, size_t capacity) {
if (!buf || capacity == 0) {
return CRYPTO_ERROR_INVALID_INPUT;
}
buf->data = sodium_malloc(capacity);
if (!buf->data) {
secure_log("ERROR", "Failed to allocate secure memory");
return CRYPTO_ERROR_MEMORY_ALLOCATION;
}
buf->size = 0;
buf->capacity = capacity;
return CRYPTO_SUCCESS;
}
static void secure_buffer_free(secure_buffer_t *buf) {
if (buf && buf->data) {
sodium_free(buf->data);
buf->data = NULL;
buf->size = 0;
buf->capacity = 0;
}
}
static crypto_error_t validate_password_strength(const char *password) {
if (!password) {
return CRYPTO_ERROR_INVALID_INPUT;
}
size_t len = strlen(password);
if (len < MIN_PASSWORD_LENGTH) {
secure_log("WARNING", "Password too short");
return CRYPTO_ERROR_WEAK_PASSWORD;
}
if (len > MAX_PASSWORD_LENGTH) {
secure_log("ERROR", "Password too long");
return CRYPTO_ERROR_INVALID_INPUT;
}
int has_upper = 0, has_lower = 0, has_digit = 0, has_special = 0;
int char_classes = 0;
for (size_t i = 0; i < len; i++) {
unsigned char c = (unsigned char)password[i];
if (c < 32 || c == 127) {
secure_log("ERROR", "Password contains invalid characters");
return CRYPTO_ERROR_INVALID_INPUT;
}
if (c >= 'A' && c <= 'Z') has_upper = 1;
else if (c >= 'a' && c <= 'z') has_lower = 1;
else if (c >= '0' && c <= '9') has_digit = 1;
else has_special = 1;
}
char_classes = has_upper + has_lower + has_digit + has_special;
if (len < 16 && char_classes < 3) {
secure_log("WARNING", "Password lacks complexity");
return CRYPTO_ERROR_WEAK_PASSWORD;
}
double charset_size = 0;
if (has_lower) charset_size += 26;
if (has_upper) charset_size += 26;
if (has_digit) charset_size += 10;
if (has_special) charset_size += 32;
double entropy = log2(charset_size) * len;
if (entropy < 60.0) {
secure_log("WARNING", "Password entropy may be insufficient");
return CRYPTO_ERROR_WEAK_PASSWORD;
}
return CRYPTO_SUCCESS;
}
static crypto_error_t safe_hex_encode(const unsigned char *in, size_t in_len, char *out, size_t out_capacity) {
if (!in || !out || in_len == 0) {
return CRYPTO_ERROR_INVALID_INPUT;
}
if (out_capacity < (in_len * 2 + 1)) {
return CRYPTO_ERROR_BUFFER_TOO_SMALL;
}
for (size_t i = 0; i < in_len; i++) {
int written = snprintf(out + i * 2, 3, "%02x", in[i]);
if (written != 2) {
return CRYPTO_ERROR_INVALID_INPUT;
}
}
out[in_len * 2] = '\0';
return CRYPTO_SUCCESS;
}
static int is_valid_hex_string(const char *hex) {
if (!hex) return 0;
size_t len = strlen(hex);
if (len == 0 || len % 2 != 0) return 0;
for (size_t i = 0; i < len; i++) {
if (!isxdigit((unsigned char)hex[i])) {
return 0;
}
}
return 1;
}
static crypto_error_t safe_hex_decode(const char *hex, unsigned char *out, size_t out_capacity, size_t *decoded_len) {
if (!hex || !out || !decoded_len) {
return CRYPTO_ERROR_INVALID_INPUT;
}
if (!is_valid_hex_string(hex)) {
return CRYPTO_ERROR_INVALID_HEX;
}
size_t hex_len = strlen(hex);
size_t expected_len = hex_len / 2;
if (expected_len > out_capacity) {
return CRYPTO_ERROR_BUFFER_TOO_SMALL;
}
for (size_t i = 0; i < expected_len; i++) {
unsigned int byte_val;
if (sscanf(hex + 2 * i, "%2x", &byte_val) != 1) {
return CRYPTO_ERROR_INVALID_HEX;
}
out[i] = (unsigned char)byte_val;
}
*decoded_len = expected_len;
return CRYPTO_SUCCESS;
}
static crypto_error_t derive_key_secure(const char *password, const unsigned char *salt, unsigned char *key_out) {
if (!password || !salt || !key_out) {
return CRYPTO_ERROR_INVALID_INPUT;
}
size_t pw_len = strlen(password);
if (pw_len == 0 || pw_len > MAX_PASSWORD_LENGTH) {
return CRYPTO_ERROR_INVALID_INPUT;
}
int result = crypto_pwhash(
key_out, KEY_SIZE,
password, pw_len,
salt,
OPSLIMIT, MEMLIMIT,
crypto_pwhash_ALG_ARGON2ID13
);
return (result == 0) ? CRYPTO_SUCCESS : CRYPTO_ERROR_KEY_DERIVATION;
}
static crypto_error_t validate_timestamp(uint64_t timestamp) {
uint64_t now = (uint64_t)time(NULL);
if (timestamp > now + TIMESTAMP_TOLERANCE_FUTURE) {
secure_log("WARNING", "Timestamp too far in future");
return CRYPTO_ERROR_TIMESTAMP_INVALID;
}
if (timestamp < now - TIMESTAMP_TOLERANCE_PAST) {
secure_log("WARNING", "Timestamp too old");
return CRYPTO_ERROR_TIMESTAMP_INVALID;
}
return CRYPTO_SUCCESS;
}
static const char* get_error_message(crypto_error_t error) {
switch (error) {
case CRYPTO_SUCCESS: return "Success";
case CRYPTO_ERROR_INIT: return "Cryptographic library initialization failed";
case CRYPTO_ERROR_WEAK_PASSWORD: return "Password does not meet security requirements";
case CRYPTO_ERROR_KEY_DERIVATION: return "Key derivation failed";
case CRYPTO_ERROR_MESSAGE_TOO_LARGE: return "Message exceeds maximum size";
case CRYPTO_ERROR_MEMORY_ALLOCATION: return "Memory allocation failed";
case CRYPTO_ERROR_ENCRYPTION_FAILED: return "Encryption operation failed";
case CRYPTO_ERROR_INVALID_INPUT: return "Invalid input parameters";
case CRYPTO_ERROR_INVALID_VERSION: return "Unsupported format version";
case CRYPTO_ERROR_TIMESTAMP_INVALID: return "Invalid or expired timestamp";
case CRYPTO_ERROR_DECRYPTION_FAILED: return "Decryption failed - wrong password or corrupted data";
case CRYPTO_ERROR_INVALID_HEX: return "Invalid hexadecimal format";
case CRYPTO_ERROR_BUFFER_TOO_SMALL: return "Buffer too small for operation";
default: return "Unknown error";
}
}
crypto_error_t encrypt_message(const char *password, const char *message, char **hex_output) {
if (!password || !message || !hex_output) {
return CRYPTO_ERROR_INVALID_INPUT;
}
*hex_output = NULL;
if (sodium_init() < 0) {
secure_log("ERROR", "Failed to initialize cryptographic library");
return CRYPTO_ERROR_INIT;
}
crypto_error_t pw_result = validate_password_strength(password);
if (pw_result != CRYPTO_SUCCESS) {
return pw_result;
}
size_t msg_len = strlen(message);
if (msg_len > MAX_MSG_SIZE) {
secure_log("ERROR", "Message too large");
return CRYPTO_ERROR_MESSAGE_TOO_LARGE;
}
unsigned char salt[SALT_SIZE];
unsigned char nonce[NONCE_SIZE];
uint64_t timestamp = (uint64_t)time(NULL);
randombytes_buf(salt, SALT_SIZE);
randombytes_buf(nonce, NONCE_SIZE);
unsigned char key[KEY_SIZE];
crypto_error_t key_result = derive_key_secure(password, salt, key);
if (key_result != CRYPTO_SUCCESS) {
secure_wipe(key, KEY_SIZE);
return key_result;
}
secure_buffer_t output_buf;
size_t total_len = HEADER_SIZE + msg_len + MAC_SIZE;
crypto_error_t buf_result = secure_buffer_init(&output_buf, total_len);
if (buf_result != CRYPTO_SUCCESS) {
secure_wipe(key, KEY_SIZE);
return buf_result;
}
size_t pos = 0;
output_buf.data[pos++] = VERSION_BYTE;
memcpy(output_buf.data + pos, salt, SALT_SIZE);
pos += SALT_SIZE;
memcpy(output_buf.data + pos, nonce, NONCE_SIZE);
pos += NONCE_SIZE;
memcpy(output_buf.data + pos, ×tamp, 8);
pos += 8;
unsigned long long ciphertext_len = 0;
int encrypt_result = crypto_aead_chacha20poly1305_ietf_encrypt(
output_buf.data + HEADER_SIZE, &ciphertext_len,
(const unsigned char*)message, msg_len,
output_buf.data, HEADER_SIZE,
NULL,
nonce, key
);
secure_wipe(key, KEY_SIZE);
if (encrypt_result != 0) {
secure_buffer_free(&output_buf);
secure_log("ERROR", "Encryption failed");
return CRYPTO_ERROR_ENCRYPTION_FAILED;
}
output_buf.size = HEADER_SIZE + ciphertext_len;
size_t hex_len = output_buf.size * 2 + 1;
*hex_output = malloc(hex_len);
if (!*hex_output) {
secure_buffer_free(&output_buf);
return CRYPTO_ERROR_MEMORY_ALLOCATION;
}
crypto_error_t hex_result = safe_hex_encode(output_buf.data, output_buf.size, *hex_output, hex_len);
secure_buffer_free(&output_buf);
if (hex_result != CRYPTO_SUCCESS) {
free(*hex_output);
*hex_output = NULL;
return hex_result;
}
secure_log("INFO", "Message encrypted successfully");
return CRYPTO_SUCCESS;
}
crypto_error_t decrypt_message(const char *password, const char *hex_input, char **plaintext_output) {
if (!password || !hex_input || !plaintext_output) {
return CRYPTO_ERROR_INVALID_INPUT;
}
*plaintext_output = NULL;
if (sodium_init() < 0) {
secure_log("ERROR", "Failed to initialize cryptographic library");
return CRYPTO_ERROR_INIT;
}
secure_buffer_t input_buf;
crypto_error_t buf_result = secure_buffer_init(&input_buf, MAX_MSG_SIZE + HEADER_SIZE + MAC_SIZE);
if (buf_result != CRYPTO_SUCCESS) {
return buf_result;
}
size_t decoded_len;
crypto_error_t decode_result = safe_hex_decode(hex_input, input_buf.data, input_buf.capacity, &decoded_len);
if (decode_result != CRYPTO_SUCCESS) {
secure_buffer_free(&input_buf);
return decode_result;
}
input_buf.size = decoded_len;
if (input_buf.size < HEADER_SIZE + MAC_SIZE) {
secure_buffer_free(&input_buf);
secure_log("ERROR", "Input too short");
return CRYPTO_ERROR_INVALID_INPUT;
}
size_t pos = 0;
unsigned char version = input_buf.data[pos++];
if (version != VERSION_BYTE) {
secure_buffer_free(&input_buf);
secure_log("ERROR", "Unsupported version");
return CRYPTO_ERROR_INVALID_VERSION;
}
unsigned char salt[SALT_SIZE];
memcpy(salt, input_buf.data + pos, SALT_SIZE);
pos += SALT_SIZE;
unsigned char nonce[NONCE_SIZE];
memcpy(nonce, input_buf.data + pos, NONCE_SIZE);
pos += NONCE_SIZE;
uint64_t timestamp;
memcpy(×tamp, input_buf.data + pos, 8);
pos += 8;
crypto_error_t ts_result = validate_timestamp(timestamp);
if (ts_result != CRYPTO_SUCCESS) {
secure_buffer_free(&input_buf);
return ts_result;
}
unsigned char key[KEY_SIZE];
crypto_error_t key_result = derive_key_secure(password, salt, key);
if (key_result != CRYPTO_SUCCESS) {
secure_buffer_free(&input_buf);
secure_wipe(key, KEY_SIZE);
return key_result;
}
secure_buffer_t plaintext_buf;
crypto_error_t pt_buf_result = secure_buffer_init(&plaintext_buf, MAX_MSG_SIZE);
if (pt_buf_result != CRYPTO_SUCCESS) {
secure_buffer_free(&input_buf);
secure_wipe(key, KEY_SIZE);
return pt_buf_result;
}
size_t ciphertext_len = input_buf.size - HEADER_SIZE;
unsigned long long plaintext_len;
int decrypt_result = crypto_aead_chacha20poly1305_ietf_decrypt(
plaintext_buf.data, &plaintext_len,
NULL,
input_buf.data + HEADER_SIZE, ciphertext_len,
input_buf.data, HEADER_SIZE,
nonce, key
);
secure_wipe(key, KEY_SIZE);
secure_buffer_free(&input_buf);
if (decrypt_result != 0) {
secure_buffer_free(&plaintext_buf);
secure_log("ERROR", "Decryption failed");
return CRYPTO_ERROR_DECRYPTION_FAILED;
}
*plaintext_output = malloc(plaintext_len + 1);
if (!*plaintext_output) {
secure_buffer_free(&plaintext_buf);
return CRYPTO_ERROR_MEMORY_ALLOCATION;
}
memcpy(*plaintext_output, plaintext_buf.data, plaintext_len);
(*plaintext_output)[plaintext_len] = '\0';
secure_buffer_free(&plaintext_buf);
secure_log("INFO", "Message decrypted successfully");
return CRYPTO_SUCCESS;
}
void generate_test_vector(void) {
const char *test_password = "SecureTestPassword123!@#";
const char *test_message = "This is a test message for cryptographic verification.";
char *encrypted_hex = NULL;
printf("=== Cryptographic Test Vector ===\n");
printf("Password: %s\n", test_password);
printf("Message: %s\n", test_message);
crypto_error_t result = encrypt_message(test_password, test_message, &encrypted_hex);
if (result == CRYPTO_SUCCESS && encrypted_hex) {
printf("Encrypted (hex): %s\n", encrypted_hex);
char *decrypted = NULL;
crypto_error_t decrypt_result = decrypt_message(test_password, encrypted_hex, &decrypted);
if (decrypt_result == CRYPTO_SUCCESS && decrypted) {
printf("Decrypted: %s\n", decrypted);
printf("Test: %s\n", strcmp(test_message, decrypted) == 0 ? "PASSED" : "FAILED");
free(decrypted);
} else {
printf("Decryption failed: %s\n", get_error_message(decrypt_result));
}
free(encrypted_hex);
} else {
printf("Encryption failed: %s\n", get_error_message(result));
}
printf("================================\n");
}
void print_usage(const char *program_name) {
printf("\nSecure Encryption Tool\n");
printf("Usage:\n");
printf(" %s -e -k <password> -m <message> # Encrypt message\n", program_name);
printf(" %s -d -k <password> -h <hex_data> # Decrypt hex data\n", program_name);
printf(" %s -t # Generate test vector\n", program_name);
printf(" %s --help # Show this help\n", program_name);
printf("\nSecurity Requirements:\n");
printf(" - Password must be at least %d characters\n", MIN_PASSWORD_LENGTH);
printf(" - Password should use multiple character classes\n");
printf(" - Messages are limited to %d bytes\n", MAX_MSG_SIZE);
printf(" - Encrypted data expires after %d days\n", TIMESTAMP_TOLERANCE_PAST / (24 * 3600));
printf("\n");
}
typedef struct {
char *password;
char *message;
char *hex_data;
int encrypt_mode;
int decrypt_mode;
int test_mode;
int help_mode;
} program_args_t;
static crypto_error_t parse_arguments(int argc, char *argv[], program_args_t *args) {
memset(args, 0, sizeof(*args));
if (argc < 2) {
args->help_mode = 1;
return CRYPTO_SUCCESS;
}
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-e") == 0) {
args->encrypt_mode = 1;
} else if (strcmp(argv[i], "-d") == 0) {
args->decrypt_mode = 1;
} else if (strcmp(argv[i], "-t") == 0) {
args->test_mode = 1;
} else if (strcmp(argv[i], "--xhelp") == 0 || strcmp(argv[i], "-xh") == 0) {
args->help_mode = 1;
} else if (strcmp(argv[i], "-k") == 0 && i + 1 < argc) {
args->password = argv[++i];
} else if (strcmp(argv[i], "-m") == 0 && i + 1 < argc) {
args->message = argv[++i];
} else if (strcmp(argv[i], "-h") == 0 && i + 1 < argc) {
args->hex_data = argv[++i];
} else {
secure_log("ERROR", "Unknown argument");
return CRYPTO_ERROR_INVALID_INPUT;
}
}
return CRYPTO_SUCCESS;
}
int main(int argc, char *argv[]) {
program_args_t args;
crypto_error_t parse_result = parse_arguments(argc, argv, &args);
if (parse_result != CRYPTO_SUCCESS || args.help_mode) {
print_usage(argv[0]);
return (parse_result == CRYPTO_SUCCESS) ? 0 : 1;
}
if (args.test_mode) {
generate_test_vector();
return 0;
}
if (args.encrypt_mode) {
if (!args.password || !args.message) {
fprintf(stderr, "Error: Encryption requires password (-k) and message (-m)\n");
print_usage(argv[0]);
return 1;
}
char *encrypted_hex = NULL;
crypto_error_t result = encrypt_message(args.password, args.message, &encrypted_hex);
if (result == CRYPTO_SUCCESS && encrypted_hex) {
printf("%s\n", encrypted_hex);
free(encrypted_hex);
return 0;
} else {
fprintf(stderr, "Encryption failed: %s\n", get_error_message(result));
return 1;
}
}
if (args.decrypt_mode) {
if (!args.password || !args.hex_data) {
fprintf(stderr, "Error: Decryption requires password (-k) and hex data (-h)\n");
print_usage(argv[0]);
return 1;
}
char *decrypted_message = NULL;
crypto_error_t result = decrypt_message(args.password, args.hex_data, &decrypted_message);
if (result == CRYPTO_SUCCESS && decrypted_message) {
printf("%s\n", decrypted_message);
free(decrypted_message);
return 0;
} else {
fprintf(stderr, "Decryption failed: %s\n", get_error_message(result));
return 1;
}
}
fprintf(stderr, "Error: Must specify operation mode (-e, -d, or -t)\n");
print_usage(argv[0]);
return 1;
}