C XOR Verschlüsselung entschlüsseln ohne den Key zu wissen?

asdfman schrieb:
Anstatt das Passwort zu erraten, versuchst du einfach mit dem Anfang des Textes. Bei XOR kann man das machen, muss am Ende aber immer noch ettliche Kombinationen ausprobieren. Das Problem bei einem unbekannten Text ist, dass er mit allem Möglichen anfangen könnte, z.B. ein Datum, ein Name oder auch eine Stadt. Dadurch kann bei diesem Vorgehen sogar eine Wörterbuchattacke für das erste Wort mit relativ hoher Wahrscheinlichkeit fehlschlagen.
Selbst wenn es ein Wort aus dem Duden ist, gibt es immer noch ~100.000 Möglichkeiten. Aber die Kombination die aus dem ersten Wort etwas sinnvolles macht, kann aus den nächsten Wörtern irgendetwas unbrauchbares produzieren. Das ist also eine ganz schöne Fummelarbeit, die sich bei einer Schlüssellänge von 4 Zeichen nicht lohnen dürfte.

Da bleibe ich doch lieber bei meinem Tipp, die 8 Millionen Versuche durchprobieren zu lassen. Es reicht ja aus, wenn man z.B. die ersten 100 Zeichen entschlüsselt. Diese überprüft man dann auf " und " und wenn das matcht auch auf andere häufige Wörter. Am Ende dann einfach eine Liste mit den Schlüsseln erstellen lassen, bei denen am meisten gematcht hat und fertig. Der Spaß kann in 30 Minuten erledigt sein.
 
Finde ich auch, bei Dateien mag das anders sein, dort ist der Anfang je nach Typ bekannt. Aber bei einem reinen deutschen Text können doch andere Ansätze schneller sein. Ich hab mal basierend auf dem Code im Anfangspost was geschrieben, was jeweils nach dem häufigsten Zeichen sucht und auf das dann mit space und e xor anwendet. Das heißt bei dem 4 Buchstabigenpasswort kommen bei mir 16 Möglichkeiten raus, die ich mir kurz anschaue. Sollte es sich bei dem Passwort noch zufälligerweise um ein Wort handeln, sticht das noch mehr heraus.

Eben mal an zwei CB-Artikeln (1200 und 1900 Zeichen) getestet und da klappt das einwandfrei.
 
Also ich bin jetzt soweit, dass ich weiß das an der
1.Position Zeichen (dec)20 10mal vorkommt
2.Position Zeichen (dec)21 10mal vorkommt
3.Position Zeichen (dec)2, 18, 30 alle 10mal vorkommen
4.Position Zeichen (dec)3 9mal vorkommt

wenn ich die mit 'e' oder 'space' XOR passt aber keins der daraus entstehenden Passwörter :(

Die Häufigkeiten der Zeichen berechne ich so:
Code:
void char_count(int array[], int verschluesselt[])
{
	int i,j;
	for (i=0; i < 255; i++)
	{
		array[i] = 0;
	}
	for (j = 0; j < 4; j++)
	{
		for (i = j; i < 200; i++)
		{
			array[verschluesselt[i]]++;
		}
	}
}

Das meist vorkommende Zeichen in Pos 1, 2, 3 & 4 ermittel ich so, indem ich die Funktion 4 mal aufrufe:
Code:
void max(int array[], int max_count[],int max_char[], int start)
{
	int x = 0;
	for (int i = start; i < 255; i+=4)
	{
		if (array[i] > x)
		{
			max_count[start] = array[i];
			max_char[start] = i;
			x = max_count[start];
		}
	}
}
 
Jetzt bin ich angefixt :)

Kanst du mir evtl. mal die verschlüsselte Datei schicken? Ich will das auch mal testen. Scheinen ja leider nicht so viele Zeichen zu sehen, was das mit der Verteilung etwas erschwert.

Aber mal noch eine andere Frage: Wo speicherst du, um welchen char es sich jeweils handelt? Dein max_char bekommt bei dir ja einfach das i zugewiesen, bewegt sich also immer willkürlich irgendwo zwischen (dec)0 und (dec)255. Das ist aber bestimmt nicht das Zeichen, das in der Datei steht.
 
