Skip to content

Commit b822764

Browse files
committed
Add feature to work with partially known hashes.
Reason and usage are described here: http://blog.mheistermann.de/2014/04/14/plaidctf-2014-parlor-crypto-250-writeup/
1 parent 3564d49 commit b822764

File tree

1 file changed

+77
-17
lines changed

1 file changed

+77
-17
lines changed

main.cpp

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include <unistd.h>
2+
#include <arpa/inet.h>
23
#include <getopt.h>
4+
#include <stdint.h>
35
#include <openssl/sha.h>
46
#include "SHA1.h"
57
#include "MD5ex.h"
@@ -113,15 +115,18 @@ void PrintHelp()
113115
cout << " -d --data The data from the known message." << endl;
114116
cout << " -a --additional The information you would like to add to the known message." << endl;
115117
cout << " -k --keylength The length in bytes of the key being used to sign the original message with." << endl;
118+
cout << " -u --unknown number if leading hash bits unknown (EXPERIMENTAL HACK)" << endl;
119+
cout << " -z --sig2 target signature (EXPERIMENTAL HACK)" << endl;
116120
cout << " Version 1.0 with MD5, SHA1, SHA256 and SHA512 support." << endl;
117121
cout << " <Developed by bwall(@bwallHatesTwits)>" << endl;
118122
}
119123

120124
int main(int argc, char ** argv)
121125
{
122-
string sig;
126+
string sig, sig2;
123127
string data;
124128
int keylength = 0;
129+
int unknown = 0;
125130
string datatoadd;
126131
Extender * sex = NULL;
127132
bool run_tests = false;
@@ -135,11 +140,13 @@ int main(int argc, char ** argv)
135140
{"data", required_argument, 0, 0},
136141
{"additional", required_argument, 0, 0},
137142
{"keylength", required_argument, 0, 0},
143+
{"unknown", required_argument, 0, 0},
144+
{"sig2", required_argument, 0, 0},
138145
{"help", no_argument, 0, 0},
139146
{0, 0, 0, 0}
140147
};
141148

142-
int c = getopt_long(argc, argv, "ts:d:a:k:h", long_options, &option_index);
149+
int c = getopt_long(argc, argv, "ts:d:a:k:u:z:h", long_options, &option_index);
143150
if (c == -1)
144151
break;
145152

@@ -149,16 +156,11 @@ int main(int argc, char ** argv)
149156
switch(option_index)
150157
{
151158
case 0:
159+
case 't':
152160
run_tests = true;
153161
break;
154162
case 1:
155163
sig.assign(optarg);
156-
sex = GetExtenderForHash(sig);
157-
if(sex == NULL)
158-
{
159-
cout << "Unsupported signature size." << endl;
160-
return 0;
161-
}
162164
break;
163165
case 2:
164166
data.assign(optarg);
@@ -170,21 +172,20 @@ int main(int argc, char ** argv)
170172
keylength = atoi(optarg);
171173
break;
172174
case 5:
175+
unknown = atoi(optarg);
176+
break;
177+
case 6:
178+
sig2.assign(optarg);
179+
break;
180+
case 7:
173181
PrintHelp();
174182
return 0;
175183
}
176184
break;
177-
case 't':
178185
run_tests = true;
179186
break;
180187
case 's':
181188
sig.assign(optarg);
182-
sex = GetExtenderForHash(sig);
183-
if(sex == NULL)
184-
{
185-
cout << "Unsupported hash size." << endl;
186-
return 0;
187-
}
188189
break;
189190
case 'd':
190191
data.assign(optarg);
@@ -195,6 +196,12 @@ int main(int argc, char ** argv)
195196
case 'k':
196197
keylength = atoi(optarg);
197198
break;
199+
case 'u':
200+
unknown = atoi(optarg);
201+
break;
202+
case 'z':
203+
sig2.assign(optarg);
204+
break;
198205
case 'h':
199206
PrintHelp();
200207
return 0;
@@ -257,9 +264,62 @@ int main(int argc, char ** argv)
257264
vector<unsigned char> vtoadd = StringToVector((unsigned char*)datatoadd.c_str());
258265

259266
unsigned char firstSig[128];
267+
unsigned char targetSig[128];
260268
DigestToRaw(sig, firstSig);
261-
unsigned char * secondSig;
262-
vector<unsigned char> * secondMessage = sex->GenerateStretchedData(vmessage, keylength, firstSig, vtoadd, &secondSig);
269+
DigestToRaw(sig2, targetSig);
270+
unsigned char * secondSig = 0;
271+
272+
273+
sex = GetExtenderForHash(sig);
274+
if(sex == NULL)
275+
{
276+
cout << "Unsupported signature size." << endl;
277+
return 0;
278+
}
279+
uint32_t maxval = 1 << unknown;
280+
uint32_t mask = ~ ((1<<(unknown)) - 1);
281+
printf("mask: %x\n", mask);
282+
vector<unsigned char> * secondMessage = 0;
283+
uint32_t *sigStart = (uint32_t*)&firstSig;
284+
uint32_t part1 = htonl(*sigStart);
285+
for (uint32_t prefix =0; prefix <= maxval; prefix++) {
286+
if (prefix % (1<<20) == 0) {
287+
float part = (float)prefix/maxval;
288+
printf("progress: 0x%16x, %.4f: ", prefix, part);
289+
#define WIDTH 40
290+
for(int i=0; i < WIDTH; i++) {
291+
if (float(i)/WIDTH < part)
292+
printf("=");
293+
else {
294+
printf(" ");
295+
}
296+
}
297+
printf("|\r");
298+
fflush(stdout);
299+
}
300+
uint32_t shiftedPrefix = prefix << (32-unknown);
301+
*sigStart = htonl(part1 | shiftedPrefix);
302+
303+
// all this allocation and deallocation is a stupid idea
304+
if (secondSig)
305+
delete[] secondSig;
306+
if (secondMessage)
307+
delete secondMessage;
308+
secondMessage = sex->GenerateStretchedData(vmessage, keylength, firstSig, vtoadd, &secondSig);
309+
// cheating a bit: if the lower 96 bit match, we're probably lucky.
310+
if (memcmp(secondSig+4, targetSig+4, 12) == 0) {
311+
printf("\nsuccess with origHash = ");
312+
for(unsigned int x = 0; x < sig.size()/2; x++)
313+
{
314+
printf("%02x", firstSig[x]);
315+
}
316+
printf("\n");
317+
printf("prefix: 0x%x\n", prefix);
318+
break;
319+
} else {
320+
}
321+
}
322+
printf("predicted sig: ");
263323
for(unsigned int x = 0; x < sig.size()/2; x++)
264324
{
265325
printf("%02x", secondSig[x]);

0 commit comments

Comments
 (0)