93 votes

Techniques pour obscurcir les chaînes sensibles en C++

Je dois stocker des informations sensibles (une clé de chiffrement symétrique que je veux garder privée) dans mon application C++. L'approche simple est la suivante :

std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

Cependant, exécuter l'application via le processus strings (ou tout autre processus qui extrait des chaînes à partir d'une application binaire) révélera la chaîne ci-dessus.

Quelles techniques devraient être utilisées pour obscurcir de telles données sensibles ?

Modifier :

D'accord, donc pratiquement tous ont dit "votre exécutable peut être inversé" - bien sûr ! C'est une de mes irritations, alors je vais me plaindre un peu ici :

Pourquoi est-ce que 99 % (OK, peut-être j'exagère un peu) de toutes les questions liées à la sécurité sur ce site obtiennent en réponse un torrent de "il n'est pas possible de créer un programme parfaitement sécurisé" - ce n'est pas une réponse utile ! La sécurité est une échelle mobile entre une parfaite utilisabilité et aucune sécurité d'un côté, et une sécurité parfaite mais aucune utilisabilité de l'autre.

Le point est que vous choisissez votre position sur cette échelle en fonction de ce que vous essayez de faire et de l'environnement dans lequel votre logiciel va s'exécuter. Je ne suis pas en train d'écrire une application pour une installation militaire, je suis en train d'écrire une application pour un PC domestique. J'ai besoin de chiffrer des données à travers un réseau non fiable avec une clé de chiffrement pré-connaître. Dans ces cas, "la sécurité par l'obscurité" est probablement suffisante ! Bien sûr, quelqu'un avec suffisamment de temps, d'énergie et de compétences pourrait inverser l'ingénierie du binaire et trouver le mot de passe, mais devinez quoi ? Ça m'est égal :

Le temps qu'il me faut pour mettre en place un système ultra sécurisé est plus coûteux que la perte de ventes due aux versions crackées (bien que je ne vende pas réellement cela, mais vous comprenez mon point). Cette tendance à vouloir faire les choses de la meilleure façon possible dans le ciel bleu parmi les nouveaux programmeurs est au mieux insensée.

Merci d'avoir pris le temps de répondre à cette question - elles ont été très utiles. Malheureusement, je ne peux accepter qu'une seule réponse, mais j'ai voté pour toutes les réponses utiles.

2 votes

Peut-être si vous décrivez ce que vous essayez d'accomplir avec la clé de chiffrement, nous pouvons vous offrir des conseils sur la façon d'éviter d'avoir besoin de le faire.

3 votes

4 votes

@Kirill : il est difficile d'appeler cette question exactement la même que celle que vous mentionnez. En effet, l'idée est la même. La question ne l'est pas.

44voto

csl Points 5401

Essentiellement, n'importe qui ayant accès à votre programme et un débogueur peut et va trouver la clé dans l'application s'il le souhaite.

Mais, si vous voulez simplement vous assurer que la clé n'apparait pas en exécutant strings sur votre binaire, vous pourriez par exemple vous assurer que la clé ne se situe pas dans la plage imprimable.

Obscurcir la clé avec XOR

Par exemple, vous pourriez utiliser XOR pour diviser la clé en deux tableaux de bytes:

clé = clé1 XOR clé2

Si vous créez clé1 avec la même longueur de byte que clé vous pouvez utiliser des valeurs de bytes (complètement) aléatoires et ensuite calculer clé2:

clé1[n] = nombre_aléatoire_de_qualité_crypto(0..255)
clé2[n] = clé[n] XOR clé1[n]

Vous pouvez faire ceci dans votre environnement de construction, et ensuite ne stocker que clé1 et clé2 dans votre application.

Protéger votre binaire

Une autre approche est d'utiliser un outil pour protéger votre binaire. Par exemple, il existe plusieurs outils de sécurité qui peuvent s'assurer que votre binaire est obfusqué et démarre une machine virtuelle sur laquelle il s'exécute. Cela rend le débogage plus difficile, et c'est aussi la manière conventionnelle dont de nombreuses applications sécurisées de qualité commerciale (ainsi que des logiciels malveillants) sont protégées.

Un des outils principaux est Themida, qui fait un excellent travail pour protéger vos binaires. Il est souvent utilisé par des programmes bien connus, comme Spotify, pour se protéger contre l'ingénierie inverse. Il possède des fonctionnalités pour empêcher le débogage dans des programmes tels que OllyDbg et Ida Pro.

Il existe également une liste plus grande, peut-être un peu obsolète, de outils pour protéger votre binaire.
Certains d'entre eux sont gratuits.

Correspondance des mots de passe

Quelqu'un a discuté ici du hachage du mot de passe+sel.

Si vous devez stocker la clé pour la comparer à un mot de passe soumis par l'utilisateur, vous devriez utiliser une fonction de hachage unidirectionnelle, de préférence en combinant le nom d'utilisateur, le mot de passe et un sel. Le problème avec cela, cependant, est que votre application doit connaître le sel pour pouvoir effectuer le hachage unidirectionnel et comparer les hashings résultants. Par conséquent, vous devez toujours stocker le sel quelque part dans votre application. Mais, comme le souligne @Edward dans les commentaires ci-dessous, cela protégera efficacement contre une attaque par dictionnaire utilisant, par exemple, des tables arc-en-ciel.

Enfin, vous pouvez utiliser une combinaison de toutes les techniques ci-dessus.

0 votes

Si c'est un mot de passe que l'utilisateur doit entrer, stockez le hachage+sel du mot de passe. Voir la réponse ci-dessous.

1 votes

@hapalibashi: Comment stockez-vous le sel de manière sécurisée dans votre application? Je ne pense pas que l'OP ait besoin d'un système de correspondance de mots de passe à sens unique, juste d'une manière généralisée de stocker des clés statiques.

2 votes

J'ai trouvé que lors de l'examen de programmes désassemblés, il n'y a généralement pas beaucoup de XOR, donc si vous espérez utiliser XOR pour obscurcir quelque chose, gardez à l'esprit qu'ils attirent l'attention sur eux-mêmes.

9voto

Chris Jefferson Points 1989

Tout d'abord, réalisez qu'il n'y a rien que vous puissiez faire pour arrêter un hacker suffisamment déterminé, et il y en a beaucoup. La protection de chaque jeu et console est finalement piratée, donc ceci n'est qu'une solution temporaire.

Il y a 4 choses que vous pouvez faire pour augmenter vos chances de rester caché pendant un certain temps.

1) Cachez les éléments de la chaîne d'une certaine manière -- quelque chose d'évident comme xor (l'opérateur ^) de la chaîne avec une autre chaîne sera suffisant pour rendre la chaîne impossible à rechercher.

2) Divisez la chaîne en morceaux -- Divisez votre chaîne et placez des morceaux dans des méthodes nommées de manière étrange dans des modules étranges. Ne facilitez pas la recherche et la découverte de la méthode contenant la chaîne. Bien sûr, une méthode devra appeler tous ces morceaux, mais cela rend quand même les choses un peu plus difficiles.

