Frage

Ich brauche sensible Informationen zu speichern (ein symmetrisches Verschlüsselungsschlüssel, die ich privat halten will) in meiner C ++ Anwendung. Der einfache Ansatz ist, dies zu tun:

std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

Um jedoch die Anwendung durch den strings Prozess läuft (oder andere, die Strings aus einer binären App extrahiert) wird die obige Zeichenfolge offenbart.

Welche Techniken sollten solche sensiblen Daten zu verschleiern verwendet werden?

Edit:

OK, so ziemlich alle von Ihnen gesagt hat "Ihre ausführbare Datei kann Reverse Engineering werden" - natürlich! Dies ist ein Haustier ärgern von mir, also werde ich ein bisschen schimpfen hier:

Warum ist es, dass 99% (OK, vielleicht übertreibe ich ein wenig) alle sicherheitsrelevanten Fragen auf dieser Seite ist mit einem Schwall von beantwortet: „Es gibt keine Möglichkeit, ein vollkommen sicheres Programm zu schaffen“ - das ist keine hilfreiche Antwort! Sicherheit ist eine gleitende Skala zwischen perfekter Bedienbarkeit und Sicherheit nicht an einem Ende, und perfekte Sicherheit, aber keine Benutzerfreundlichkeit auf dem anderen Seite.

Der Punkt ist, dass Sie Ihre Position auf dieser gleitenden Skala wählen, je nachdem, was Sie versuchten, in dem zu tun und die Umwelt Ihre Software ausgeführt wird. Ich bin nicht eine App für eine militärische Einrichtung zu schreiben, ich bin eine App für einen Heim-PC zu schreiben . Ich muß die Daten über ein nicht vertrauenswürdiges Netzwerk mit einem vorher bekannten Verschlüsselungsschlüssel verschlüsseln. In diesen Fällen „Sicherheit durch Unklarheit“ ist wahrscheinlich gut genug! Sicher, jemand mit genug Zeit, Energie und Geschick konnte die binäre Reverse-Engineering und das Passwort finden, aber was denken Sie? Mir ist es egal:

Die Zeit, die ich ein erstklassiges sicheres System zu implementieren braucht ist teurer als der Umsatzverlust aufgrund der gerissenen Versionen (nicht, dass ich dies tatsächlich verkauft werde, aber Sie bekommen meine Nummer). Dieser blau-Himmel „läßt es tun, um den absoluten besten Weg möglich“ Trend in der Programmierung unter neuen Programmierern ist töricht, gelinde gesagt.

Vielen Dank, dass Sie sich die Zeit nehmen, diese Frage zu beantworten - sie waren sehr hilfreich. Leider kann ich nur eine Antwort akzeptieren, aber ich habe bis gestimmt alle nützlichen Antworten.

War es hilfreich?

Lösung

Im Grunde jeder, der Zugang zu Ihrem Programm und einem Debugger können und wird den Schlüssel in der Anwendung finden, wenn sie wollen.

Aber, wenn Sie nur sicherstellen möchten, ist der Schlüssel nicht angezeigt wird, wenn strings auf dem binären läuft, könnten Sie zum Beispiel sicherstellen, dass der Schlüssel nicht im druckbaren Bereich.

Obscuring Schlüssel mit XOR

Zum Beispiel könnten Sie XOR verwenden den Schlüssel in zwei Byte-Arrays aufgeteilt:

key = key1 XOR key2

Wenn Sie Schlüssel1 mit der gleichen Byte-Länge als key erstellen Sie (vollständig) zufälligen Byte-Werte verwenden können und dann key2 berechnen:

key1[n] = crypto_grade_random_number(0..255)
key2[n] = key[n] XOR key1[n]

Sie können dies tun, in Ihrer Build-Umgebung, und auch nur dann speichern key1and key2 in Ihrer Anwendung.

Der Schutz Ihrer binären

Ein weiterer Ansatz ist es, ein Werkzeug zu benutzen, um Ihre binären zu schützen. Zum Beispiel gibt es mehrere Sicherheits-Tools, die sicherstellen können, Ihre binäre verschleiert wird und startet eine virtuelle Maschine, die es läuft. Dies macht es schwer (er) zu debuggen, und ist auch die Art und Weise convential viele handelsübliche Qualität sichere Anwendungen (auch leider Malware) geschützt ist.