Achso, sorry das hab ich vergessen zu erwähnen ^^
Ich lese die Zeichen mit der Funktion "read_crypt" in verschluesselt[] ein. Sprich dort werden alles Zeichen (dec) gespeichert.

Wenn ich dann "array[verschluesselt]++" ausführe, weiß ich ja z.B. bei verschleusselt=25, dass das 25. Zeichen aus dem Ascii Bereich vorgekommen ist. Also zähle ich es einen höher. Und das mache ich dann für alle Zeichen im Array verschluesselt.

Oder habe ich da einen Gedankenfehler?

Code:
void read_crypt(int verschluesselt[])
{
	FILE *pin;
	pin = fopen("crypt.bin", "rb");

	for (int i = 0; i < 200; i++)
	{
		verschluesselt[i] = getc(pin);
	}

	fclose(pin);
}

Die Datei kann ich leider nicht hochladen :-/ Es kommt immer ein Fehler, dass die Datei ungültig ist. Es handelt sich um eine ".bin" Datei.
 
Bin mir grade auf die Schnelle nicht sicher. Also enthält jetzt verschlüsselt[] jeden Wert von 0000 0000 bis 1111 1111 jeweils einmal oder wie?

Die Datei kannst du ja einfach zippen, .zip-Archive sind erlaubt.

Aber wie gesagt, wenn es sich nur um einen kürzeren Text handelt, kann die Annahme, dass Leerzeichen oder 'e' das häufigste Zeichen ist womöglich nicht mehr getroffen werden.
 
