|
@@ -1,16 +1,54 @@
|
|
|
-#include <openssl/x509.h>
|
|
|
+/**
|
|
|
+ * \file wiener.c
|
|
|
+ *
|
|
|
+ */
|
|
|
#include <math.h>
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
+#include <openssl/x509.h>
|
|
|
+#include <openssl/rsa.h>
|
|
|
+#include <openssl/bn.h>
|
|
|
+
|
|
|
#include "questions.h"
|
|
|
#include "qwiener.h"
|
|
|
|
|
|
-#define EPS 1e-10
|
|
|
|
|
|
-int wiener_question_setup(void) { return 0; }
|
|
|
-int wiener_question_teardown(void) { return 0; }
|
|
|
+cf_t* cf_new(void)
|
|
|
+{
|
|
|
+ cf_t *f;
|
|
|
+
|
|
|
+ f = (cf_t *) malloc(sizeof(cf_t));
|
|
|
+
|
|
|
+ size_t i;
|
|
|
+
|
|
|
+ for (i=0; i!=3; i++) {
|
|
|
+ f->fs[i].h = BN_new();
|
|
|
+ f->fs[i].k = BN_new();
|
|
|
+ }
|
|
|
+ f->a = BN_new();
|
|
|
+ f->x.h = BN_new();
|
|
|
+ f->x.k = BN_new();
|
|
|
+
|
|
|
+ f->ctx = BN_CTX_new();
|
|
|
+
|
|
|
+ return f;
|
|
|
+}
|
|
|
+
|
|
|
+void cf_free(cf_t* f)
|
|
|
+{
|
|
|
+ size_t i;
|
|
|
+
|
|
|
+ for (i=0; i!=3; i++) {
|
|
|
+ BN_free(f->fs[i].h);
|
|
|
+ BN_free(f->fs[i].k);
|
|
|
+ }
|
|
|
+ BN_free(f->a);
|
|
|
+ BN_free(f->x.h);
|
|
|
+ BN_free(f->x.k);
|
|
|
+
|
|
|
+ free(f);
|
|
|
+}
|
|
|
|
|
|
-int wiener_question_test(X509* cert) { return 1; }
|
|
|
|
|
|
/**
|
|
|
* \brief Initialized a continued fraction.
|
|
@@ -32,25 +70,38 @@ int wiener_question_test(X509* cert) { return 1; }
|
|
|
* a₋₁ = 0
|
|
|
* h₋₁ = 1 h₋₂ = 0
|
|
|
* k₋₁ = 0 k₋₂ = 1
|
|
|
+ *
|
|
|
+ * \param f A continued fraction structure. If f is NULL, a new one is
|
|
|
+ * allocated.
|
|
|
+ * \param num Numerator to be used as initial numerator for the fraction to be
|
|
|
+ * approximated.
|
|
|
+ * \param den Denominator to be used as denominator for the fraction to be
|
|
|
+ * approximated.
|
|
|
+ *
|
|
|
+ * \return the continued fraction fiven as input.
|
|
|
*/
|
|
|
-void cfrac_init(struct cf* f, double x)
|
|
|
+cf_t* cf_init(cf_t* f, BIGNUM* num, BIGNUM* den)
|
|
|
{
|
|
|
- f->fs[0].h = 0;
|
|
|
- f->fs[0].k = 1;
|
|
|
+ if (!f) f = cf_new();
|
|
|
|
|
|
- f->fs[1].h = 1;
|
|
|
- f->fs[1].k = 0;
|
|
|
+ BN_zero(f->fs[0].h);
|
|
|
+ BN_one(f->fs[0].k);
|
|
|
+
|
|
|
+ BN_one(f->fs[1].h);
|
|
|
+ BN_zero(f->fs[1].k);
|
|
|
|
|
|
f->i = 2;
|
|
|
- f->x = x;
|
|
|
- f->a = 0;
|
|
|
+ if (!BN_copy(f->x.h, num)) return NULL;
|
|
|
+ if (!BN_copy(f->x.k, den)) return NULL;
|
|
|
+
|
|
|
+ return f;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* \brief Produces the next fraction.
|
|
|
*
|
|
|
- * Each new approximation hᵢ/kᵢ is defined recursively as:
|
|
|
+ * Each new approximation hᵢ/kᵢ is defined rec ursively as:
|
|
|
* hᵢ = aᵢhᵢ₋₁ + hᵢ₋₂
|
|
|
* kᵢ = aᵢkᵢ₋₁ + kᵢ₋₂
|
|
|
* Meanwhile each new aᵢ is simply the integer part of x.
|
|
@@ -60,31 +111,182 @@ void cfrac_init(struct cf* f, double x)
|
|
|
* \return NULL if the previous fraction approximates at its best the number,
|
|
|
* a pointer to the next fraction in the series othw.
|
|
|
*/
|
|
|
-struct fraction* cfrac_next(struct cf* f)
|
|
|
+bigfraction_t* cf_next(cf_t *f)
|
|
|
{
|
|
|
- struct fraction *fs = f->fs;
|
|
|
- struct fraction *ith_fs = &fs[f->i];
|
|
|
+ bigfraction_t *ith_fs = &f->fs[f->i];
|
|
|
+ BIGNUM* rem = BN_new();
|
|
|
|
|
|
- f->a = lrint(floor(f->x));
|
|
|
- if (f->x - f->a < EPS) return NULL;
|
|
|
+ if (BN_is_zero(f->x.h)) return NULL;
|
|
|
+ BN_div(f->a, rem, f->x.h, f->x.k, f->ctx);
|
|
|
|
|
|
- fs[f->i].h = f->a * fs[(f->i-1+3) % 3].h + fs[(f->i-2+3) % 3].h;
|
|
|
- fs[f->i].k = f->a * fs[(f->i-1+3) % 3].k + fs[(f->i-2+3) % 3].k;
|
|
|
+ /* computing hᵢ */
|
|
|
+ if (!BN_mul(f->fs[f->i].h , f->a, f->fs[(f->i-1+3) % 3].h, f->ctx)) goto oh_fuck;
|
|
|
+ if (!BN_add(f->fs[f->i].h, f->fs[f->i].h, f->fs[(f->i-2+3) % 3].h)) goto oh_fuck;
|
|
|
+ /* computing kᵢ */
|
|
|
+ if (!BN_mul(f->fs[f->i].k , f->a, f->fs[(f->i-1+3) % 3].k, f->ctx)) goto oh_fuck;
|
|
|
+ if (!BN_add(f->fs[f->i].k, f->fs[f->i].k, f->fs[(f->i-2+3) % 3].k)) goto oh_fuck;
|
|
|
|
|
|
f->i = (f->i + 1) % 3;
|
|
|
- f->x = 1. / (f->x - f->a);
|
|
|
+ /* update x. */
|
|
|
+ if (!BN_copy(f->x.h, f->x.k)) goto oh_fuck;
|
|
|
+ if (!BN_copy(f->x.k, rem)) goto oh_fuck;
|
|
|
|
|
|
return ith_fs;
|
|
|
+
|
|
|
+ oh_fuck:
|
|
|
+ printf("of fuck!\n");
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
}
|
|
|
|
|
|
+static void BN_int2bn(BIGNUM** a, short int i)
|
|
|
+{
|
|
|
+ if (!*a) *a = BN_new();
|
|
|
+ /* trolololololol. */
|
|
|
+ BN_one(*a);
|
|
|
+ (*a)->d[0] = i;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Square Root for bignums.
|
|
|
+ *
|
|
|
+ */
|
|
|
+int BN_sqrtmod(BIGNUM* dv, BIGNUM* rem, BIGNUM* a, BN_CTX* ctx)
|
|
|
+{
|
|
|
+ char *abn2dec;
|
|
|
+ int g[100];
|
|
|
+ long al;
|
|
|
+ long x = 0, r = 0;
|
|
|
+ int i, j;
|
|
|
+ int d;
|
|
|
+ long y, yn;
|
|
|
+
|
|
|
+ abn2dec = BN_bn2dec(a);
|
|
|
+ sscanf(abn2dec, "%ld", &al);
|
|
|
+
|
|
|
+ r = 0;
|
|
|
+ x = 0;
|
|
|
+ for (i=0; al > 0; i++) {
|
|
|
+ g[i] = al%100;
|
|
|
+ al /= 100;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (j=i-1; j>=0; j--) {
|
|
|
+ r = r*100 + g[j];
|
|
|
+ y = 0;
|
|
|
+ for (d=1; d!=10; d++) {
|
|
|
+ yn = d*(20*x + d);
|
|
|
+ if (yn <= r) y = yn; else break;
|
|
|
+ }
|
|
|
+ r -= y;
|
|
|
+ x = 10*x + d -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ sprintf(abn2dec, "%ld", r);
|
|
|
+ BN_dec2bn(&rem, abn2dec);
|
|
|
+ sprintf(abn2dec, "%ld", x);
|
|
|
+ BN_dec2bn(&dv, abn2dec);
|
|
|
+ OPENSSL_free(abn2dec);
|
|
|
+
|
|
|
+ return BN_is_zero(rem);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * Weiner Attack Implementation
|
|
|
+ */
|
|
|
+
|
|
|
+int wiener_question_setup(void) { return 0; }
|
|
|
+
|
|
|
+int wiener_question_teardown(void) { return 0; }
|
|
|
+
|
|
|
+int wiener_question_test(X509* cert) { return 1; }
|
|
|
+
|
|
|
+
|
|
|
int wiener_question_ask(X509* cert)
|
|
|
{
|
|
|
- return 0;
|
|
|
+ RSA *rsa;
|
|
|
+ /* key data */
|
|
|
+ BIGNUM *n, *e, *d, *phi;
|
|
|
+ BIGNUM *p, *q;
|
|
|
+ /* continued fractions coefficient, and mod */
|
|
|
+ cf_t* cf;
|
|
|
+ bigfraction_t *it;
|
|
|
+ size_t i;
|
|
|
+ BIGNUM *t, *tmp, *rem;
|
|
|
+ /* equation coefficients */
|
|
|
+ BIGNUM *b2, *delta;
|
|
|
+ BN_CTX *ctx;
|
|
|
+
|
|
|
+ rsa = X509_get_pubkey(cert)->pkey.rsa;
|
|
|
+ phi = BN_new();
|
|
|
+ tmp = BN_new();
|
|
|
+ rem = BN_new();
|
|
|
+ n = rsa->n;
|
|
|
+ e = rsa->e;
|
|
|
+ b2 = BN_new();
|
|
|
+ delta = BN_new();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * generate the continued fractions approximating e/N
|
|
|
+ */
|
|
|
+ cf = cf_init(NULL, e, n);
|
|
|
+ ctx = cf->ctx;
|
|
|
+ for (i=0, it = cf_next(cf);
|
|
|
+ // XXX. how many keys shall I test?
|
|
|
+ i!=100 && it;
|
|
|
+ i++, it = cf_next(cf)) {
|
|
|
+ t = it->h;
|
|
|
+ d = it->k;
|
|
|
+ /*
|
|
|
+ * Recovering φ(N) = (ed - 1) / t
|
|
|
+ * TEST1: obviously the couple {t, d} is correct → (ed-1) | t
|
|
|
+ */
|
|
|
+ BN_mul(phi, e, d, cf->ctx);
|
|
|
+ BN_usub(tmp, phi, BN_value_one());
|
|
|
+ BN_div(phi, rem, tmp, t, cf->ctx);
|
|
|
+ if (!BN_is_zero(rem)) continue;
|
|
|
+ // XXX. check, is it possible to fall here, assuming N, e are valid?
|
|
|
+ if (BN_is_odd(phi) && BN_cmp(n, phi) > 0) continue;
|
|
|
+ /*
|
|
|
+ * Recovering p, q
|
|
|
+ * Solving the equation
|
|
|
+ * x² + [N-φ(N)+1]x + N = 0
|
|
|
+ * which, after a few passages, boils down to:
|
|
|
+ * x² + (p+q)x + (pq) = 0
|
|
|
+ *
|
|
|
+ * TEST2: φ(N) is correct → the two roots of x are integers
|
|
|
+ */
|
|
|
+ BN_usub(b2, n, phi);
|
|
|
+ BN_uadd(b2, b2, BN_value_one());
|
|
|
+ BN_rshift(b2, b2, 1);
|
|
|
+ if (BN_is_zero(b2)) continue;
|
|
|
+ /* delta */
|
|
|
+ BN_sqr(tmp, b2, ctx);
|
|
|
+ BN_usub(delta, tmp, n);
|
|
|
+ if (!BN_sqrtmod(tmp, rem, delta, ctx)) continue;
|
|
|
+ /* key found :) */
|
|
|
+ p = BN_new();
|
|
|
+ q = BN_new();
|
|
|
+ BN_usub(p, b2, tmp);
|
|
|
+ BN_uadd(q, b2, tmp);
|
|
|
+ //printf("Primes: %s %s", BN_bn2dec(p), BN_bn2dec(q));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ cf_free(cf);
|
|
|
+ BN_free(rem);
|
|
|
+ BN_free(tmp);
|
|
|
+ BN_free(b2);
|
|
|
+ BN_free(delta);
|
|
|
+ BN_free(phi);
|
|
|
+
|
|
|
+ return i;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-struct qa_question WienerQuestion = {
|
|
|
+qa_question_t WienerQuestion = {
|
|
|
.name = "Wiener",
|
|
|
.setup = wiener_question_setup,
|
|
|
.teardown = wiener_question_teardown,
|