Eines der führenden Tools ist Themida , was tut einen tollen Job Ihre Binärdateien zu schützen. Es wird oft von bekannten Programmen wie Spotify, zum Schutz vor Reverse Engineering eingesetzt. Es verfügt über Funktionen Debugging in Programmen wie OllyDbg und Ida Pro zu verhindern.

Es gibt auch eine größere Liste, vielleicht etwas veraltet, von Tool zum Schutz Ihre binären .
Einige von ihnen sind kostenlos.

Passwort passende

Jemand hier diskutiert Passwort Hashing + Salz.

Wenn Sie den Schlüssel speichern, müssen sie gegen eine Art von Benutzer-Passwort eingereicht übereinstimmen, sollten Sie eine Einweg-Hash-Funktion verwenden, vorzugsweise von Benutzernamen kombiniert, Passwort und ein Salz. Das Problem dabei ist allerdings, dass Ihre Anwendung des Salz der Lage sein, zu wissen, hat die Einweg- und vergleichen das resultierende Hashes zu tun. So also müssen Sie noch das Salz irgendwo in Ihrer Anwendung zu speichern. Aber, wie @Edward in den Kommentaren unten weist darauf hin, diese effektiv schützen vor einem Wörterbuchangriff verwenden, beispiel, Rainbow-Tabellen.

Schließlich können Sie eine Kombination aus allen oben genannten Techniken verwenden.

Andere Tipps

Zunächst einmal erkennen, dass es nichts, was Sie, dass ein ausreichend entschlossenen Hacker tun können, wird aufhören, und es gibt viele Menschen in Ihrer Umgebung. Der Schutz bei jedem Spiel und Konsole um schließlich geknackt, so ist dies nur eine temporäre Lösung.

Es gibt 4 Dinge, die Sie tun werden Sie Chancen für eine Weile versteckt erhöhen bleiben.

1) ausblenden, die Elemente der Zeichenfolge in irgendeiner Weise - etwas offensichtlich wie XOR-Verknüpfung (der Operator ^) die Zeichenfolge mit einer anderen Zeichenfolge gut genug sein wird, um die Zeichenfolge unmöglich zu machen, suchen

.

2) Teilen Sie die Zeichenfolge in Stücke - teilen Sie Ihre String-und Pop-Bits davon in ungewöhnlichem Namen Methoden in fremden Module. Sie nicht, es in machen es einfach, die Methode mit dem String zu durchsuchen und finden. Natürlich diese Bits einige Methoden, um alle nennen, aber es macht immer noch es etwas schwieriger.

3) Nicht immer die Zeichenfolge im Speicher bauen - die meisten Hacker-Tools verwenden, die sie sehen die Zeichenfolge im Speicher lassen, nachdem Sie es codiert haben. Wenn möglich, vermeiden Sie dies. Wenn Sie zum Beispiel den Schlüssel senden an einen Server aus, schicken Sie es Zeichen für Zeichen, so dass die ganze Zeichenfolge nie herum ist. Natürlich, wenn Sie es von so etwas wie RSA-Codierung verwenden, dann ist dies schwieriger.

4) Führen Sie eine Ad-hoc-Algorithmus - zu all dies, fügen Sie eine einzigartige Wendung oder zwei. Vielleicht fügen Sie einfach 1 bis alles, was Sie produzieren, oder zweimal jede Verschlüsselung tun, oder einen Zucker hinzufügen. Dies macht es nur ein wenig schwieriger für den Hacker, der schon weiß, was zu suchen, wenn jemand verwendet, beispielsweise Vanille md5 Hashing oder RSA-Verschlüsselung.

Vor allem, stellen Sie sicher, dass es nicht so wichtig ist, wenn (und es wird, wenn, wenn Sie Anwendung populär wird genug) Ihr Schlüssel entdeckt wird!

Eine Strategie i in der Vergangenheit verwendet habe, ist eine Reihe von scheinbar zufälligen Zeichen zu erstellen. Sie fügen zunächst, und dann bestimmte Zeichen mit einem algebraischen Verfahren finden, wo jeder Schritt von 0 bis N eine Zahl