Doch, das klappt bei mir, hab den Klartext (abgesehen von den Umlauten, bei denen hapert's.)

Das Passwort kriege ich hierrüber:
Code:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>

#define pwdlength 4
int length=0, laenge[pwdlength], counter[pwdlength][256];
char zeichen[pwdlength][256];


int add_to_chart(int eingabe, int position)
{
	int i;
	
	if (laenge[position]==0) {
		zeichen[position][0]=eingabe;
		laenge[position]++;
		(counter[position][0])++;
		return 0;
	}
	
	for(i=0; i<laenge[position];i++){
		if (eingabe==(zeichen[position][i])){
			(counter[position][i])++;
			return 0;
		}
	}
	zeichen[position][i]=eingabe;
	(counter[position][i])++;
	laenge[position]++;
}

void read( char *in, int pwdlaenge)
{
    FILE *pin, *pout;
    int c, i;
     
    pin = fopen( in, "rb");
    if(!pin)
    return;
	
	for(i=0;i<pwdlaenge;i++){
	fseek(pin, 0L, SEEK_SET);
	length=0;
	while(1){
		c = getc( pin);
		if (feof(pin)) break;
		if (length%pwdlength==i) add_to_chart(c, i);
		length++;
    }
	}
	fclose( pin);
}

void crypt( char *in, char *out, unsigned char *passwort)
    {
    FILE *pin, *pout;
    int c;
    unsigned char *p;
     
    pin = fopen( in, "rb");
    pout = fopen( out, "wb");
    if( !pin)
    return;
    for( p = passwort; ; p++)
    {
    c = getc( pin);
    if( feof( pin))
    break;
    if( !*p)
    p = passwort;
    putc( c ^*p, pout);
    }
    fclose( pin);
    fclose( pout);
}


int sort_pwd(char *liste, int stellenzahl, int aktuelle_stelle, char *kandidaten){
	int i;
	if (aktuelle_stelle==stellenzahl) return(0);
		for(i=0;i<pow(2,stellenzahl-aktuelle_stelle-1);i++){
			liste[i*stellenzahl+aktuelle_stelle]=kandidaten[0];
		}
		for(i=pow(2,stellenzahl-aktuelle_stelle-1);i<pow(2,stellenzahl-aktuelle_stelle);i++){
			liste[i*stellenzahl+aktuelle_stelle]=kandidaten[1];
		}
		
		sort_pwd(liste, stellenzahl, aktuelle_stelle+1, kandidaten+2);
		char *zweite_haelfte=liste+ (int)(pow(2,stellenzahl-aktuelle_stelle-1)*stellenzahl);
		sort_pwd(zweite_haelfte, stellenzahl, aktuelle_stelle+1, kandidaten+2);
}


void main()
{
    char in[100];
    char out[100];
    unsigned char passwd[100];
     
    printf( "Eingabedatei: " );
    scanf( "%s", in);
     
    read(in, pwdlength);
	
	int i,j, max=0;
	int indexmax[pwdlength]={-1,-1,-1,-1};
	
	for(j=0; j<pwdlength;j++){
	for(i=0; i<laenge[j];i++){
		if (counter[j][i]>max){
			max=counter[j][i];
			indexmax[j]=i;
		}
	}
	max=0;
	}
	
	char kandidaten[2*pwdlength];
	printf("\nMit E bzw Leerzeichen ergibt sich:");
	for(j=0; j<pwdlength;j++){
		printf("\nBuchstabe %d: \'%c\' oder \'%c\'", j, 'e'^(zeichen[j][indexmax[j]]), ' '^(zeichen[j][indexmax[j]]));
		kandidaten[2*j]='e'^(zeichen[j][indexmax[j]]);
		kandidaten[2*j+1]=' '^(zeichen[j][indexmax[j]]);
	}
	
	char* passwortliste=malloc(pow(2, pwdlength)*pwdlength*sizeof (char));
	for(i=0;i<pow(2, pwdlength)*pwdlength;i++){passwortliste[i]='-';}
	sort_pwd(passwortliste, pwdlength, 0, kandidaten);

	for(i=0;i<64;i++){
		if (i%4==0) printf("\n");
		printf("%c", passwortliste[i]);
	}
	
}

In dem Fall ist 'e' das häufigste Zeichen.
 
Habe es gerademal in Go geschrieben: http://play.golang.org/p/vyjoPo6a3a
bei mir geht es mit Buchstaben zählen, komme auf

Code:
$ go run decrypt.go -l 4 -o crypt.bin
Passwort: wgyp
Bachelor Informatik.Softwaresysteme
Qualifikationsziele
Ziel der Ausbildung im Studiengang Informatik.Softwaresysteme ist es, Menschen f�r die
anspruchsvolle und interessante Arbeit im Umfeld der Informatik zu qualifizieren. Die
Absolventinnen und Absolventen erhalten eine Berufsbef�higung zum professionellen Entwurf und
zur Erstellung von Softwaresystemen, sowie die Begleitung solcher Systeme �ber den kompletten
Lebenszyklus vom Konzept �ber Planung, Implementierung, Test, Auslieferung bis hin zum Update.
Die F�cher des Studiengangs spannen daher einen weiten Bogen vom Softwaredesign �ber die
verschiedenen Werkzeuge bis hin zur Programmierung in verschiedenen Sprachen, enth�lt aber auch
begleitende F�cher wie z.B. Projektmanagement.
Im Studiengang werden die Aspekte Business, Entertainment und Mobile explizit mit entsprechenden
Wahlm�glichkeiten angesprochen. Die F�cherauswahl ist hierbei bewusst flexibel gestaltet, um den
jeweiligen Interessen der Studierenden optimalen Entfaltungsspielraum zu geben und um vielf�ltige
Spezialisierungsm�glichkeiten zu bieten. Neben den Kernf�chern aus der Informatik bestehen
weitere Wahlm�glichkeiten aus benachbarten Studieng�ngen wie z.B. der Wirtschaftsinformatik.
Die jungen Absolventinnen und Absolventen sind in der Lage, f�r die in Software abzubildenden
Prozesse ein Modell zu entwickeln, die Einflussgr��en zu definieren, Datenstrukturen zu erarbeiten
und eine passende Softwarearchitektur zu entwerfen und zu implementieren.
 
Du hast aber schon die komplette Datei eingelesen und nicht nur die ersten 200 Zeichen?

Und warum führst du in Zeile 8 das ganze jeweils vier mal aus, nur am Anfang ein Zeichen ignoriert?
 
Zuletzt bearbeitet:
Servus.

Bei dem eingesetzten Verfahren, dass der selbe Schlüssel immerwieder unmodifiziert angewendet wird (fixer Key, Blocklänge = Schlüssellänge, immer wieder angewandt => ECB (Electronic Codebook Mode)), kommst du mit dem Index of Coincidence ganz schnell ans Ziel: https://de.wikipedia.org/wiki/Koinzidenzindex

1.) Den Input um 1 Byte rotieren, sprich was vorher an x[0] stand, steht an x[1], x[1] nach x[2] usw. Das letzte Zeichen kommt an x[0].
2.) Dann den rotierten Input mit dem originalen Input vergleichen und die Anzahl der Zeichen zählen, die gleich sind. Diesen Wert merken/ausgeben.
3.) Wieder bei 1. Anfangen (den rotierten Input wieder um 1 Byte weiter rotieren)