3) Ne construisez jamais la chaîne en mémoire -- la plupart des hackers utilisent des outils qui leur permettent de voir la chaîne en mémoire après l'avoir encodée. Évitez cela si possible. Si, par exemple, vous envoyez la clé à un serveur, envoyez-la caractère par caractère, de sorte que la chaîne entière ne soit jamais stockée. Bien sûr, si vous l'utilisez pour quelque chose comme le codage RSA, alors c'est plus compliqué.

4) Faites un algorithme ad-hoc -- en plus de tout cela, ajoutez une touche unique ou deux. Peut-être ajoutez simplement 1 à tout ce que vous produisez, ou chiffrez deux fois, ou ajoutez un sucre. Cela rend juste les choses un peu plus difficiles pour le hacker qui sait déjà quoi chercher quand quelqu'un utilise, par exemple, le hachage md5 vanille ou le chiffrement RSA.

Au-dessus de tout, assurez-vous que ce n'est pas trop important quand (et cela arrivera lorsque votre application deviendra suffisamment populaire) votre clé est découverte !

5voto

Paul Sasik Points 37766

Une stratégie que j'ai déjà utilisée dans le passé consiste à créer un tableau de caractères apparemment aléatoires. Vous insérez initialement, puis localisez vos caractères particuliers avec un processus algébrique où chaque étape de 0 à N donnera un nombre < taille du tableau qui contient le caractère suivant dans votre chaîne obfusquée. (Cette réponse est maintenant obfusquée!)

Exemple:

Étant donné un tableau de caractères (les chiffres et les tirets sont uniquement à titre de référence)

0123456789
----------
ALFHNFELKD
LKFKFLEHGT
FLKRKLFRFK
FJFJJFJ!JL

Et une équation dont les six premiers résultats sont : 3, 6, 7, 10, 21, 47

Donnerait le mot "HELLO!" à partir du tableau ci-dessus.

0 votes

Bonne idée - je suppose que vous pourriez encore l'améliorer en utilisant des caractères non imprimables dans le tableau...

4voto

Frerich Raabe Points 23711

Bien sûr, stocker des données privées dans un logiciel qui est distribué à l'utilisateur comporte toujours un risque. Tout ingénieur suffisamment éduqué (et dévoué) pourrait décrypter les données.

Ceci étant dit, vous pouvez souvent rendre les choses suffisamment sécurisées en augmentant la barrière que les gens doivent franchir pour révéler vos données privées. C'est généralement un bon compromis.

Dans votre cas, vous pourriez encombrer vos chaînes de caractères avec des données non imprimables, puis décoder celles-ci au moment de l'exécution à l'aide d'une fonction d'aide simple, comme ceci :

void unscramble( char *s )
{
    for ( char *str = s + 1; *str != 0; str += 2 ) {
        *s++ = *str;
    }
    *s = '\0';
}

void f()
{
    char privateStr[] = "\001H\002e\003l\004l\005o";
    unscramble( privateStr ); // privateStr est 'Hello' maintenant.

    string s = privateStr;
    // ...
}

2voto

Michael Foukarakis Points 14892

Voici un moyen de contourner les chaines de caractères:

#define passphrase(t) \
{ \
    memset(t, 0, sizeof(t)); \
    t[0] = 'm'; \
    t[1] = 'y'; \
    t[2] = 'p'; \
    t[3] = 'a'; \
    t[4] = 's'; \
    t[5] = 's'; \
    t[6] = 0; \
}

D'après les précisions de votre question, je suppose que vous ne souhaitez pas aller plus loin que cela. Si vous le voulez, vous pouvez construire sur cette base :

  • Jouez un peu avec les affectations de valeurs. Un simple XOR, peut-être. Si vous en avez envie, utilisez le code d'assemblage comme clé. :P
  • Utilisez des chiffrements par bloc, même si c'est quelque chose que vous inventez en une seule soirée. En fait, utiliser quelque chose que vous avez inventé vous-même est probablement une meilleure idée que d'utiliser des algorithmes bien connus - cela déroute les gens.
  • Devenez fou.

MODIFICATION : Voici une autre idée : si votre application a besoin d'une clé pour crypter des données, que diriez-vous d'en générer une à l'exécution, comme cela se fait avec RSA, par exemple. Cela ne s'affichera pas lors de l'analyse statique de votre exécutable, et vous pouvez utiliser n'importe quelles techniques pour la masquer à l'exécution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X