Beispiel:

ein Feld von Zeichen Given (Zahlen und Bindestriche dienen lediglich)

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

und eine Gleichung, deren ersten sechs Ergebnisse sind: 3, 6, 7, 10, 21, 47

Möchten Sie das Wort ergeben „HALLO!“ aus dem Feld oben.

ich mit @Checkers, die ausführbare Datei zustimmen werden Reverse-Engineering.

Ein bisschen besserer Weg ist es dynamisch zu erstellen, zum Beispiel:

std::string myKey = part1() + part2() + ... + partN();

Ich habe eine einfache Verschlüsselungs-Tool für Strings erstellt, kann er automatisch verschlüsselte Zeichenfolgen generieren und hat ein paar zusätzliche Optionen, dass ein paar Beispiele zu tun:

String als globale Variable:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xCF, 0x34, 0xF8, 0x5F, 0x5C, 0x3D, 0x22, 0x13, 0xB4, 0xF3, 0x63, 0x7E, 0x6B, 0x34, 0x01, 0xB7, 0xDB, 0x89, 0x9A, 0xB5, 0x1B, 0x22, 0xD4, 0x29, 0xE6, 0x7C, 0x43, 0x0B, 0x27, 0x00, 0x91, 0x5F, 0x14, 0x39, 0xED, 0x74, 0x7D, 0x4B, 0x22, 0x04, 0x48, 0x49, 0xF1, 0x88, 0xBE, 0x29, 0x1F, 0x27 };

myKey[30] -= 0x18;
myKey[39] -= 0x8E;
myKey[3] += 0x16;
myKey[1] += 0x45;
myKey[0] ^= 0xA2;
myKey[24] += 0x8C;
myKey[44] ^= 0xDB;
myKey[15] ^= 0xC5;
myKey[7] += 0x60;
myKey[27] ^= 0x63;
myKey[37] += 0x23;
myKey[2] ^= 0x8B;
myKey[25] ^= 0x18;
myKey[12] ^= 0x18;
myKey[14] ^= 0x62;
myKey[11] ^= 0x0C;
myKey[13] += 0x31;
myKey[6] -= 0xB0;
myKey[22] ^= 0xA3;
myKey[43] += 0xED;
myKey[29] -= 0x8C;
myKey[38] ^= 0x47;
myKey[19] -= 0x54;
myKey[33] -= 0xC2;
myKey[40] += 0x1D;
myKey[20] -= 0xA8;
myKey[34] ^= 0x84;
myKey[8] += 0xC1;
myKey[28] -= 0xC6;
myKey[18] -= 0x2A;
myKey[17] -= 0x15;
myKey[4] ^= 0x2C;
myKey[9] -= 0x83;
myKey[26] += 0x31;
myKey[10] ^= 0x06;
myKey[16] += 0x8A;
myKey[42] += 0x76;
myKey[5] ^= 0x58;
myKey[23] ^= 0x46;
myKey[32] += 0x61;
myKey[41] ^= 0x3B;
myKey[31] ^= 0x30;
myKey[46] ^= 0x6C;
myKey[35] -= 0x08;
myKey[36] ^= 0x11;
myKey[45] -= 0xB6;
myKey[21] += 0x51;
myKey[47] += 0xD9;

Als Unicode-String mit Entschlüsselungsschleife:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
wchar_t myKey[48];

