diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2025-02-10 00:39:50 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2025-02-10 00:39:50 (GMT) |
commit | d01509d9afe32c0d98d2efba5e75a9df53ac5de9 (patch) | |
tree | f4d742bec88c34ee9d04c42d16dc7ac84bc642b7 /src/core/secstorage.c | |
parent | 71d0b80eca2fd2aed5883e2a6a57cb8c03aa27ff (diff) |
Switch the secure storage to the GObject system.
Diffstat (limited to 'src/core/secstorage.c')
-rw-r--r-- | src/core/secstorage.c | 779 |
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; - -} |