106 Stimmen

Techniken zur Verschleierung sensibler Zeichenketten in C++

Ich muss sensible Informationen (einen symmetrischen Verschlüsselungsschlüssel, den ich geheim halten möchte) in meiner C++-Anwendung speichern. Der einfache Ansatz ist dieser:

std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

Wenn Sie die Anwendung jedoch über den strings Prozess (oder jeder andere, der Zeichenketten aus einer binären Anwendung extrahiert) wird die obige Zeichenkette aufdecken.

Welche Techniken sollten verwendet werden, um solche sensiblen Daten zu verbergen?

Edita:

OK, also haben so ziemlich alle von Ihnen gesagt "Ihre ausführbare Datei kann zurückentwickelt werden" - natürlich! Das ist eines meiner Lieblingsärgernisse, also werde ich hier ein bisschen schimpfen:

Warum werden 99% (OK, vielleicht übertreibe ich ein wenig) aller sicherheitsrelevanten Fragen auf dieser Website mit einem Schwall von "es gibt keine Möglichkeit, ein perfekt sicheres Programm zu erstellen" beantwortet - das ist keine hilfreiche Antwort! Sicherheit ist eine gleitende Skala zwischen perfekter Benutzerfreundlichkeit und keiner Sicherheit am einen Ende und perfekter Sicherheit aber keiner Benutzerfreundlichkeit am anderen Ende.

Der Punkt ist, dass Sie Ihre Position auf dieser gleitenden Skala wählen, je nachdem, was Sie zu tun versuchen und die Umgebung, in der Ihre Software laufen wird. Ich schreibe keine Anwendung für eine Militäreinrichtung, sondern eine Anwendung für einen Heim-PC. . Ich muss Daten über ein nicht vertrauenswürdiges Netz mit einem bekannten Verschlüsselungscode verschlüsseln. In diesen Fällen ist "Sicherheit durch Unklarheit" wahrscheinlich gut genug! Sicher, jemand mit genügend Zeit, Energie und Geschick könnte das Binärprogramm zurückentwickeln und das Passwort herausfinden, aber was soll's? Es ist mir egal:

Die Zeit, die ich benötige, um ein erstklassiges sicheres System zu implementieren, ist teurer als die Umsatzeinbußen durch die geknackten Versionen (nicht dass ich das tatsächlich verkaufen würde, aber Sie verstehen, worauf ich hinaus will). Dieser blauäugige "Wir machen es auf die absolut bestmögliche Art und Weise"-Trend in der Programmierung unter neuen Programmierern ist gelinde gesagt töricht.

Vielen Dank, dass Sie sich die Zeit genommen haben, diese Fragen zu beantworten - sie waren sehr hilfreich. Leider kann ich nur eine Antwort akzeptieren, aber ich habe alle nützlichen Antworten hochgestuft.

4voto

Frerich Raabe Punkte 85859

Natürlich ist die Speicherung privater Daten in Software, die an den Nutzer ausgeliefert wird, immer ein Risiko. Jeder ausreichend ausgebildete (und engagierte) Ingenieur könnte die Daten zurückentwickeln.

Allerdings kann man die Sicherheit oft schon dadurch erhöhen, dass man die Hürde, die jemand überwinden muss, um Ihre privaten Daten preiszugeben, erhöht. Das ist in der Regel ein guter Kompromiss.

In Ihrem Fall könnten Sie Ihre Zeichenketten mit nicht druckbaren Daten überladen und diese dann zur Laufzeit mit einer einfachen Hilfsfunktion wie der folgenden 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;
    // ...
}

4voto

Bartosz Wójcik Punkte 1012

Ich habe ein einfaches Verschlüsselungstool für Strings erstellt, es kann automatisch verschlüsselte Strings erzeugen und hat ein paar zusätzliche Optionen, um das zu tun, ein paar Beispiele:

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;

2voto

Nic Strong Punkte 6422

Das hängt davon ab, was Sie zu schützen versuchen, wie Joshperry betont. Aus Erfahrung würde ich sagen, wenn es Teil eines Lizenzsystems zum Schutz Ihrer Software ist, dann lassen Sie es lieber. Sie werden sie nach und nach zurückentwickeln. Verwenden Sie einfach eine einfache Chiffre wie ROT-13, um sie vor einfachen Angriffen zu schützen (indem Sie Zeichenketten über sie laufen lassen). Wenn es darum geht, die sensiblen Daten der Benutzer zu schützen, würde ich mich fragen, ob es klug ist, diese Daten mit einem lokal gespeicherten privaten Schlüssel zu schützen. Auch hier kommt es darauf an, was Sie schützen wollen.

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

2voto

sbi Punkte 211669

Wie bereits gesagt wurde, gibt es keine Möglichkeit, Ihre Saite vollständig zu schützen. Aber es gibt Möglichkeiten, sie mit einer angemessenen Sicherheit zu schützen.

Als ich dies tun musste, habe ich eine unschuldig aussehende Zeichenkette in den Code eingefügt (z. B. einen Copyright-Hinweis oder eine gefälschte Benutzereingabeaufforderung oder irgendetwas anderes, das nicht von jemandem geändert werden kann, der nicht verwandten Code korrigiert), diese Zeichenkette mit sich selbst als Schlüssel verschlüsselt, einen Hashwert (unter Hinzufügung eines Salzes) erstellt und das Ergebnis als Schlüssel verwendet, um das zu verschlüsseln, was ich eigentlich verschlüsseln wollte.

Natürlich kann das System gehackt werden, aber dazu braucht es einen entschlossenen Hacker.

1voto

Collin Punkte 437

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

Wie bereits in einem früheren Beitrag erwähnt, sollten Sie bei einem Mac den Schlüsselbund verwenden.

Im Grunde genommen sind alle diese netten Ideen, wie Sie Ihren privaten Schlüssel in Ihrem Binärprogramm speichern können, aus der Sicht der Sicherheit so schlecht, dass Sie sie nicht anwenden sollten. Jeder, der Ihren privaten Schlüssel bekommt, ist eine große Sache, bewahren Sie ihn nicht innerhalb Ihres Programms auf. Je nachdem, wie wichtig Ihre Anwendung ist, können Sie Ihre privaten Schlüssel auf einer Smartcard oder auf einem entfernten Computer aufbewahren, mit dem Ihr Code kommuniziert, oder Sie können tun, was die meisten Leute tun, und sie an einem sehr sicheren Ort auf dem lokalen Computer aufbewahren (dem "Schlüsselspeicher", der eine Art seltsame, sichere Registrierung ist), der durch Berechtigungen und alle Stärken Ihres Betriebssystems geschützt ist.

Dies ist ein gelöstes Problem und die Antwort ist, den Schlüssel NICHT in Ihrem Programm zu behalten :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X