myKey[21] = 0x00A6;
myKey[10] = 0x00B0;
myKey[29] = 0x00A1;
myKey[22] = 0x00A2;
myKey[19] = 0x00B4;
myKey[33] = 0x00A2;
myKey[0] = 0x00B8;
myKey[32] = 0x00A0;
myKey[16] = 0x00B0;
myKey[40] = 0x00B0;
myKey[4] = 0x00A5;
myKey[26] = 0x00A1;
myKey[18] = 0x00A5;
myKey[17] = 0x00A1;
myKey[8] = 0x00A0;
myKey[36] = 0x00B9;
myKey[34] = 0x00BC;
myKey[44] = 0x00B0;
myKey[30] = 0x00AC;
myKey[23] = 0x00BA;
myKey[35] = 0x00B9;
myKey[25] = 0x00B1;
myKey[6] = 0x00A7;
myKey[27] = 0x00BD;
myKey[45] = 0x00A6;
myKey[3] = 0x00A0;
myKey[28] = 0x00B4;
myKey[14] = 0x00B6;
myKey[7] = 0x00A6;
myKey[11] = 0x00A7;
myKey[13] = 0x00B0;
myKey[39] = 0x00A3;
myKey[9] = 0x00A5;
myKey[2] = 0x00A6;
myKey[24] = 0x00A7;
myKey[46] = 0x00A6;
myKey[43] = 0x00A0;
myKey[37] = 0x00BB;
myKey[41] = 0x00A7;
myKey[15] = 0x00A7;
myKey[31] = 0x00BA;
myKey[1] = 0x00AC;
myKey[47] = 0x00D5;
myKey[20] = 0x00A6;
myKey[5] = 0x00B0;
myKey[38] = 0x00B0;
myKey[42] = 0x00B2;
myKey[12] = 0x00A6;

for (unsigned int fngdouk = 0; fngdouk < 48; fngdouk++) myKey[fngdouk] ^= 0x00D5;

String als globale Variable:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xAF, 0xBB, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xA7, 0xA5, 0xB4, 0xA7, 0xB6, 0xB2, 0xA3, 0xB5, 0xB5, 0xB9, 0xB1, 0xB4, 0xA6, 0xB6, 0xAA, 0xA3, 0xB6, 0xBB, 0xB1, 0xB7, 0xB9, 0xAB, 0xAE, 0xAE, 0xB0, 0xA7, 0xB8, 0xA7, 0xB4, 0xA9, 0xB7, 0xA7, 0xB5, 0xB5, 0x42 };

for (unsigned int dzxykdo = 0; dzxykdo < 48; dzxykdo++) myKey[dzxykdo] -= 0x42;

Natürlich Speicherung private Daten in Software, die den Benutzer ausgeliefert wird, ist immer ein Risiko. Jede hinreichend ausgebildete (und dedicated) Ingenieur konnte die Daten Reverse Engineering.

Davon abgesehen, kann man oft Dinge sicher genug, um durch die Barriere erhöhen, die Menschen überwinden müssen, um Ihre privaten Daten zu offenbaren. Das ist in der Regel ein guter Kompromiss.

In Ihrem Fall Sie Ihre Strings mit nicht druckbaren Daten Unordnung könnten, und dann, dass, wie dies mit einer einfachen Hilfsfunktion zur Laufzeit dekodieren:

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 is 'Hello' now.

    string s = privateStr;
    // ...
}

Etwas davon abhängig, was Sie versuchen, zum Schutz der als joshperry verweist. Aus Erfahrung würde ich sagen, dass wenn es Teil eines Genehmigungssystems ist Ihre Software zu schützen, dann nicht die Mühe. Sie werden eventially es Reverse Engineering. Verwenden Sie einfach einen einfachen Chiffre wie ROT-13 aus einfachen Angriffen zu schützen (Linie Strings über sie läuft). Wenn es sich um Benutzer sensible Daten zu sichern, würde ich in Frage zu stellen, ob diese Daten mit einem privaten Schlüssel zu schützen lokal gespeichert ein kluger Schritt ist. Auch hier darauf ankommt, was Sie zu schützen versuchen.

EDIT:. Wenn Sie gehen, um es dann eine Kombination von Techniken zu tun, die Chris als rot13 weit besser sein wird betont

Wie bereits erwähnt wurde, gibt es keine Möglichkeit, Ihren String völlig zu schützen. Aber es gibt Möglichkeiten, es wis eine angemessene Sicherheit zu schützen.

Als ich dies zu tun hatte, habe ich einige unschuldig aussehende Zeichenfolge in den Code (ein Copyright-Hinweis, zum Beispiel, oder einige gefälschte Benutzerführung oder irgendetwas anderes, das nicht von jemandem Festsetzung nicht verwandten Code geändert wird) setzen, verschlüsselt dass sich als Schlüssel, gehasht, dass (etwas Salz hinzufügen), und verwendet das Ergebnis als Schlüssel zu verschlüsseln, was ich wollte eigentlich verschlüsseln.