Du wirst feststellen, dass bei diesem Verschlüsselungsmodus (ECB) die Häufigkeit der gleichen Zeichen immer dann besonders hoch ist, wenn man die Blocklänge (und damit die Schlüssellänge) trifft. Treten keine solchen Häufigkeitsspitzen auf, wurde vermutlich nicht der ECB Modus verwendet.

Sobald du die Schlüssellänge hast, so verfahren wie adsfman es beschrieben hat (nur dass du die Schlüssellänge nicht mehr raten musst).

(das ist übrigens einer von vielen Gründen, warum man ein Passwort niemals als Schlüssel benutzt, sondern aus dem Passwort einen Schlüssel generiert. Und - warum man den ECB Modus nicht benutzt)
 
Zuletzt bearbeitet:
Mein Senf dazu:
Koinzidenzindex + Frequenzanalyse in Python.

Funktioniert super (inkl. Umlaute).

Code:
import re, sys, operator, itertools, getopt

FREQ_CHARS = ['e', ' ', 'n', 'i', 's']
FREQ_WORDS = ['der', 'die', 'und', 'in', 'den']
HELP_TEXT = 'decryptxor.py -i <inputfile> [-e <encoding>]'
    
def decrypt(ciphertext, pw, encoding):
    plaintext = bytearray(ciphertext)
    length = len(pw)

    for i in range(len(plaintext)):
        plaintext[i] = plaintext[i] ^ ord(pw[i % length])

    return plaintext.decode(encoding = encoding, errors = 'replace')


def getMostFreqChars(ciphertext, pwLength):
    dicts = [{} for i in range(pwLength)]
    i = 0

    for byte in ciphertext:
        dic = dicts[i]
        if byte in dic: 
            dic[byte] += 1
        else:
            dic[byte] = 1
        i = (i + 1) % pwLength

    pairs = [(0,0) for i in range(pwLength)]
    i = 0

    for dic in dicts:        
        for byte in dic:
            freq = dic[byte]
            if freq > pairs[i][1]:
                pairs[i] = (byte, freq)
        i += 1

    return [pair[0] for pair in pairs]


def getMostFreqWords(text, count):
    dic = {}

    for word in text.split(' '):
        word = word.strip(' \t\n\r,.;:?!()[]{}\'\"').lower()
        if word in dic: 
            dic[word] += 1
        else: 
            dic[word] = 1

    mostFreq = sorted(dic.items(), key = operator.itemgetter(1), reverse = True)
    return [x[0] for x in mostFreq[:count]]


def getPassword(ciphertext, pwLength, encoding):
    chars = getMostFreqChars(ciphertext, pwLength)

    for i in range(1, len(FREQ_CHARS)):
        for product in itertools.product(FREQ_CHARS[:i], repeat = pwLength):
            pw = ''.join([chr(chars[i] ^ ord(product[i])) for i in range(pwLength)])
            plaintext = decrypt(ciphertext, pw, encoding)
            words = getMostFreqWords(plaintext, 5)			
            if (all([re.match("^[^\W\d]+$", x) for x in words]) 
                and any([x in words for x in FREQ_WORDS])):
                return pw, plaintext

    return None, ciphertext


