summaryrefslogtreecommitdiff
path: root/src/core/secstorage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/secstorage.c')
-rw-r--r--src/core/secstorage.c779
1 files changed, 0 insertions, 779 deletions
diff --git a/src/core/secstorage.c b/src/core/secstorage.c
deleted file mode 100644
index 7f57b1c..0000000
--- a/src/core/secstorage.c
+++ /dev/null
@@ -1,779 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * secstorage.c - conservation sécurisée d'éléments de configuration
- *
- * Copyright (C) 2025 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * Chrysalide 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.
- *
- * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "secstorage.h"
-
-
-#include <assert.h>
-#include <string.h>
-#include <openssl/evp.h>
-#include <openssl/rand.h>
-
-
-#include "../core/logs.h"
-#include "../glibext/helpers.h"
-
-
-
-/**
- * Les mécanismes de hachage de mot de passe doivent être utilisés avec un sel,
- * et la longueur du sel doit être d’au moins 128 bits.
- *
- * Cette note concerne le hachage de mots de passe et non la dérivation de secrets
- * cependant.
- *
- * Source : https://cyber.gouv.fr/sites/default/files/2021/03/anssi-guide-selection_crypto-1.0.pdf
- */
-
-#define SECRET_STORAGE_SALT_SIZE (256 / 8)
-
-
-/**
- * Nombre d'itérations pour PBKDF2 : en 2023, OWASP recommande 600000 itérations
- * pour PBKDF2-HMAC-SHA256 (et 210000 pour PBKDF2-HMAC-SHA512).
- *
- * Source : https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
- */
-
-#define PBKDF2_HMAC_SHA256_ITERATIONS (2 << 20)
-
-
-/**
- * AES 256 : clef de 256 bits, IV de 128 bits
- */
-
-#define SECRET_STORAGE_KEK_SIZE (256 / 8)
-
-#define SECRET_STORAGE_KEY_SIZE (256 / 8)
-
-#define SECRET_STORAGE_BLOCK_SIZE (128 / 8)
-
-#define SECRET_STORAGE_IV_SIZE SECRET_STORAGE_BLOCK_SIZE
-
-
-/* Conservation des clefs de déchiffrement maîtres par configuration. */
-static GHashTable *__unlocked_keys = NULL;
-
-
-/* Fournit l'espace de configuration réel à manipuler. */
-static GSettings *get_secret_storage_settings(GSettings *);
-
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Initialise le stockage des clefs de déchiffrement en place. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void init_secret_storage(void)
-{
- __unlocked_keys = g_hash_table_new_full(g_direct_hash, g_direct_equal, g_object_unref, free);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Supprime le stockage des clefs de déchiffrement en place. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void exit_secret_storage(void)
-{
- assert(__unlocked_keys != NULL);
-
- g_hash_table_remove_all(__unlocked_keys);
- g_hash_table_unref(__unlocked_keys);
-
- __unlocked_keys = NULL;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* *
-* Description : Fournit l'espace de configuration réel à manipuler. *
-* *
-* Retour : Instance de travail à employer avant libération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GSettings *get_secret_storage_settings(GSettings *settings)
-{
- GSettings *result; /* Instance à retourner */
-
-
- if (settings != NULL)
- {
- ref_object(settings);
- result = settings;
- }
- else
- result = NULL; // TODO
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* *
-* Description : Détermine si une clef de chiffrement protégée est en place. *
-* *
-* Retour : Bilan de l'analyse. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool has_secret_storage_key(GSettings *settings)
-{
- bool result; /* Bilan à retourner */
- GVariant *value; /* Valeur de configuration */
- gsize length; /* Taille d'une valeur donnée */
-
- result = false;
-
- settings = get_secret_storage_settings(settings);
- assert(settings != NULL);
-
- value = g_settings_get_value(settings, "master");
-
- g_variant_get_fixed_array(value, &length, 1);
-
- result = (length > SECRET_STORAGE_IV_SIZE);
-
- g_variant_unref(value);
-
- unref_object(settings);
-
- return result;;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* password = mot de passe principal à appliquer. *
-* *
-* Description : Définit un mot de passe pour protéger une clef maître. *
-* *
-* Retour : Bilan de la mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool set_secret_storage_password(GSettings *settings, const char *passwd)
-{
- bool result; /* Bilan à retourner */
- unsigned char salt[SECRET_STORAGE_SALT_SIZE]; /* Sel pour la dérivation*/
- int ret; /* Bilan à d'un appel */
- GVariant *value; /* Valeur de configuration */
- unsigned char kek[SECRET_STORAGE_KEK_SIZE]; /* Clef de protection */
- unsigned char key[SECRET_STORAGE_KEY_SIZE]; /* Clef maître */
- unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
- EVP_CIPHER_CTX *ctx; /* Contexte pour le chiffrement*/
- unsigned char encrypted[64]; /* Partie chiffrée à conserver */
- unsigned char *iter; /* Tête d'écriture */
- int outlen; /* Taille des données utiles */
-
- result = false;
-
- settings = get_secret_storage_settings(settings);
- assert(settings != NULL);
-
- if (has_secret_storage_key(settings))
- goto exit;
-
- /* Création d'un sel pour la dérivation du mot de passe */
-
- ret = RAND_bytes(salt, sizeof(salt));
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- /**
- * La fonction g_variant_new_fixed_array() retourne un variant
- * avec un décompte de référence flottant.
- */
-
- value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
- salt, SECRET_STORAGE_SALT_SIZE, sizeof(unsigned char));
-
- /**
- * Comme le variant à une référence flottante, la fonction
- * g_settings_set_value() consomme cette référence.
- *
- * Il n'y a donc pas lieu d'appeler g_variant_unref().
- */
-
- g_settings_set_value(settings, "salt", value);
-
- /* Dérivation du mot de passe */
-
- ret = PKCS5_PBKDF2_HMAC(passwd, strlen(passwd),
- salt, SECRET_STORAGE_SALT_SIZE,
- PBKDF2_HMAC_SHA256_ITERATIONS, EVP_sha256(),
- SECRET_STORAGE_KEK_SIZE, kek);
-
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- /* Définition de la clef maître et de son IV de chiffrement */
-
- ret = RAND_bytes(key, sizeof(key));
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- ret = RAND_bytes(iv, sizeof(iv));
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- /* Chiffrement de la clef maître */
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (ctx == NULL)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
-
- ret = EVP_EncryptInit_ex2(ctx, EVP_aes_256_wrap_pad(), kek, iv, NULL);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- memcpy(encrypted, iv, SECRET_STORAGE_IV_SIZE);
-
- iter = encrypted + SECRET_STORAGE_IV_SIZE;
-
- ret = EVP_EncryptUpdate(ctx, iter, &outlen, key, SECRET_STORAGE_KEY_SIZE);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter += outlen;
-
- ret = EVP_EncryptFinal_ex(ctx, iter, &outlen);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter += outlen;
-
- assert((iter - encrypted) < 64);
-
- /* Conservation de la clef protégée */
-
- value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
- encrypted, iter - encrypted, sizeof(unsigned char));
-
- g_settings_set_value(settings, "master", value);
-
- result = true;
-
- exit_with_ctx:
-
- EVP_CIPHER_CTX_free(ctx);
-
- exit:
-
- unref_object(settings);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* *
-* Description : Détermine si la clef de chiffrement maître est vérouillée. *
-* *
-* Retour : Bilan de la détermination. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool is_secret_storage_locked(GSettings *settings)
-{
- bool result; /* Bilan à retourner */
-
- settings = get_secret_storage_settings(settings);
- assert(settings != NULL);
-
- result = (g_hash_table_lookup(__unlocked_keys, settings) == NULL);
-
- unref_object(settings);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* password = mot de passe principal à utiliser. *
-* *
-* Description : Déverrouille la clef de chiffrement maître. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool unlock_secret_storage(GSettings *settings, const char *passwd)
-{
- bool result; /* Bilan à retourner */
- GVariant *salt_value; /* Valeur du sel configuré */
- gsize salt_length; /* Taille du sel conservé */
- gconstpointer salt; /* Données associées #1 */
- unsigned char kek[SECRET_STORAGE_KEK_SIZE]; /* Clef de protection */
- int ret; /* Bilan à d'un appel */
- GVariant *enc_value; /* Paramètres de chiffrement */
- gsize enc_length; /* Taille de ces paramètrs */
- gconstpointer encrypted; /* Données associées #2 */
- EVP_CIPHER_CTX *ctx; /* Contexte de déchiffrement */
- unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
- unsigned char key[SECRET_STORAGE_KEY_SIZE]; /* Clef maître */
- unsigned char *iter; /* Tête d'écriture */
- int outlen; /* Taille des données utiles */
- void *unlocked; /* Zone de conservation */
-#ifndef NDEBUG
- gboolean new; /* Validation de la création */
-#endif
-
- result = false;
-
- settings = get_secret_storage_settings(settings);
- assert(settings != NULL);
-
- if (!is_secret_storage_locked(settings))
- {
- result = true;
- goto quick_exit;
- }
-
- /* Récupération du sel mis en place */
-
- salt_value = g_settings_get_value(settings, "salt");
-
- salt = g_variant_get_fixed_array(salt_value, &salt_length, sizeof(bin_t));
-
- if (salt_length != SECRET_STORAGE_SALT_SIZE)
- goto exit_with_salt;
-
- /* Dérivation du mot de passe */
-
- ret = PKCS5_PBKDF2_HMAC(passwd, strlen(passwd),
- salt, SECRET_STORAGE_SALT_SIZE,
- PBKDF2_HMAC_SHA256_ITERATIONS, EVP_sha256(),
- SECRET_STORAGE_KEK_SIZE, kek);
-
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_salt;
- }
-
- /* Récupération des paramètres chiffrés */
-
- enc_value = g_settings_get_value(settings, "master");
-
- encrypted = g_variant_get_fixed_array(enc_value, &enc_length, sizeof(bin_t));
-
- if (enc_length <= SECRET_STORAGE_IV_SIZE)
- goto exit_with_enc;
-
- /* Déhiffrement de la clef maître */
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (ctx == NULL)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_enc;
- }
-
- EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
-
- memcpy(iv, encrypted, SECRET_STORAGE_IV_SIZE);
-
- ret = EVP_DecryptInit_ex2(ctx, EVP_aes_256_wrap_pad(), kek, iv, NULL);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter = key;
-
- ret = EVP_DecryptUpdate(ctx, iter, &outlen,
- ((unsigned char *)encrypted) + SECRET_STORAGE_IV_SIZE,
- enc_length - SECRET_STORAGE_IV_SIZE);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter += outlen;
-
- ret = EVP_DecryptFinal_ex(ctx, iter, &outlen);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- assert((iter - key) == SECRET_STORAGE_KEY_SIZE);
-
- /* Stockage de la clef maître en mémoire */
-
- ref_object(settings);
-
- unlocked = malloc(SECRET_STORAGE_KEY_SIZE);
- memcpy(unlocked, key, SECRET_STORAGE_KEY_SIZE);
-
-#ifndef NDEBUG
- new = g_hash_table_replace(__unlocked_keys, settings, unlocked);
- assert(new);
-#else
- g_hash_table_replace(__unlocked_keys, settings, unlocked);
-#endif
-
- result = true;
-
- /* Sortie */
-
- exit_with_ctx:
-
- EVP_CIPHER_CTX_free(ctx);
-
- exit_with_enc:
-
- g_variant_unref(enc_value);
-
- exit_with_salt:
-
- g_variant_unref(salt_value);
-
- quick_exit:
-
- unref_object(settings);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* *
-* Description : Verrouille la clef de chiffrement maître. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void lock_secret_storage(GSettings *settings)
-{
- settings = get_secret_storage_settings(settings);
- assert(settings != NULL);
-
- g_hash_table_remove(__unlocked_keys, settings);
-
- unref_object(settings);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* in = séquence d'octets à traiter. *
-* out = séquence d'octets résultantes. [OUT] *
-* *
-* Description : Chiffre des données avec la clef de chiffrement maître. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool encrypt_secret_storage_data(GSettings *settings, const sized_binary_t *in, sized_binary_t *out)
-{
- bool result; /* Bilan à retourner */
- gpointer key; /* Clef de chiffrement */
- unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
- int ret; /* Bilan à d'un appel */
- EVP_CIPHER_CTX *ctx; /* Contexte pour le chiffrement*/
- size_t needed; /* Taille de la sortie */
- unsigned char *iter; /* Tête d'écriture */
- int outlen; /* Taille des données utiles */
-
- result = false;
-
- settings = get_secret_storage_settings(settings);
- assert(settings != NULL);
-
- if (is_secret_storage_locked(settings))
- goto quick_exit;
-
- /* Récupération de la clef maître et d'un IV de chiffrement */
-
- key = g_hash_table_lookup(__unlocked_keys, settings);
-
- ret = RAND_bytes(iv, sizeof(iv));
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- /* Préparation de la zone de réception */
-
- needed = SECRET_STORAGE_IV_SIZE + ((in->size / SECRET_STORAGE_BLOCK_SIZE) + 1) * SECRET_STORAGE_BLOCK_SIZE;
-
- setup_sized_binary(out, needed);
-
- /* Chiffrement des données */
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (ctx == NULL)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- ret = EVP_EncryptInit_ex2(ctx, EVP_aes_256_cbc(), key, iv, NULL);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- memcpy(out->data, iv, SECRET_STORAGE_IV_SIZE);
-
- iter = out->bin_data + SECRET_STORAGE_IV_SIZE;
-
- ret = EVP_EncryptUpdate(ctx, iter, &outlen, in->bin_data, in->size);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter += outlen;
-
- ret = EVP_EncryptFinal_ex(ctx, iter, &outlen);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter += outlen;
-
- assert((iter - out->bin_data) == out->size);
-
- result = true;
-
- /* Sortie */
-
- exit_with_ctx:
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!result)
- exit_sized_binary(out);
-
- exit:
- quick_exit:
-
- unref_object(settings);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : settings = éventuel espace de configuration à manipuler. *
-* in = séquence d'octets à traiter. *
-* out = séquence d'octets résultantes. [OUT] *
-* *
-* Description : Déchiffre des données avec la clef de chiffrement maître. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool decrypt_secret_storage_data(GSettings *settings, const sized_binary_t *in, sized_binary_t *out)
-{
- bool result; /* Bilan à retourner */
- gpointer key; /* Clef de chiffrement */
- unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé */
- int ret; /* Bilan à d'un appel */
- EVP_CIPHER_CTX *ctx; /* Contexte pour le chiffrement*/
- size_t needed; /* Taille de la sortie */
- unsigned char *iter; /* Tête d'écriture */
- int outlen; /* Taille des données utiles */
-
- result = false;
-
- settings = get_secret_storage_settings(settings);
- assert(settings != NULL);
-
- if (is_secret_storage_locked(settings))
- goto quick_exit;
-
- /* Récupération de la clef maître et d'un IV de chiffrement */
-
- key = g_hash_table_lookup(__unlocked_keys, settings);
-
- if (in->size < SECRET_STORAGE_IV_SIZE)
- goto exit;
-
- memcpy(iv, in->data, SECRET_STORAGE_IV_SIZE);
-
- /* Préparation de la zone de réception */
-
- needed = in->size - SECRET_STORAGE_IV_SIZE;
-
- setup_sized_binary(out, needed);
-
- /* Chiffrement des données */
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (ctx == NULL)
- {
- LOG_ERROR_OPENSSL;
- goto exit;
- }
-
- ret = EVP_DecryptInit_ex2(ctx, EVP_aes_256_cbc(), key, iv, NULL);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter = out->bin_data;
-
- ret = EVP_DecryptUpdate(ctx, iter, &outlen,
- in->bin_data + SECRET_STORAGE_IV_SIZE, in->size - SECRET_STORAGE_IV_SIZE);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter += outlen;
-
- ret = EVP_DecryptFinal_ex(ctx, iter, &outlen);
- if (ret != 1)
- {
- LOG_ERROR_OPENSSL;
- goto exit_with_ctx;
- }
-
- iter += outlen;
-
- assert((iter - out->bin_data) <= out->size);
-
- resize_sized_binary(out, iter - out->bin_data);
-
- result = true;
-
- /* Sortie */
-
- exit_with_ctx:
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!result)
- exit_sized_binary(out);
-
- exit:
- quick_exit:
-
- unref_object(settings);
-
- return result;
-
-}