-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgenerate.cpp
396 lines (303 loc) · 14.6 KB
/
generate.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
#include <iostream>
#include <fstream>
#include <iomanip>
#include <list>
#include <vector>
#include <ctime>
#include <cmath>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <random>
#include "blake.hpp"
using namespace std;
typedef list<pair<char[7],char[7]>*> Table_t;
extern char alphabet[64];
extern void (*hashfun)( uint8_t *out, const uint8_t *in, uint64_t inlen );
extern void (*redfun) ( char* out, const uint8_t *in, int red_by );
bool lookup(char* pwd, Table_t* rainbow, char* startpoint );
extern bool v, savechain, prng, inplace;
extern ofstream outchain;
/*
* Comparator function to be passed in list sorter.
*
* With an iput of "first" and "second" start-end-pair pointers,
* returns whether (first->end) < (second->end)
* based on alphabet's indexing. ( see matrix above )
*
* That means first compare key is endpoint,
* Second is startpoint, then select arbitrarily.
*
*/
bool pass_comparator(const pair<char[7],char[7]>* first, const pair<char[7],char[7]>* second){
unsigned int i=0;
while( i<7 ){
if( first->second[i] < second->second[i] )
return true;
else if ( first->second[i] > second->second[i] )
return false;
else
++i;
}
// If endpoints identical, compare based on startpoints!
i=0;
while( i<7 ){
if( first->first[i] < second->first[i] )
return true;
else if ( first->first[i] > second->first[i] )
return false;
else
++i;
}
// If even startpoints identical (<1 in a million) leave them be.
return true;
}
/*
* Binary predicate function to be passed in list duplicate-remover.
*
* With an iput of "first" and "second" start-end-pair pointers,
* returns whether (first->end) = (second->end)
*
*/
bool pass_predicate(const pair<char[7],char[7]>* pair1, const pair<char[7],char[7]>* pair2){
//replace sole "return" statement with if-clause to deallocate the non-unique pairs found as well
return( !strcmp(pair1->second, pair2->second) );
}
/*
* Struct used to pass data to the worker threads.
*
* id : Specifies the threads's id assigned by the spawner thread.
*
* my_m : Specifies the # of chains the subtable created must have
*
* t : Specifies the # of links/chain the subtable created must have
*
* prog_v : Refereence to a vector where the thread will report it's progress.
* The element of the vector is indexed by this thread's id.
*
* rainbow : Reference to an allocated subtable the thread has to fill.
*
*/
struct ThreadData{
int my_id;
long my_m;
int my_t;
vector<long>* my_prog_v;
Table_t* my_rainbow;
};
void* worker_thread( void* args );
pthread_mutex_t vector_mutex = PTHREAD_MUTEX_INITIALIZER;
Table_t* generate_tables(long m, int t, int threads, bool post){
long discarded = 0;
float progress = 0;
char cur_pwd[7]; // Both hash and reduction functions take
uint8_t cur_h[32]; // preallocated buffers in arguments and fill them.
char passchar;
char startpoint[7];
startpoint[6] = '\0'; // Startpoint string is a plain old C-string
if(!prng) // Initialize whatever PRNG is used
srand( time(NULL) );
// else
int range_from = 0;
int range_to = 63;
default_random_engine generator( (unsigned int)time(0) );
uniform_int_distribution<int> distr(range_from, range_to);
// Allocate rainbow table structure
Table_t* rainbow = new Table_t();
cout << "Generating tables (m="<<m<<", t="<<t<<")"<< endl;
////////////////////// SINGLE-THREADED ALGORITHM
if(threads==1){
for(long i=0; i<m ; i++){ // For every chain
progress = (float)i / (float)m;
pair<char[7],char[7]>* start_end;
do{
for(int j=0; j<6; j++){
if(!prng) // Start from a random password
passchar = alphabet[ rand() % 64 ];
else
passchar = alphabet[ distr(generator) ];
startpoint[j] = passchar;
}
if(savechain && i<10) outchain << "CHAIN #" << i+1 << endl;
for(int j=1; j<=t-1 ; j++){ // For every link
if(j==1){
if(savechain && i<10) outchain << startpoint;
hashfun( cur_h,(uint8_t*)startpoint,6 ); // (1) HASH link's password
} // or chain's starting point if it's the first
else{
if(savechain && i<10) outchain << cur_pwd;
hashfun( cur_h,(uint8_t*)cur_pwd,6 );
}
if(savechain && i<10){ // Update output file if specified to do so
outchain << " -> ";
for(int k=0; k<32; k++)
outchain << hex << setw(2) << setfill('0') << (int)cur_h[k] << dec ;
outchain << " -> " << endl;
}
redfun( cur_pwd,cur_h,j ); // (2) REDUCE previously computed hash using the correct red-fun
} // and start all over again
if(savechain && i<10) outchain << cur_pwd << '\n' << endl;
start_end = new pair<char[7],char[7]>(); // Finally, create start-end pair,
strcpy( start_end -> first, startpoint);
strcpy( start_end -> second, cur_pwd);
char startpoint_f[7]; // dummy arg- won't be used
if(i<5) break; // don't bother looking if table is still too small
bool found = lookup(start_end->second, rainbow, startpoint_f);
if(!found){
break;
}else{
discarded++;
delete start_end;
}
}while(inplace);
rainbow -> push_back( start_end ); // allocate pair dynamically and store pointer in container
if(v) cout << setw(6) << setprecision(2) << fixed
<< progress*100 << "% complete..." << '\r' << flush;
}
if(v) cout<<"100.00% complete... Done!" << endl;
if(v && inplace){
cout<<discarded<<" chains were discarded in the process" << endl;
}
}else{ ////////////////////// MULTI-THREADED ALGORITHM
long i, sub_m;
int id;
Table_t** subtables = new Table_t*[threads]; // Subtables allocated here, filled in threads
for(id=0 ; id<threads ; id++) subtables[id] = new Table_t();
pthread_t* workers = new pthread_t[threads];
vector<long> progress_bars(threads, 0); // Create a vector where all workers threads
// will report their progress
long m_div = m / threads;
int m_rem = int(m - long(m_div)*long(threads) ); // Calculate std. load per worker
for(id=0 ; id<threads ; id++){ // Workers identified by their index in the array
sub_m = long((id ? m_div : m_div+m_rem)); // First thread takes the rem. rows plus std. load
ThreadData* worker_args = new ThreadData(); // Allocate the struct to pass arguments for worker
worker_args->my_id = id;
worker_args->my_m = sub_m;
worker_args->my_t = t;
worker_args->my_prog_v = &progress_bars;
worker_args->my_rainbow = subtables[id];
if( pthread_create( &(workers[id]), NULL, worker_thread, (void*)worker_args)){
char msg[64];
sprintf(msg, "Pthread_create failed for thread #%d.\nError descriptiion:",id);
perror(msg);
exit(2);
}
}
if(v) cout<<"Spawned thread #0 with "<<m_div+m_rem<<" rows workload"<<endl
<<"Spawned threads #1...#"<<threads-1<<" with "<<m_div<<" rows workload"<<endl;
// After all workers are spawned...
do{ // ...the main thread every once in a while...
sleep(10);
pthread_mutex_lock(&vector_mutex);
long overall_progress=0;
for(id=0; id<threads ; id++) // ...estimates the overall progress (in absolute values)...
overall_progress += long(progress_bars[id]);
pthread_mutex_unlock(&vector_mutex);
float overall_progress_pct = (float)overall_progress / float(m) * 100;
cout << "Overall progress: "<<setw(6) << setprecision(2) << fixed
<<overall_progress_pct<< "% complete..." << '\r' << flush;
if(overall_progress==m) break; // ...and sleeps until it's over.
} while(true);
if(v) cout<<"Overall progress: 100.00% complete... Done!" << endl;
pair<char[7],char[7]>* temp;
if(v)
cout<<"Assembling table from subtables...";
for(id=0 ; id<threads ; id++){ // Then eventually, wait for all workers to exit
pthread_join( workers[id],NULL );
// if(v) cout<<"Thread #"<<id<<" exited"<<endl;
sub_m = (id ? m_div : m_div+m_rem);
for(i=0; i<sub_m; i++){ // And concatenate their subtale to the final table
temp = subtables[id]->front();
subtables[id]->pop_front();
rainbow->push_back( temp );
}
// if(v) cout<<"\tTable now has "<<rainbow->size()<<" chains in total"<<endl;
}
if(v) cout << " Done!" << endl;
delete[] workers;
delete[] subtables;
}
if(v) cout << "Sorting table... " << flush;
rainbow -> sort( pass_comparator ); // And return a sorted table (ASCENDING) , to prepare for binary searches.
if(v) cout << "Done!" << endl;
if(post && !inplace){
if(v) cout << "Post processing table... " << flush;
rainbow -> unique( pass_predicate ); // Remove any chains having non-unique endpoints
long perfect = rainbow->size();
if(v){
cout << "Done!\n\t" << ( (float)m-(float)perfect )/(float)m * 100
<<"% of chains had same endpoints and were removed\n\tNew m="
<<perfect<<endl;
}
}
return rainbow;
}
void* worker_thread( void* args ){
ThreadData* _args = (ThreadData*) args;
int id = _args->my_id;
long my_subm = _args->my_m; // Upon creation, worker thread gets
int t = _args->my_t; // the parameters passed to it
vector<long>* progress_bars = _args->my_prog_v;
Table_t* my_rainbow = _args->my_rainbow;
delete _args; // Then frees the struct
float my_prog =0.0, my_last_prog = 0.0;
char cur_pwd[7];
uint8_t cur_h[32];
char passchar;
char startpoint[7];
startpoint[6] = '\0'; // Startpoint string is a plain old C-string
bool savechain_m = savechain && (id==0); // Chain printing statements will only
// be executed for the first thread
pthread_t rseed = pthread_self(); // Initialize whatever PRNG is used
int range_from = 0;
int range_to = 63;
default_random_engine generator( (unsigned int)time(0)+pthread_self() );
uniform_int_distribution<int> distr(range_from, range_to);
for(long i=0 ; i<my_subm ; i++){
my_prog = (float)i / (float)my_subm;
for(int j=0; j<6; j++){
int rand_idx;
if(!prng){
rand_idx = rand_r( (unsigned int*)&rseed );
passchar = alphabet[ rand_idx % 64 ];
}else{
passchar = alphabet[ distr(generator) ];
}
startpoint[j] = passchar;
}
if(savechain_m && i<10) outchain << "CHAIN #" << i+1 << endl;
for(int j=1; j<=t-1 ; j++){ // For every link
if(j==1){
if(savechain_m && i<10) outchain << startpoint;
hashfun( cur_h,(uint8_t*)startpoint,6 ); // (1) HASH link's password
}else{
if(savechain_m && i<10) outchain << cur_pwd;
hashfun( cur_h,(uint8_t*)cur_pwd,6 ); // or chain's starting point if it's the first
}
if(savechain_m && i<10){ // Update output file if specified to do so
outchain << " -> ";
for(int k=0; k<32; k++)
outchain << hex << setw(2) << setfill('0') << (int)cur_h[k] << dec ;
outchain << " -> " << endl;
}
redfun( cur_pwd,cur_h,j ); // (2) REDUCE previously computed hash using the correct red-fun
} // and start all over again
if(savechain_m && i<10) outchain << cur_pwd << '\n' << endl;
pair<char[7],char[7]>* start_end = new pair<char[7],char[7]>(); // Finally, create start-end pair,
strcpy( start_end -> first, startpoint);
strcpy( start_end -> second, cur_pwd);
my_rainbow -> push_back( start_end ); // allocate pair dynamically and store pointer in container
if(my_prog >= my_last_prog + 0.1){ // After every 10% of work is carried out
pthread_mutex_lock(&vector_mutex);
progress_bars->at(id) = i; // Report the abs. value of work carried out so far
pthread_mutex_unlock(&vector_mutex);
if(v) cout<<"Worker thread #"<<id<<": Now "<<int(my_prog*100)<<"% complete! "<<endl;
my_last_prog = my_prog; // And update the watch
}
}
pthread_mutex_lock(&vector_mutex); // Make a last report before exiting
progress_bars->at(id) = my_subm;
pthread_mutex_unlock(&vector_mutex);
if(v) cout<<"Worker thread #"<<id<<": Finished! "<<endl;
pthread_exit(NULL);
}