def getPasswordLength(ciphertext):    
    textLength = len(ciphertext)
    maxKeyLength = min(textLength, 128)
    coincidences = {}

    for i in range(1, maxKeyLength):
        coincidences[i] = 0
        for j in range(textLength):
            if ciphertext[j] is ciphertext[(j + i) % textLength]:
                coincidences[i] += 1

    list = sorted(coincidences.items(), key = operator.itemgetter(1), reverse = True)
    listLength = min(len(list), 10)
    list = list[:listLength]

    for i in range(listLength - 1):
        maxIdx = max(list[i][0], list[i + 1][0])
        minIdx = min(list[i][0], list[i + 1][0])
        if maxIdx % minIdx is 0:
            minAbs = minIdx
            for j in range(listLength):
                maxIdx = max(list[j][0], minAbs)
                minIdx = min(list[j][0], minAbs)
                if maxIdx % minIdx is 0 and minIdx < minAbs and minIdx > 1:
                    minAbs = minIdx
            return minAbs        

    return 1


def main(argv):
    inputfile = ''
    encoding = 'utf-8'

    try:
        opts, args = getopt.getopt(argv,'hi:e:',['ifile=','encoding='])
    except getopt.GetoptError:
        print(HELP_TEXT)
        sys.exit(2)

    for opt, arg in opts:
        if opt == '-h':
            print(HELP_TEXT)
            sys.exit()
        elif opt in ('-i', '--ifile'):
            inputfile = arg
        elif opt in ('-e', '--encoding'):
            encoding = arg
         
    with open(inputfile, 'rb') as file:
         ciphertext = file.read()

    pwLength = getPasswordLength(ciphertext)
    pw, plaintext = getPassword(ciphertext, pwLength, encoding)

    if pw is not None:
        print('Password: ' + pw)
        print('')
        print(plaintext.replace(u'\ufffd', '?'))
    else:
        print('I failed :-(')


if __name__ == '__main__':
   main(sys.argv[1:])
$ py decryptxor.py -i crypt.bin -e cp852
Password: wgyp

Bachelor Informatik.Softwaresysteme
Qualifikationsziele
Ziel der Ausbildung im Studiengang Informatik.Softwaresysteme ist es, Menschen für die
anspruchsvolle und interessante Arbeit im Umfeld der Informatik zu qualifizieren. Die
Absolventinnen und Absolventen erhalten eine Berufsbefähigung zum professionellen Entwurf und
zur Erstellung von Softwaresystemen, sowie die Begleitung solcher Systeme über den kompletten
Lebenszyklus vom Konzept über Planung, Implementierung, Test, Auslieferung bis hin zum Update.
Die Fächer des Studiengangs spannen daher einen weiten Bogen vom Softwaredesign über die
verschiedenen Werkzeuge bis hin zur Programmierung in verschiedenen Sprachen, enthält aber auch
begleitende Fächer wie z.B. Projektmanagement.
Im Studiengang werden die Aspekte Business, Entertainment und Mobile explizit mit entsprechenden
Wahlmöglichkeiten angesprochen. Die Fächerauswahl ist hierbei bewusst flexibel gestaltet, um den
jeweiligen Interessen der Studierenden optimalen Entfaltungsspielraum zu geben und um vielfältige
Spezialisierungsmöglichkeiten zu bieten. Neben den Kernfächern aus der Informatik bestehen
weitere Wahlmöglichkeiten aus benachbarten Studiengängen wie z.B. der Wirtschaftsinformatik.
Die jungen Absolventinnen und Absolventen sind in der Lage, für die in Software abzubildenden
Prozesse ein Modell zu entwickeln, die Einflussgrößen zu definieren, Datenstrukturen zu erarbeiten
und eine passende Softwarearchitektur zu entwerfen und zu implementieren.
 
Vielen Dank Leute für die Unterstüzung!
Habe es letztendlich mit der Buchstabenhäufigkeit gelöst.
 

Ähnliche Themen

Zurück
Oben