//
// crypt.c
// secrets
//
// Created by Anders on 08/07/2020.
//
#if defined linux || defined __linux__
#include <bsd/stdlib.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "crypt.h"
#include "../lib/monocypher.h"
#include "../util/require.h"
#include "../util/stringu.h"
static void create_key(uint8_t key[KEY_SIZE], const uint8_t salt[SALT_SIZE], char *password) {
uint32_t password_size = (uint32_t) strlen(password);
const uint32_t nb_blocks = 100000; /* 100 megabytes */
const uint32_t nb_iterations = 3; /* 3 iterations */
void *work_area = malloc(nb_blocks * 1024); /* Work area */
if (work_area == NULL) {
/* Handle malloc() failure */
/* Wipe secrets if they are no longer needed */
crypto_wipe(password, password_size);
} else {
crypto_argon2i(key, KEY_SIZE,
work_area, nb_blocks, nb_iterations,
(uint8_t *)password, password_size,
salt, SALT_SIZE);
crypto_wipe(password, password_size);
free(work_area);
}
}
static void encrypt(Secret *secret, uint8_t key[KEY_SIZE], char *message) {
uint16_t message_size = (uint16_t) strlen(message);
secret->cipher = malloc(message_size);
secret->cipher_size = message_size;
arc4random_buf(secret->nonce, NONCE_SIZE);
crypto_lock(secret->mac, secret->cipher, key, secret->nonce, (uint8_t*) message, message_size);
crypt_wipe(message);
crypto_wipe(key, KEY_SIZE);
}
static bool decrypt(FILE* dest, uint8_t key[KEY_SIZE], const Secret *secret) {
char message[secret->cipher_size + 1];
message[secret->cipher_size] = '\0';
if (crypto_unlock((uint8_t*) message, key, secret->nonce, secret->mac, secret->cipher, secret->cipher_size)) {
/* The message is corrupted.
* Wipe key if it is no longer needed,
* and abort the decryption.
*/
crypto_wipe(key, KEY_SIZE);
return false;
} else {
fprintf(dest, "%s", message);
crypt_wipe(message);
crypto_wipe(key, KEY_SIZE);
return true;;
}
}
Secret* crypt_create_alloc(char *password, char *message) {
require(!stringu_equals(password, message), "secret and decrypt-password should not be the same\n");
Secret* secret = calloc(1, sizeof(*secret));
arc4random_buf(secret->salt, SALT_SIZE);
uint8_t key[KEY_SIZE];
create_key(key, secret->salt, password);
encrypt(secret, key, message);
return secret;
}
bool crypt_print(FILE* dest, char *password, const Secret* secret) {
uint8_t key[KEY_SIZE];
create_key(key, secret->salt, password);
return decrypt(dest, key, secret);
}
void crypt_wipe(char *text) {
crypto_wipe(text, strlen(text) + 1);
}