aboutsummaryrefslogtreecommitdiffstats
path: root/src/inexact.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/inexact.c')
-rw-r--r--src/inexact.c1033
1 files changed, 1033 insertions, 0 deletions
diff --git a/src/inexact.c b/src/inexact.c
new file mode 100644
index 0000000..231eb3f
--- /dev/null
+++ b/src/inexact.c
@@ -0,0 +1,1033 @@
+/* Inexact source code package.
+ *
+ * Written in 2019 by <ben@hackade.org>.
+ *
+ * To the extent possible under law, the author have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along with
+ * this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include "inexact.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h> // for chmod only
+#include <unistd.h>
+#include "argon2.h"
+#include "base64.h"
+#include "chacha20_drng.h"
+#include "curve25519.h"
+#include "norx_inexact.h"
+#include "readpassphrase.h"
+#include "sha3.h"
+
+/*
+ * Generate a random private key and derive the X25519 public key.
+ * Store result in base64 to files.
+ *
+ */
+int generate_keys(const char *seckey_filename, const char *pubkey_filename,
+ int no_password) {
+ unsigned char *privatekey_b64 = NULL;
+ unsigned char *publickey_b64 = NULL;
+ unsigned char *privatekey_b64t = NULL;
+ unsigned char *publickey_b64t = NULL;
+ unsigned char salt[32] = {0};
+ unsigned char privatekey_buffer[64] = {0};
+
+ char password[256] = {0};
+ char *password_out = NULL;
+ char password_verif[256] = {0};
+ char *password_verif_out = NULL;
+ size_t password_len = 0;
+ size_t password_verif_len = 0;
+
+ const uint32_t t_cost = 3;
+ const uint32_t m_cost = (1 << 12);
+ const uint32_t parallelism = 1;
+
+ size_t private_base64_len = 0;
+ size_t private_b64t_len = 0;
+ size_t public_base64_len = 0;
+ size_t public_b64t_len = 0;
+
+ FILE *fs = NULL;
+ FILE *fp = NULL;
+
+ struct chacha20_drng *drng = NULL;
+
+ int exitcode = 1;
+
+ curve25519_key privatekey;
+ curve25519_key publickey;
+
+ /* Secret (or private) key */
+
+ if (no_password) {
+ int ret = drng_chacha20_init(&drng);
+ if (ret) {
+ printf("Chacha20 allocation failed: %d\n", ret);
+ goto exit;
+ }
+ if (drng_chacha20_get(drng, privatekey, sizeof(curve25519_key))) {
+ printf("Getting random numbers failed\n");
+ goto exit;
+ }
+
+ curve25519_donna_basepoint(publickey, privatekey);
+
+ memcpy(privatekey_buffer, privatekey, sizeof(curve25519_key));
+ memcpy(privatekey_buffer + sizeof(curve25519_key), publickey,
+ sizeof(curve25519_key));
+ } else {
+ struct chacha20_drng *drng;
+ int ret = drng_chacha20_init(&drng);
+ if (ret) {
+ printf("Chacha20 allocation failed: %d\n", ret);
+ goto exit;
+ }
+ if (drng_chacha20_get(drng, salt, sizeof(salt))) {
+ printf("Getting random numbers failed\n");
+ goto exit;
+ }
+
+ password_out =
+ readpassphrase("Password : ", password, sizeof(password), 0);
+ if (password_out != password) {
+ printf("password input failed.\n");
+ goto exit;
+ }
+ password_len = strlen(password);
+
+ password_verif_out =
+ readpassphrase("Verifying, please re-enter : ", password_verif,
+ sizeof(password_verif), 0);
+ if (password_verif_out != password_verif) {
+ printf("password input failed.\n");
+ goto exit;
+ }
+ password_verif_len = strlen(password_verif);
+
+ if (password_len != password_verif_len) {
+ printf("Mismatch.\n");
+ goto exit;
+ }
+
+ if (memcmp(password, password_verif, password_len) != 0) {
+ printf("Mismatch.\n");
+ goto exit;
+ }
+
+ int a2res = argon2id_hash_raw(t_cost, m_cost, parallelism, password,
+ password_len, salt, sizeof(salt),
+ privatekey, sizeof(curve25519_key));
+ if (a2res != ARGON2_OK) {
+ printf("argon2 failed.");
+ goto exit;
+ }
+
+ curve25519_donna_basepoint(publickey, privatekey);
+ memcpy(privatekey_buffer, salt, sizeof(salt));
+ memcpy(privatekey_buffer + sizeof(salt), publickey,
+ sizeof(curve25519_key));
+ }
+
+ privatekey_b64 = base64_encode(privatekey_buffer, sizeof(privatekey_buffer),
+ &private_base64_len);
+ if (privatekey_b64 == NULL) {
+ printf("base64 encoding failed.\n");
+ goto exit;
+ }
+
+ privatekey_b64t =
+ b64t_encode(privatekey_b64, private_base64_len, &private_b64t_len);
+ if (privatekey_b64t == NULL) {
+ printf("b64t encoding failed.\n");
+ goto exit;
+ }
+
+ fs = fopen(seckey_filename, "wb");
+ if (fs == NULL) {
+ printf("secret key file opening failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+
+ ssize_t slen = fwrite(privatekey_b64t, 1, private_b64t_len, fs);
+ if (slen != private_b64t_len) {
+ printf("secret key file writing failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+ if (fwrite("\n", 1, 1, fs) != 1) {
+ printf("public key file writing failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+
+ int res = chmod(seckey_filename, S_IRUSR | S_IWUSR);
+ if (res != 0) {
+ printf("secret key file chmod failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+
+ /* Public key */
+
+ publickey_b64 =
+ base64_encode(publickey, sizeof(curve25519_key), &public_base64_len);
+
+ if (publickey_b64 == NULL) {
+ printf("base64 encoding failed.\n");
+ goto exit;
+ }
+
+ publickey_b64t =
+ b64t_encode(publickey_b64, public_base64_len, &public_b64t_len);
+
+ if (publickey_b64t == NULL) {
+ printf("b64t encoding failed.\n");
+ goto exit;
+ }
+
+ fp = fopen(pubkey_filename, "wb");
+ if (fp == NULL) {
+ printf("public key file opening failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+
+ ssize_t plen = fwrite(publickey_b64t, 1, public_b64t_len, fp);
+ if (plen != public_b64t_len) {
+ printf("public key file writing failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+ if (fwrite("\n", 1, 1, fp) != 1) {
+ printf("public key file writing failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+
+ exitcode = 0;
+
+exit:
+ drng_chacha20_destroy(drng);
+
+ memset(privatekey_b64, 0, private_base64_len);
+ memset(privatekey_b64t, 0, private_b64t_len);
+ memset(privatekey, 0, sizeof(curve25519_key));
+ memset(publickey_b64, 0, public_base64_len);
+ memset(publickey_b64t, 0, public_b64t_len);
+ memset(publickey, 0, sizeof(curve25519_key));
+ memset(salt, 0, sizeof(salt));
+ memset(privatekey_buffer, 0, sizeof(privatekey_buffer));
+ memset(password, 0, sizeof(password));
+ memset(password_verif, 0, sizeof(password_verif));
+
+ free(privatekey_b64);
+ free(publickey_b64);
+ free(privatekey_b64t);
+ free(publickey_b64t);
+
+ if (fs != NULL) {
+ fclose(fs);
+ }
+ if (fp != NULL) {
+ fclose(fp);
+ }
+
+ return exitcode;
+}
+
+/*
+ * Return key file content in key variable.
+ *
+ */
+int get_seckey(const char *keyfile, unsigned char *skey, unsigned char *pkey) {
+ unsigned char *base64_decoded = NULL;
+ unsigned char *b64t_decoded = NULL;
+
+ size_t base64_decoded_len = 0;
+ size_t b64t_decoded_len = 0;
+ size_t password_len = 0;
+
+ FILE *fs = NULL;
+
+ unsigned char salt[32] = {0};
+ char password[256] = {0};
+ char *password_out = NULL;
+ curve25519_key pubkey;
+ curve25519_key pubkey_from_secret;
+ curve25519_key seckey;
+
+ const uint32_t t_cost = 3;
+ const uint32_t m_cost = (1 << 12);
+ const uint32_t parallelism = 1;
+
+ int exitcode = 1;
+
+ fs = fopen(keyfile, "rb");
+ if (fs == NULL) {
+ printf("key file opening failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+
+ int rsb = fseek(fs, 0L, SEEK_END);
+ if (rsb != 0) {
+ printf("seek to end file '%s' failed: %s.\n", keyfile, strerror(errno));
+ goto exit;
+ }
+
+ size_t sz = ftell(fs);
+ if (sz == -1) {
+ printf("tell file '%s' failed: %s.\n", keyfile, strerror(errno));
+ goto exit;
+ }
+
+ int rse = fseek(fs, 0L, SEEK_SET);
+ if (rse != 0) {
+ printf("seek file to begin'%s' failed: %s.\n", keyfile,
+ strerror(errno));
+ goto exit;
+ }
+
+ /* max_size = base64(sizeof(curve25519_key)) = 64 * 4 / 3 + 1 -> 86 */
+ unsigned char file_data[87] = {0};
+
+ size_t readed = fread(&file_data, 1, sz, fs);
+ if (readed != sz) {
+ printf("read file '%s' failed: %s.\n", keyfile, strerror(errno));
+ goto exit;
+ }
+
+ b64t_decoded = b64t_decode(file_data, readed, &b64t_decoded_len);
+ if (b64t_decoded == NULL) {
+ printf("b64t decoding failed.\n");
+ goto exit;
+ }
+
+ base64_decoded =
+ base64_decode(b64t_decoded, b64t_decoded_len, &base64_decoded_len);
+ if (base64_decoded == NULL) {
+ printf("base64 decoding failed.\n");
+ goto exit;
+ }
+
+ if (base64_decoded_len != 64) {
+ printf("decoded size mismatch.\n");
+ goto exit;
+ }
+
+ memcpy(seckey, base64_decoded, sizeof(curve25519_key));
+ memcpy(pubkey, base64_decoded + sizeof(curve25519_key),
+ sizeof(curve25519_key));
+ curve25519_donna_basepoint(pubkey_from_secret, seckey);
+
+ int password_protected_flag =
+ (memcmp(pubkey, pubkey_from_secret, sizeof(curve25519_key)) != 0);
+ if (password_protected_flag) {
+ memcpy(salt, base64_decoded, sizeof(salt));
+ password_out =
+ readpassphrase("Password : ", password, sizeof(password), 0);
+ if (password_out != password) {
+ printf("password input failed.\n");
+ goto exit;
+ }
+ password_len = strlen(password);
+
+ int a2res = argon2id_hash_raw(t_cost, m_cost, parallelism, password,
+ password_len, salt, sizeof(salt), seckey,
+ sizeof(curve25519_key));
+ if (a2res != ARGON2_OK) {
+ printf("argon2 failed.");
+ goto exit;
+ }
+ curve25519_donna_basepoint(pubkey_from_secret, seckey);
+ if (memcmp(pubkey_from_secret, pubkey, sizeof(curve25519_key)) != 0) {
+ printf("Bad password\n");
+ goto exit;
+ }
+ }
+
+ memcpy(skey, seckey, sizeof(curve25519_key));
+ if (pkey != NULL) {
+ memcpy(pkey, pubkey_from_secret, sizeof(curve25519_key));
+ }
+ exitcode = 0;
+
+exit:
+ memset(file_data, 0, sizeof(file_data));
+ memset(base64_decoded, 0, base64_decoded_len);
+ memset(b64t_decoded, 0, b64t_decoded_len);
+ memset(salt, 0, sizeof(salt));
+ memset(password, 0, sizeof(password));
+ memset(seckey, 0, sizeof(curve25519_key));
+ memset(pubkey, 0, sizeof(curve25519_key));
+ memset(pubkey_from_secret, 0, sizeof(curve25519_key));
+
+ if (fs != NULL) {
+ fclose(fs);
+ }
+
+ free(base64_decoded);
+ free(b64t_decoded);
+
+ return exitcode;
+}
+
+/*
+ * Return key file content in key variable.
+ *
+ */
+int get_pubkey(const char *keyfile, unsigned char *pkey) {
+ unsigned char *base64_decoded = NULL;
+ unsigned char *b64t_decoded = NULL;
+
+ size_t b64t_decoded_len = 0;
+ size_t base64_decoded_len = 0;
+
+ FILE *fs = NULL;
+
+ curve25519_key pubkey;
+
+ int exitcode = 1;
+
+ fs = fopen(keyfile, "rb");
+ if (fs == NULL) {
+ printf("key file opening failed: %s.\n", strerror(errno));
+ goto exit;
+ }
+
+ int rsb = fseek(fs, 0L, SEEK_END);
+ if (rsb != 0) {
+ printf("seek to end file '%s' failed: %s.\n", keyfile, strerror(errno));
+ goto exit;
+ }
+
+ size_t sz = ftell(fs);
+ if (sz == -1) {
+ printf("tell file '%s' failed: %s.\n", keyfile, strerror(errno));
+ goto exit;
+ }
+
+ int rse = fseek(fs, 0L, SEEK_SET);
+ if (rse != 0) {
+ printf("seek file to begin'%s' failed: %s.\n", keyfile,
+ strerror(errno));
+ goto exit;
+ }
+
+ /* max_size = base64(sizeof(curve25519_key)) = 32 * 4 / 3 + 1 -> 44 */
+ unsigned char file_data[44] = {0};
+ size_t readed = fread(&file_data, 1, sz, fs);
+ if (readed != sz) {
+ printf("read file '%s' failed: %s.\n", keyfile, strerror(errno));
+ goto exit;
+ }
+
+ b64t_decoded = b64t_decode(file_data, readed, &b64t_decoded_len);
+ if (b64t_decoded == NULL) {
+ printf("b64t decoding failed.\n");
+ goto exit;
+ }
+
+ base64_decoded =
+ base64_decode(b64t_decoded, b64t_decoded_len, &base64_decoded_len);
+ if (base64_decoded == NULL) {
+ printf("base64 decoding failed.\n");
+ goto exit;
+ }
+
+ if (base64_decoded_len != 32) {
+ printf("decoded size mismatch.\n");
+ goto exit;
+ }
+
+ memcpy(pkey, base64_decoded, 32);
+
+ exitcode = 0;
+
+exit:
+ memset(file_data, 0, sizeof(file_data));
+ memset(b64t_decoded, 0, b64t_decoded_len);
+ memset(base64_decoded, 0, base64_decoded_len);
+ memset(pubkey, 0, sizeof(curve25519_key));
+
+ if (fs != NULL) {
+ fclose(fs);
+ }
+
+ free(b64t_decoded);
+ free(base64_decoded);
+
+ return exitcode;
+}
+
+/*
+ * Encrypt data, return allocated message in base64.
+ *
+ */
+unsigned char *encrypt_data(const unsigned char *seckey,
+ const unsigned char *pubkey,
+ const unsigned char *salt,
+ const unsigned char *data,
+ size_t data_len, // in bytes
+ size_t rand_len, // in bytes
+ size_t tag1_len, // in bytes
+ int base64_transformation, // 0 or 1
+ size_t *out_encrypted_len) {
+ unsigned char *rand = NULL;
+ unsigned char *encrypted1 = NULL;
+ unsigned char *part1 = NULL;
+ unsigned char *encrypted = NULL;
+ unsigned char *encrypted_b64 = NULL;
+ unsigned char *encrypted_b64t = NULL;
+ unsigned char *out = NULL;
+
+ size_t encrypted1_len = 0;
+ size_t norx_encrypted1_len = 0;
+ size_t tag1_len_bits = tag1_len * 8;
+ size_t part1_len = 0;
+ size_t part0_len = 0;
+ size_t norx_params_encrypted_len = 0;
+ size_t encrypted_b64_len = 0;
+ size_t encrypted_b64t_len = 0;
+ size_t encrypted_len = 0;
+
+ const size_t shared_secret_len = 32;
+ unsigned char shared_secret[32] = {0};
+
+ const size_t nonce1_len = 32;
+ const size_t tag0_len = 4;
+ const size_t tag0_len_bits = tag0_len * 8;
+ const size_t params_len = 5;
+ const size_t params_encrypted_len = 9; // params_len + tag0_len
+ const size_t nonce0_len = 32;
+ const size_t header0_len = 4;
+ const size_t encrypted_len_expected = data_len + tag1_len;
+
+ const uint8_t *key1 = 0;
+ const uint8_t *nonce1 = 0;
+ unsigned char params[5] = {0};
+ unsigned char params_encrypted[9] = {0};
+ const uint8_t *key0 = 0;
+ const uint8_t *nonce0 = 0;
+ unsigned char header0[4] = {0};
+
+ struct chacha20_drng *drng = NULL;
+
+ *out_encrypted_len = 0;
+
+ // generate shared secret from DH X25519
+ curve25519_donna(shared_secret, seckey, pubkey);
+
+ // generate part 1 random data
+ rand = malloc(rand_len);
+ if (rand == NULL) {
+ printf("malloc failed.\n");
+ goto exit;
+ }
+
+ int ret = drng_chacha20_init(&drng);
+ if (ret) {
+ printf("Chacha20 allocation failed: %d\n", ret);
+ goto exit;
+ }
+ if (drng_chacha20_get(drng, rand, rand_len)) {
+ printf("Getting random numbers failed\n");
+ goto exit;
+ }
+
+ // generate part 0 message
+ part0_len = params_len + tag0_len;
+
+ params[0] = (rand_len >> 24) & 0xFF;
+ params[1] = (rand_len >> 16) & 0xFF;
+ params[2] = (rand_len >> 8) & 0xFF;
+ params[3] = rand_len & 0xFF;
+
+ params[4] = tag1_len;
+
+ // calculate part length
+ encrypted1_len = tag1_len + data_len;
+ part1_len = encrypted1_len + rand_len;
+ encrypted_len = part0_len + part1_len;
+
+ // generate part 0 header
+ header0[0] = (encrypted_len >> 24) & 0xFF;
+ header0[1] = (encrypted_len >> 16) & 0xFF;
+ header0[2] = (encrypted_len >> 8) & 0xFF;
+ header0[3] = encrypted_len & 0xFF;
+
+ // generate nonce 1
+ sha3_context nc1;
+ sha3_Init256(&nc1);
+ sha3_Update(&nc1, params, params_len);
+ sha3_Update(&nc1, rand, rand_len);
+ nonce1 = sha3_Finalize(&nc1);
+
+ // generate key for part1
+ sha3_context kc1;
+ sha3_Init256(&kc1);
+ sha3_Update(&kc1, nonce1, nonce1_len);
+ sha3_Update(&kc1, shared_secret, shared_secret_len);
+ key1 = sha3_Finalize(&kc1);
+
+ // encrypt message data
+ encrypted1 = malloc(encrypted1_len);
+ if (encrypted1 == NULL) {
+ printf("malloc failed.\n");
+ goto exit;
+ }
+
+ norx_aead_encrypt(encrypted1, &norx_encrypted1_len, params, params_len,
+ data, data_len, NULL, 0, nonce1, key1, tag1_len_bits);
+ if (encrypted1_len != norx_encrypted1_len ||
+ norx_encrypted1_len != encrypted_len_expected) {
+ printf("Norx encryption failed.\n");
+ goto exit;
+ }
+
+ // generate full part 1 buffer
+ part1 = malloc(part1_len);
+ if (part1 == NULL) {
+ printf("malloc failed.\n");
+ goto exit;
+ }
+ memcpy(part1, rand, rand_len);
+ memcpy((part1 + rand_len), encrypted1, encrypted1_len);
+
+ // generate part 0 nonce: sha3-256(rand+encrypted1)
+ sha3_context nc0;
+ sha3_Init256(&nc0);
+ sha3_Update(&nc0, part1, part1_len);
+ nonce0 = sha3_Finalize(&nc0);
+
+ // generate key for part 0
+ sha3_context kc0;
+ sha3_Init256(&kc0);
+ sha3_Update(&kc0, nonce0, nonce0_len);
+ sha3_Update(&kc0, shared_secret, shared_secret_len);
+ key0 = sha3_Finalize(&kc0);
+
+ // encrypt params (part 0 message)
+ norx_aead_encrypt(params_encrypted, &norx_params_encrypted_len, header0,
+ header0_len, params, params_len, NULL, 0, nonce0, key0,
+ tag0_len_bits);
+ if (params_encrypted_len != norx_params_encrypted_len) {
+ printf("Norx encryption failed.\n");
+ goto exit;
+ }
+
+ // symmetric case
+ if (salt) {
+ encrypted_len = encrypted_len + 64;
+ }
+
+ // generate full message buffer
+ encrypted = malloc(encrypted_len);
+ if (encrypted == NULL) {
+ printf("malloc failed.\n");
+ goto exit;
+ }
+
+ if (salt) {
+ memcpy(encrypted, salt, 32);
+ memcpy(32 + encrypted, pubkey, 32);
+ memcpy(64 + encrypted, params_encrypted, params_encrypted_len);
+ memcpy(64 + encrypted + params_encrypted_len, part1, part1_len);
+ } else {
+ memcpy(encrypted, params_encrypted, params_encrypted_len);
+ memcpy(encrypted + params_encrypted_len, part1, part1_len);
+ }
+
+ // encode full message in base64
+ encrypted_b64 = base64_encode(encrypted, encrypted_len, &encrypted_b64_len);
+ if (encrypted_b64 == NULL || encrypted_b64_len == 0 ||
+ encrypted_b64_len < encrypted_len) {
+ printf("Base64 encoding failed.\n");
+ goto exit;
+ }
+
+ // transform base64 encoding
+ if (base64_transformation) {
+ encrypted_b64t =
+ b64t_encode(encrypted_b64, encrypted_b64_len, &encrypted_b64t_len);
+ if (encrypted_b64t == NULL || encrypted_b64t_len == 0) {
+ memset(encrypted_b64, 0, encrypted_b64_len);
+ free(encrypted_b64);
+ goto exit;
+ }
+ out = encrypted_b64t;
+ *out_encrypted_len = encrypted_b64t_len;
+ memset(encrypted_b64, 0, encrypted_b64_len);
+ free(encrypted_b64);
+ } else {
+ out = encrypted_b64;
+ *out_encrypted_len = encrypted_b64_len;
+ }
+
+exit:
+ drng_chacha20_destroy(drng);
+
+ memset(rand, 0, rand_len);
+ memset(encrypted1, 0, encrypted1_len);
+ memset(part1, 0, part1_len);
+ memset(encrypted, 0, encrypted_len);
+ memset(params, 0, params_len);
+ memset(params_encrypted, 0, params_encrypted_len);
+ memset(shared_secret, 0, shared_secret_len);
+ memset(header0, 0, header0_len);
+
+ memset(&kc0, 0, sizeof(sha3_context));
+ memset(&kc1, 0, sizeof(sha3_context));
+ memset(&nc0, 0, sizeof(sha3_context));
+ memset(&nc1, 0, sizeof(sha3_context));
+
+ free(rand);
+ free(encrypted1);
+ free(part1);
+ free(encrypted);
+
+ return out;
+}
+
+int get_symmetrickeys(unsigned char *salt_out, unsigned char *seckey_out,
+ unsigned char *pubkey_out) {
+ struct chacha20_drng *drng;
+
+ const uint32_t t_cost = 3;
+ const uint32_t m_cost = (1 << 12);
+ const uint32_t parallelism = 1;
+
+ char password[256] = {0};
+ char *password_out = NULL;
+ char password_verif[256] = {0};
+ char *password_verif_out = NULL;
+ size_t password_len = 0;
+ size_t password_verif_len = 0;
+
+ int exitcode = 1;
+
+ int ret = drng_chacha20_init(&drng);
+ if (ret) {
+ printf("Chacha20 allocation failed: %d\n", ret);
+ goto exit;
+ }
+ if (drng_chacha20_get(drng, salt_out, 32)) {
+ printf("Getting random numbers failed\n");
+ goto exit;
+ }
+
+ password_out = readpassphrase("Password : ", password, sizeof(password), 0);
+ if (password_out != password) {
+ printf("password input failed.\n");
+ goto exit;
+ }
+ password_len = strlen(password);
+
+ password_verif_out =
+ readpassphrase("Verifying, please re-enter : ", password_verif,
+ sizeof(password_verif), 0);
+ if (password_verif_out != password_verif) {
+ printf("password input failed.\n");
+ goto exit;
+ }
+ password_verif_len = strlen(password_verif);
+
+ if (password_len != password_verif_len) {
+ printf("Mismatch.\n");
+ goto exit;
+ }
+
+ if (memcmp(password, password_verif, password_len) != 0) {
+ printf("Mismatch.\n");
+ goto exit;
+ }
+
+ int a2res =
+ argon2id_hash_raw(t_cost, m_cost, parallelism, password, password_len,
+ salt_out, 32, seckey_out, sizeof(curve25519_key));
+ if (a2res != ARGON2_OK) {
+ printf("argon2 failed.");
+ goto exit;
+ }
+
+ curve25519_donna_basepoint(pubkey_out, seckey_out);
+
+ exitcode = 0;
+
+exit:
+ drng_chacha20_destroy(drng);
+ memset(password, 0, sizeof(password));
+ memset(password_verif, 0, sizeof(password_verif));
+
+ return exitcode;
+}
+
+int check_get_symmetrickeys(const unsigned char *data, const size_t data_len,
+ unsigned char *seckey_out,
+ unsigned char *pubkey_out) {
+ const uint32_t t_cost = 3;
+ const uint32_t m_cost = (1 << 12);
+ const uint32_t parallelism = 1;
+
+ char password[256] = {0};
+ char *password_out = NULL;
+ size_t password_len = 0;
+
+ unsigned char *data_b64t_decoded = NULL;
+ unsigned char *encrypted = NULL;
+ size_t data_b64t_decoded_len = 0;
+ size_t encrypted_len = 0;
+
+ unsigned char salt[32] = {0};
+
+ curve25519_key pubkey_from_secret;
+ int exitcode = 1;
+
+ data_b64t_decoded = b64t_decode(data, data_len, &data_b64t_decoded_len);
+
+ encrypted =
+ base64_decode(data_b64t_decoded, data_b64t_decoded_len, &encrypted_len);
+ if (encrypted == NULL) {
+ printf("base64 decoding failed.\n");
+ goto exit;
+ }
+
+ memcpy(salt, encrypted, 32);
+ memcpy(pubkey_from_secret, encrypted + 32, 32);
+
+ password_out = readpassphrase("Password : ", password, sizeof(password), 0);
+ if (password_out != password) {
+ printf("password input failed.\n");
+ goto exit;
+ }
+ password_len = strlen(password);
+
+ int a2res =
+ argon2id_hash_raw(t_cost, m_cost, parallelism, password, password_len,
+ salt, 32, seckey_out, sizeof(curve25519_key));
+ if (a2res != ARGON2_OK) {
+ printf("argon2 failed.");
+ goto exit;
+ }
+
+ curve25519_donna_basepoint(pubkey_out, seckey_out);
+ if (memcmp(pubkey_out, pubkey_from_secret, sizeof(curve25519_key)) != 0) {
+ printf("Wrong password\n");
+ memset(seckey_out, 0, sizeof(curve25519_key));
+ memset(salt, 0, 32);
+ memset(pubkey_out, 0, sizeof(curve25519_key));
+ goto exit;
+ }
+
+ exitcode = 0;
+
+exit:
+ memset(password, 0, sizeof(password));
+ memset(encrypted, 0, encrypted_len);
+ memset(data_b64t_decoded, 0, data_b64t_decoded_len);
+
+ free(encrypted);
+ free(data_b64t_decoded);
+
+ return exitcode;
+}
+
+/*
+ * Decrypt data, return allocated clear text message.
+ *
+ */
+unsigned char *decrypt_data(const unsigned char *seckey,
+ const unsigned char *pubkey,
+ const unsigned char *data, size_t data_len,
+ int symmetric_flag, size_t *data_len_out) {
+ unsigned char *data_b64t_decoded = NULL;
+ unsigned char *encrypted = NULL;
+ unsigned char *part1 = NULL;
+ unsigned char *rand = NULL;
+ unsigned char *message = NULL;
+ unsigned char *encrypted1 = NULL;
+
+ size_t shared_secret_len = 32;
+ unsigned char shared_secret[32] = {0};
+
+ size_t encrypted_len = 0;
+ size_t data_b64t_decoded_len = 0;
+ size_t part1_len = 0;
+ size_t rand_len = 0;
+ size_t tag1_len = 0;
+ size_t tag1_len_bits = 0;
+ size_t encrypted1_len = 0;
+ size_t message_len = 0;
+ size_t norx_message_len = 0;
+
+ const size_t tag1_len_min = 4;
+ const size_t rand_len_min = 4;
+ const size_t nonce1_len = 32;
+ const size_t tag0_len = 4;
+ const size_t tag0_len_bits = tag0_len * 8;
+ const size_t part0_len = 9; // params_len + tag0_len;
+ const size_t nonce0_len = 32;
+
+ const uint8_t *nonce0 = 0;
+ const size_t header0_len = 4;
+ unsigned char header0[4] = {0};
+ const uint8_t *key0 = 0;
+ unsigned char encrypted0[9] = {0};
+ const size_t params_len = 5;
+ unsigned char params[5];
+ size_t norx_params_len = 0;
+ const uint8_t *nonce1 = 0;
+ const uint8_t *key1 = 0;
+
+ // shared secret DH X25519
+ curve25519_donna(shared_secret, seckey, pubkey);
+
+ // decode base64
+ data_b64t_decoded = b64t_decode(data, data_len, &data_b64t_decoded_len);
+
+ // decode base64 transformation
+ encrypted =
+ base64_decode(data_b64t_decoded, data_b64t_decoded_len, &encrypted_len);
+ if (encrypted == NULL) {
+ printf("base64 decoding failed.\n");
+ goto exit;
+ }
+ if (encrypted_len < part0_len + tag1_len_min + rand_len_min) {
+ printf("Size mismatch.\n");
+ goto exit;
+ }
+
+ if (symmetric_flag) {
+ encrypted = encrypted + 64;
+ encrypted_len = encrypted_len - 64;
+ }
+
+ // part1 message allocation and copy
+ part1_len = encrypted_len - part0_len;
+ part1 = malloc(part1_len);
+ if (part1 == NULL) {
+ printf("malloc failed.\n");
+ goto exit;
+ }
+ memcpy(part1, encrypted + part0_len, part1_len);
+
+ // generate part 0 header
+ header0[0] = (encrypted_len >> 24) & 0xFF;
+ header0[1] = (encrypted_len >> 16) & 0xFF;
+ header0[2] = (encrypted_len >> 8) & 0xFF;
+ header0[3] = encrypted_len & 0xFF;
+
+ // nonce 0 generation: sha3-256(part1)
+ sha3_context nc0;
+ sha3_Init256(&nc0);
+ sha3_Update(&nc0, part1, part1_len);
+ nonce0 = sha3_Finalize(&nc0);
+
+ // generate key 0
+ sha3_context kc0;
+ sha3_Init256(&kc0);
+ sha3_Update(&kc0, nonce0, nonce0_len);
+ sha3_Update(&kc0, shared_secret, shared_secret_len);
+ key0 = sha3_Finalize(&kc0);
+
+ // decrypt part 0 part (params)
+ memcpy(encrypted0, encrypted, part0_len);
+
+ int n0 = norx_aead_decrypt(params, &norx_params_len, header0, header0_len,
+ encrypted0, part0_len, NULL, 0, nonce0, key0,
+ tag0_len_bits);
+
+ if (n0 != 0) {
+ printf("Norx0 decryption failed.\n");
+ goto exit;
+ }
+
+ // get part 1 encryption params
+ rand_len =
+ (params[0] << 24) + (params[1] << 16) + (params[2] << 8) + params[3];
+ tag1_len = params[4];
+ tag1_len_bits = tag1_len * 8;
+
+ if (tag1_len != 4 && tag1_len != 8 && tag1_len != 16 && tag1_len != 24 &&
+ tag1_len != 32) {
+ printf("bad auth tag len.\n");
+ goto exit;
+ }
+ if (rand_len > (encrypted_len - part0_len - tag1_len) ||
+ rand_len < rand_len_min) {
+ printf("size mismatch.\n");
+ goto exit;
+ }
+
+ // allocate and copy rand 1
+ rand = malloc(rand_len);
+ if (rand == NULL) {
+ printf("malloc failed.\n");
+ goto exit;
+ }
+ memcpy(rand, encrypted + part0_len, rand_len);
+
+ // generate nonce1: sha3-256(rand)
+ sha3_context nc1;
+ sha3_Init256(&nc1);
+ sha3_Update(&nc1, params, params_len);
+ sha3_Update(&nc1, rand, rand_len);
+ nonce1 = sha3_Finalize(&nc1);
+
+ // generate key for part1
+ sha3_context kc1;
+ sha3_Init256(&kc1);
+ sha3_Update(&kc1, nonce1, nonce1_len);
+ sha3_Update(&kc1, shared_secret, shared_secret_len);
+ key1 = sha3_Finalize(&kc1);
+
+ // get encrypted message buffer
+ encrypted1 = encrypted + part0_len + rand_len;
+ encrypted1_len = encrypted_len - part0_len - rand_len;
+
+ message_len = encrypted1_len - tag1_len;
+ message = malloc(message_len);
+ if (message == NULL) {
+ printf("malloc failed.\n");
+ goto exit;
+ }
+
+ int n1 = norx_aead_decrypt(message, &norx_message_len, params, params_len,
+ encrypted1, encrypted1_len, NULL, 0, nonce1,
+ key1, tag1_len_bits);
+ if (n1 != 0 || norx_message_len != message_len) {
+ printf("Norx1 decryption failed.\n");
+ goto exit;
+ }
+
+ *data_len_out = message_len;
+
+exit:
+ memset(data_b64t_decoded, 0, data_b64t_decoded_len);
+ memset(encrypted, 0, encrypted_len);
+ memset(part1, 0, part1_len);
+ memset(rand, 0, rand_len);
+ memset(shared_secret, 0, shared_secret_len);
+ memset(encrypted0, 0, part0_len);
+ memset(params, 0, params_len);
+ memset(header0, 0, header0_len);
+
+ memset(&kc0, 0, sizeof(sha3_context));
+ memset(&kc1, 0, sizeof(sha3_context));
+ memset(&nc0, 0, sizeof(sha3_context));
+ memset(&nc1, 0, sizeof(sha3_context));
+
+ free(data_b64t_decoded);
+ if (symmetric_flag)
+ free(encrypted - 64);
+ else
+ free(encrypted);
+ free(part1);
+ free(rand);
+
+ return message;
+ return NULL;
+}
+