Natürlich könnte gehackt werden, aber es hat einen entschlossenen Hacker nehmen, dies zu tun.

Stattdessen private Schlüssel in der ausführbaren Datei zu speichern, sollten Sie es von dem Benutzer verlangen, und speichern Sie es mit Hilfe eines externen Passwort-Manager , etwas ähnlich wie Mac OS X Schlüsselbund.

Wenn Sie auf Windows-Benutzer DPAPI, http://msdn.microsoft .com / en-us / library / ms995355.aspx

Als frühere Post sagte, wenn Sie auf dem Mac sind die Schlüsselanhänger verwenden.

Im Grunde all diese netten Ideen, wie Sie Ihren privaten Schlüssel in Ihrem binären speichern sind ausreichend schlecht aus Sicht der Sicherheit, die Sie nicht, sie tun sollten. Wer mit dem privaten Schlüssel bekommen ist eine große Sache, tun Sie es nicht in Ihrem Programm hält. Je nachdem, wie Ihre Anwendung importieren ist, dass Sie Ihre privaten Schlüssel auf einer Smartcard zu halten, auf einem entfernten Computer Code Gespräche oder Sie können tun, was die meisten Menschen tun und halten sie in einem sehr sicheren Ort auf dem lokalen Computer (den „Schlüssel Speicher“, die wie eine Art seltsam sichere Registrierung ist), die von Berechtigungen und die ganzen Stärke Ihres O geschützt ist.

Dies ist ein Problem gelöst und die Antwort ist nicht den Schlüssel in Ihrem Programm zu halten:)

Versuchen Sie dieser . Der Quellcode wird erläutert, wie im Fluge aller Strings in einem bestimmten Visual Studio c ++ Projekt verschlüsseln und zu entschlüsseln.

Eine Methode, die ich vor kurzem versucht, lautet:

  1. Nehmen Sie Hash (SHA256) der privaten Daten und es im Code als part1 bevölkern
  2. Nehmen Sie XOR von privaten Daten und deren Hash-und füllen Sie es in Code als part2
  3. Daten Bestücken: Lagern Sie das nicht als char str [], aber bevölkern auf Laufzeit mit Zuordnung Anweisungen
  4. (wie in Makro weiter unten)
  5. Nun erzeugt die privaten Daten auf der Laufzeit durch die XOR von part1 und part2 unter
  6. Zusätzlicher Schritt : Berechnen Hash erzeugten Daten und vergleicht ihn mit part1. Es wird die Integrität der privaten Daten überprüfen.

MACRO aufzufüllen Daten:

Nehmen wir an, Private Daten von 4 Bytes. Wir definieren ein Makro für sie, die die Daten mit Zuordnung Anweisungen in einigen zufälligen Reihenfolge gespeichert werden.

#define POPULATE_DATA(str, i0, i1, i2, i3)\
{\
    char *p = str;\
    p[3] = i3;\
    p[2] = i2;\
    p[0] = i0;\
    p[1] = i1;\
}

Sie nun dieses Makro in Code, wo Sie part1 und part2 speichern müssen, wie folgt:

char part1[4] = {0};
char part2[4] = {0};
POPULATE_DATA(part1, 1, 2, 3, 4); 
POPULATE_DATA(part2, 5, 6, 7, 8);

Kontext abhängig, aber man kann nur speichern Sie die Hash des Schlüssels sowie ein Salz (konstanter String, leicht zu verschleiern).

Dann, wenn (falls) der Benutzer den Schlüssel eingibt, fügen Sie die Salz , berechnen Sie die Hash und vergleichen.

Die Salz ist wahrscheinlich unnötig in diesem Fall hält er einen Brute-Force-Wörterbuch-Angriff, wenn der Hash kann (eine Google-Suche auch wissen, war zu arbeiten) isoliert werden.

Ein Hacker nach wie vor nur einen JMP-Befehl einfügen irgendwo die ganze Menge zu umgehen, aber das ist etwas komplizierter als eine einfache Textsuche.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top