bmaj8PCosFLAJjeHaevvvchnJedmg2iujpePOPivI2x2asw0yKa2eA15xvFJMFe82RGIcdlvxyaAPRuDuJhFjbh78BFsnCufJkarwEyKa0azHxccw5qegpcP9yaO0FKoohanxgiAfK1Lqwba51bKtjacbvdjMmcBkiv8kd62sBd98c4twa98sgj3iPh7nkP4
rlaejTPrua1DhBdg0jrIoDBi8fc1GIJAigivIGaxs1OmfPcctNadK3HErvzPLCeDPD8fkMNPCBcIwuoGfEHegOfk9k9pwktslqaBenaati1uNthMiyk9ndpy7gdIz88iot6A09cbNeIMheyjBvbeegL7aGp7mCb91hCxnvgV5abfImrPfLbrbraAsN6loJgh
Beide Saiten müssen gehasht werden bb66000000000000d698000000000000
Genau wie bei "C, 128 Bytes - By: Squeamish Ossifrage" beeinflussen die höherwertigen Bits niemals die niederwertigen Bits, dies kann ausgenutzt werden.
Code
Visual C ++ verwendet " unsichere " Zeichenfolgenoperationen
#include "stdafx.h"
#include <string>
#include <iostream>
#include <fstream>
long long x, y;
//Original hash function (not used for cracking).
void h(char inp[]){
long long c;
int index = 0;
int len = strlen(inp);
x = 0;
y = 0;
long long p = 0;
for (c = 9; c ; c = (index<len?inp[index++]:-1) + 1) {
for (++p; c--;) {
x = x*'[3QQ' + p;
y ^= c*x;
y ^= x ^= y;
}
}
printf("%016llx%016llx\n", x, y);
}
//Partial hash, takes a string and a starting point in the stream.
//The byte 0x08 must be prepended to a string in order to produce a full legal hash.
void hp(char inp[],long long p){
long long c;
int index = 0;
int len = strlen(inp);
x = 0;
y = 0;
for (index = 0; index<len; index++) {
c = inp[index] + 1;
for (++p; c--;) {
x = x*'[3QQ' + p;
y ^= c*x;
y ^= x ^= y;
}
}
}
//Reverse partial hash, backtracks the inner state.
void hprev(char inp[], long long p){
long long c;
long long clim;
int index = 0;
int len = strlen(inp);
p += len + 1;
x = 0;
y = 0;
for (index = len-1; index>=0; index--) {
clim = inp[index] + 1;
c = 0;
for (--p; c<clim;c++) {
y ^= x;
x ^= y;
y ^= c*x;
x -= p;
x = x * 17372755581419296689;
//The multiplicative inverse of 1530089809 mod 2^64.
}
}
}
const int rows = 163840;
const int maprows = 524288;
//Store for intermediate input strings, row 0 contains 64 columns with 3-char strings,
//row 1 contain 32 columns with 6-char strings and so forth, the final strings will
//contain one string from each column, in order.
char store[7][rows][512];
//Storage for a hashmap, used for matching n strings with n string in O(n) time.
char map[maprows][512];
int _tmain(int argc, _TCHAR* argv[])
{
char alpha[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int row;
int col;
int layer;
int a=0, b=0, c=0;
int colzero;
//Produce some starting strings.
for (row = 0; row < rows; row++){
//All column 0 strings begin with 0x08 in order to imitate the hash.
store[0][row][0] = 8;
colzero = 1;
for (col = 0; col < 64; col++){
store[0][row][col * 8 + colzero] = alpha[a];
store[0][row][col * 8 + colzero + 1] = alpha[b];
store[0][row][col * 8 + colzero + 2] = alpha[c];
store[0][row][col * 8 + colzero + 3] = 0;
colzero = 0;
}
a++;
if (a >= 52){
b++;
a = 0;
if (b >= 52){
c++;
b = 0;
}
}
}
//Layer for layer, column for column, build strings that preserve successively
//more zero bits. Forward calculated partial hashes are matched with backwards
//calculated partial hashes.
for (layer = 1; layer < 7; layer++){
int slayer = layer - 1;
int swidth = 1 << (slayer + 3);
int width = 1 << (layer + 3);
int slen = 3 << slayer;
int len = 3 << layer;
int colnum;
int layershift=slayer*8;
for (col = 0,colnum=0; col < 512; col+=width,colnum++){
printf("Layer: %i, column: %i\n",layer,colnum);
memset(map, 0, sizeof map);
int col2 = col + swidth;
for (row = 0; row < rows; row++){
hprev(store[slayer][row] + col2, 1 + slen*(1 + colnum * 2));
x = (x >> layershift) & 255;
y = (y >> layershift) & 255;
int index = (x << 3) | (y << 11);
for (a = 0; a < 8; a++){
if (map[index + a][0] == 0){
strcpy_s(map[index + a], store[slayer][row] + col2);
break;
}
}
}
int destrow = 0;
for (row = 0; row < rows && destrow < rows; row++){
hp(store[slayer][row] + col, !!colnum + slen*(colnum * 2));
x = (x >> layershift) & 255;
y = (y >> layershift) & 255;
int index = (x << 3) | (y << 11);
for (a = 0; a < 8 && destrow < rows; a++){
if (map[index + a][0]){
strcpy(store[layer][destrow] + col, store[slayer][row] + col);
strcat(store[layer][destrow] + col, map[index + a]);
destrow++;
}
}
}
}
}
memset(map, 0, sizeof map);
char temp[1000];
std::ofstream myfile;
myfile.open("hashout.txt");
for (row = 0; row < rows; row++){
hp(store[6][row], 0);
sprintf(temp, "%016llx%016llx", x, y);
myfile << store[6][row] <<" " << temp << "\n";
}
myfile << "\n";
//The final hash set has 96 of 128 output bits set to 0, I could have gone all
//the way, but this is enough to find a collision via the birthday paradox.
for (row = 0; row < rows; row++){
hp(store[6][row], 0);
long long xc = x;
long long yc = y;
int pos = (xc >> 45 | ((yc >> 48) & 7)) & (maprows-1);
while (map[pos][0]!=0){
hp(map[pos], 0);
if (x == xc && y == yc){
myfile << store[6][row] << "\n" << map[pos] << "\n";
sprintf(temp,"%016llx%016llx", x, y);
myfile << temp << "\n\n";
}
pos = (pos + 1) % maprows;
}
strcpy_s(map[pos], store[6][row]);
}
myfile.close();
printf("done");
getchar();
return 0;
}
Python, 109 Bytes von Sp3000
Beachten Sie, dass Martin zuerst geknackt hat, daher bin ich mir nicht sicher, ob dies Punkte verdient. Andererseits habe ich eher einen Preimage-Angriff als eine einfache Kollision ausgeführt - ein viel stärkeres Ergebnis. Dies bedeutet, dass Sie ihm einen beliebigen Hash-Wert zuweisen können und eine Eingabe erstellen, die diesen Hash-Wert generiert.
Und um zu zeigen, dass es funktioniert:
Und um einen bestimmten Satz von Zahlen anzugeben, die kollidieren:
quelle
Python, 109 Bytes von Sp3000
und
beide ergeben
Der Algorithmus teilt die Eingabe in 128-Bit-Chunks auf und ändert den Hash (Seed-to-Wert
42
) für jeden Chunk wiederholt , bevor am Ende ein zusätzliches Hashing durchgeführt wird. Um eine Kollision zu finden, ist es unser Ziel, zwei Zahlen zu finden, die dasselbe Ergebnis liefern, nachdem der folgende Pseudocode für jeden Block ausgeführt wurde:Da der Hash mod 2 128 ist , wollen wir nach Zahlen suchen, die alle interessanten Dinge außerhalb dieses Bitbereichs verschieben. Aber der Hash ist
42
so angelegt , dass er zunächst einige nicht so wichtige Bits enthält:Meine Idee war, diese Teile loszuwerden, wenn ich den ersten Teil hinzufüge. Versuchen wir also 2 128 -42:
Das ist ziemlich einfach, also versuchen wir, das als eine der beiden Zahlen zu verwenden. (In der Tat ist die erste Nummer der Kollision, die ich verwendet habe, 2 128 -42.
Wie finden wir nun eine andere Zahl mit dem gleichen Ergebnis? Nun, nach einer Iteration ist der Hash nicht
42
mehr vorhanden, aber2**122
wie wir gerade gezeigt haben. Durch Hinzufügen eines zweiten Teils zu unserer Eingabenummer können wir nun eine weitere Iteration ausführen. Wir können den zweiten Block mit demselben Argument wie diesen auswählen, dh wir wollen 2 128 -2 122 . Dann ist das Zwischenergebnis danachhash += chunk
identisch und wir erhalten am Ende dasselbe Ergebnis.Wir können also die beiden Zahlen der Kollision berechnen:
Wir können leicht viel mehr Kollisionen wie diese erzeugen.
quelle
Mathematica, 89 Bytes von LegionMammal978
und
Beide ergeben
0
.Das Prinzip dieses Cop besteht darin, einen "zufälligen" binären 1-D-Zellularautomaten aus einer "zufälligen" Anfangsbedingung für eine "zufällige" Anzahl von Schritten zu entwickeln und dann die ersten 128 Zellen des Ergebnisses als Ganzzahl zu interpretieren.
Das Problem besteht darin, dass die Regel einfach durch bestimmt wird
Mod[#^2,256]
, sodass jedes Vielfache von 16 die Regel ergibt. Dies0
ist die triviale Regel, bei der alle Zellen immer Null sind. Wenn die Eingabe nicht durch 99 teilbar ist, werden wir mindestens 1 Schritt weiterentwickeln, sodass die Ausgabe immer Null ist. Also kollidieren zwei beliebige Vielfache, die keine Vielfachen von 99 sind, definitiv. Allerdings Eingang0
auch gibt 0 (trotz nie der Regel verwendet wird ), weil die Anfangsbedingung nur die binäre Darstellung des Eingangssignals (die alle Nullen in diesem Fall).Abgesehen davon können wir andere Kollisionen finden, die völlig unabhängig von der Regel sind. Wie oben erwähnt, bedeutet ein Vielfaches von 99, dass sich der Zellularautomat überhaupt nicht weiterentwickelt hat. Das Ergebnis ist also einfach das erste (höchstwertige) 128-Bit der Anfangsbedingung. Dies ist selbst nur die eingegebene Zahl. Wenn wir also zwei Vielfache nehmen, die sich in den ersten 128 Bits nicht unterscheiden (rechts mit Nullen aufgefüllt), erhalten wir auch eine Kollision. Das einfachste Beispiel dafür ist
M = 99
,N = 99*2 = 198
.quelle
J, 39 Bytes
Die erste Nummer ist:
Das heißt,
10000000
64-mal wiederholt. Die zweite Zahl ist die plus eins, dhBeide ergeben
Erläuterung
Beginnen wir mit
x := H 10000000 = 146018215378200688979555343618839610915
undy := 2^128
. Anstatt zu finden ,a, b
so dassa == b mod y
, suchen wir füra, b
so dassx^a == x^b mod y
im Algorithmus Verwendung der Macht Türme machen.Aber es muss
k
solche gebenx^k == 1 mod y
, dax, y
es Koprime gibt, und dafürk
müssen wir habena == b mod k
. Wir können also den diskreten Logarithmus von 1 Mody
finden und für den ersten Schritt erhalten wirAlso wollen wir jetzt zwei
a, b
solche Zahlen findena == b mod k
. Um dies zu tun, setzen wiry
zu seink
und versuchen zu finden ,a, b
so dassx^a == x^b mod y
wieder. Mit der gleichen Logik nehmen wir den diskreten Logarithmus wieder und erhaltenWir wiederholen dies, bis wir zu einem kleinen
y
Punkt kommen. An diesem Punkt ist es trivial, zwei Zahlen zu finden, die das gleiche Modulo habeny
. Nach 63 Iterationeny = 4
funktionieren grundsätzlich zwei beliebige Zahlen.Hier ist der Mathematica-Code zum Generieren der diskreten Protokollkette:
Dies ergibt die folgende Ausgabe .
quelle
2^(2^30)
Limit zu überschreiten, daher der Scheck.Pyth, 8 Bytes von FryAmTheEggman
und
Die Gleitkommapräzision ist dafür nicht groß genug.
quelle
437409784163148
für beide. Ich frage mich, warum es einen Unterschied gibt ...437409784163148
und37409784163148
ich denke, es hat aus irgendeinem Grund nur die letzte Ziffer verloren, aber 99 ... 997 gibt die gleiche Antwort wie 999 ... 98.CJam, 44 Bytes,
Benutzerjimmy23013Die Zahlen sind zu groß, um sie zu posten, also sind sie hier auf Pastebin: Nummer 1 , Nummer 2 .
Die erste Zahl ist
600^2 = 360000
eins. Die zweite Zahl ist bis auf die folgenden Änderungen identisch:Beides muss Hash sein
271088937720654725553339294593617693056
.Erläuterung
Werfen wir einen Blick auf die erste Hälfte des Codes:
Also, wenn wir zwei Eingangszahlen finden können, so dass die Summen von
S[i][j]*13^i*19^j
16^20
sowohl für das ursprüngliche 600-breite Array als auch für das gezippte Array dasselbe Modulo aufweisen , sind wir fertig.Um die Sache ein wenig einfacher zu machen, werden wir nur darüber nachdenken
600^2 = 360000
-stellige Eingabenummern, so dass das 600-breite Array nur ein Quadrat mit 600 mal 600 Ziffern ist. Dies erleichtert die Visualisierung und ist seitdem gültig10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Um die Sache noch weiter zu vereinfachen, betrachten wir nur solche Eingabezeichenfolgen, deren Ziffernquadrat entlang der Hauptdiagonale symmetrisch ist, so dass das ursprüngliche Array und das gezippte Array identisch sind. Dadurch können wir auch die anfängliche Umkehrung der Zeichenfolge und die Indexnummerierung von rechts nach links ignorieren, die sich gegenseitig aufheben.Um uns anzufangen, können wir die erste Zahl als
360000
eine annehmen . Um die zweite Zahl zu erhalten, möchten wir diese ändern, indem wir einige der Ziffern so ändern, dass die Summen das gleiche Modulo haben16^20
, wobei die Symmetrie des Ziffernquadrats erhalten bleibt. Wir erreichen dies, indem wir eine Liste von Tripeln finden,(i, j, k)
damitwo
1 <= k <= 8
ist der Betrag, um den die Ziffer 1 erhöht werden muss (dh indem eine Ziffer von 2 auf 9 geändert wird - wir hätten 0 einschließen können, aber wir haben es nicht benötigt) und0 <= i < j < 600
sind Indexpaare.Sobald wir die haben
(i, j, k)
Drillinge, ändern wir die Ziffern auf(i, j)
und(j, i)
zu ,1+k
um die zweite Nummer. Die Drillinge wurden mit einem gierigen Backtracking-Algorithmus gefunden, und für die zweite Zahl über dem Ziffernquadrat sieht es folgendermaßen aus:Zum Beispiel
(i, j, k) = (0, 1, 7)
entspricht das Ändern der Ziffern(0, 1)
(Position600*0 + 1 = 1
) und(1, 0)
(Position600*1 + 0 = 600
) zu1 + 7 = 8
.Hier ist der Backtracker in Python 3, obwohl eine genauere Betrachtung ergab, dass wir ziemlich viel Glück hatten, da tatsächlich kein Backtracking stattgefunden hat:
Als Bonus gibt es hier einen nicht so effizienten Port des Hashes in Python 3. Es war nutzlos.
quelle
PHP 4.1, 66 Bytes von Ismael Miguel
Gefunden mit einfachem iteriertem Hashing, beginnend mit 1:
quelle
hash(hash(hash(...(hash(1)...)))
) erstellt. Die erste Kette formte sich fast augenblicklich zu einer Schleife. Ich brauchte nicht einmal meinen Multithread-Hash-Cracker aufzurufen.Python 3 (216) von Sp3000
Meine Nachrichten sind
Ich habe diesen Python 2-Code verwendet, um sie zu generieren:
Der große Modul war ein Produkt von zwei Primzahlen
a
undb
. Ich denke, die Hoffnung war, dass es NP-unmöglich für uns sein würde, das Semiprime zu berücksichtigen, aber ich denke, 128 Bit sind zu klein, da mir eine Webseite die Antwort sofort gab.Das multiplikative Gruppenmodulo
ab
hat die Ordnung (a - 1) (b - 1), was bedeutet, dass, wenn wir eine Zahl auf diese Potenz erhöhen, dies zu 0 oder (normalerweise) 1 führen muss. Also habe ich 1 Bits an Stellen gesetzt, die resultierten 2 (a-1) (b-1) wird in den Hash multipliziert. Dann ist die andere Nachricht im Grunde genommen 0, aber ich setze in jeder Zahl ein weiteres Bit, um die Längen gleich zu machen.Ich denke, es wäre ärgerlicher gewesen, wenn der Hash-Wert in jedem Punkt genau abgepasst worden wäre, anstatt erst, nachdem alle Primzahlen verwendet worden wären. Dann wäre es nicht so einfach gewesen, beliebige Exponenten für sie zu bauen.
quelle
C, 128 Bytes - durch: zimperliches Ossifrage
Die folgenden beiden Zeichenfolgen haben beide einen Hash-Wert für alle Nullen:
Die Hash-Funktion ist so aufgebaut, dass höherwertige Bits niemals niederwertige Bits beeinflussen. Daher kann ich eine Sammlung von Zeichenfolgen generieren, bei denen alle
x
niederwertigen Bits Null sind. Dann kann ich verkettete Kombinationen dieser Zeichenfolgen versuchen, um einige zu finden, bei denen mehr der Zeichenfolgen vorhanden sind niedrigere Bits sind Null usw. Ich bin mir ziemlich sicher, dass es mehr Möglichkeiten gibt, dies zu unterbrechen, und auch Möglichkeiten, die deutlich kürzere Zeichenfolgen erzeugen, aber auf diese Weise habe ich es vermieden, viel zu rechnen.quelle
0x0000000a0000000a0000000a0000000a
meinem System, aber das ist immer noch ziemlich erstaunlich. (echo -ne '\x0a' |./hash
gibt auch das gleiche Ergebnis.)Python 3, 118 Bytes
und
(das heißt: 9E400 und 9E4000)
Beide produzieren
Etwas tiefer zu graben, scheint, dass jede ganze Zahl, gefolgt von k wiederholten Ziffern, so dass k> 128 und (k% 4 == 0) den gleichen Hash zurückgeben. Zum Beispiel
H("1"+"1"*32*4)
undH("1"+"1"*33*4)
beides13493430891393332689861502800964084413
. Hmmm, 128 ...quelle
Python 2, 161 Bytes, von Puzzled
und
Beide haben die Ausgabe:
Die Zahlen sind 2 ^ 128 und 2 ^ 128 + (3 * 5 * 7 * 11 * 13 * 17) ^ 2 * 19 * 2 ^ 32.
quelle
Java, 299 Bytes von SuperJedi224
Pastebin für
M
. In binärerM
Form hat 655351
s, gefolgt von 20
s.Pastebin für
N
. In binärerN
Form hat 218451
s, gefolgt von 1747660
s.Beide ergeben
0
.Beachten Sie, dass die Grundlage des Algorithmus ist
i.bitCount()*i.bitLength()+1
und wir das Ergebnis letztendlich zur Potenz voni
und zu Mod 2 128 nehmen . Die Idee war also, nur zwei zu findeni
, die durch vier teilbar sind, aber bei denen der erste Ausdruck 2 32 ergibt . Dies wurde leicht durch Faktorisierung von 2 32 erreicht -1 berücksichtigt und zwei Faktoren für die Anzahl der Einsen und die Gesamtbitbreite der Zahl ausgewählt wurden.Bearbeiten: Eigentlich gibt es ein bisschen mehr
M
Gründe , warum Null ergibt, aber wir können aufgrund meiner Erklärung leicht mehr Zahlen finden, die Null ergeben, indem wir andere Faktoren von 2 32 -1 verwenden, so dass am Ende mindestens 64 Nullen stehen.quelle
C, 134 Bytes (von Barteks2x)
und
beides hash zu
weil der Algorithmus nur die letzte Ziffer hascht!
quelle
C 87 Bytes
Mit meinem Kollisions-Bruteforcer gefunden.
quelle
473E0B6ED5AF2B92 7EC2BC9B5E9F5645 -> 0000000000000000 0EAC34C8A9F94389
nach 3525078917 Hash-Funktionsaufrufen undreal 14m24.970s user 48m42.410s
Uhrzeit.Python 2, 115 Bytes, durch zimperliche Ossifrage
und
Der Hashwert hatte nichts mit der Reihenfolge der Blöcke zu tun.
quelle
Python 2.x, 139 Bytes von Puzzled
H(2)
und
H(128)
beide kehren zurück
16645614427504350476847004633262883518
.quelle
C ++, 239 Bytes von SpelingMistake
Unter Verwendung des bereitgestellten "Haupt" -Programms erzeugen die folgenden zwei Eingaben den gleichen Hash:
und
Die ersten 8 Bytes der Eingabe werden aufgrund dieses Fehlers im Code nie verarbeitet :
weil das
--i
Ergebnis falsch , wenni==1
,q[0]
(die ersten 8 BytesI
istint64
). Das Ersetzen der Schleifenbedingung durchfor(I i=n;i--;)
hätte dies behoben.quelle
Ruby, 90 Bytes, von MegaTom
und
Das sind 2 und 11, gefolgt von 40 Null-Bytes. Sie haben also beide 41 Bytes. Der Hash-Wert wird um die Eingabelänge für jedes Byte addiert und anschließend in Dezimalzahlen umgekehrt. Eine mit endende Eingabelänge
1
kann sicherstellen, dass der Hash-Wert mit a endet0
ziemlich schnell . Beim Umkehren wird die Länge des Hash-Werts um 1 verringert.Beide haben den Hash-Wert
259
.quelle
C # - 393 bytes - von: Logan Dam
70776e65642062792031333337206861786f72
und70776e65642062792031333337206861786f7200
beides zu haschen18E1C8E645F1BBD1
.quelle