Kaynağa Gözat

Wiener's question working \o/

Adding wiener's attack to questions., with unittests over a fake certificate.
Data has been taken from:
<http://isc08.twisc.org/slides/S5P3_Revisiting_Wiener's_Attack-New_Weak_Keys_in_RSA.pdf>
Michele Orrù 11 yıl önce
ebeveyn
işleme
092d2db451

+ 66 - 0
src/questions/test/test_wiener.c

@@ -1,6 +1,9 @@
 #include <assert.h>
 #include <math.h>
 
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
 #include "questions.h"
 #include "qwiener.h"
 
@@ -67,6 +70,38 @@ void test_cf(void)
 
     it=cf_next(f);
   }
+
+  BN_dec2bn(&x.h, "60728973");
+  BN_dec2bn(&x.k, "160523347");
+  cf_init(f, x.h, x.k);
+  /* 0 */
+  it = cf_next(f);
+  /* 1 / 2 */
+  it = cf_next(f);
+  BN_dec2bn(&expected, "2");
+  assert(BN_is_one(it->h) && !BN_cmp(it->k, expected));
+  /* 1 / 3 */
+  it = cf_next(f);
+  BN_dec2bn(&expected, "3");
+  assert(BN_is_one(it->h) && !BN_cmp(it->k, expected));
+  /* 2 / 5 */
+  it = cf_next(f);
+  BN_dec2bn(&expected, "2");
+  assert(!BN_cmp(expected, it->h));
+  BN_dec2bn(&expected, "5");
+  assert(!BN_cmp(expected, it->k));
+  /* 3 / 8 */
+  it = cf_next(f);
+  BN_dec2bn(&expected, "3");
+  assert(!BN_cmp(expected, it->h));
+  BN_dec2bn(&expected, "8");
+  assert(!BN_cmp(expected, it->k));
+  /* 14/ 37 */
+  it = cf_next(f);
+  BN_dec2bn(&expected, "14");
+  assert(!BN_cmp(expected, it->h));
+  BN_dec2bn(&expected, "37");
+  assert(!BN_cmp(expected, it->k));
 }
 
 
@@ -94,6 +129,18 @@ void test_BN_sqrtmod(void)
   assert(!BN_cmp(root, expected));
   assert(BN_is_zero(rem));
 
+  BN_dec2bn(&a, "5");
+  BN_dec2bn(&expected, "2");
+  BN_sqrtmod(root, rem, a, ctx);
+  assert(!BN_cmp(root, expected));
+  assert(BN_is_one(rem));
+
+  BN_dec2bn(&a, "106929");
+  BN_dec2bn(&expected, "327");
+  BN_sqrtmod(root, rem, a, ctx);
+  assert(BN_is_zero(rem));
+  assert(!BN_cmp(root, expected));
+
   BN_free(root);
   BN_free(rem);
   BN_free(mayzero);
@@ -102,10 +149,29 @@ void test_BN_sqrtmod(void)
   BN_free(expected);
 }
 
+
+void test_wiener(void)
+{
+  X509 *crt;
+  FILE *fp = fopen("test/wiener_test.crt", "r");
+
+  crt = PEM_read_X509(fp, NULL, 0, NULL);
+  if (!crt) {
+    ERR_print_errors();
+    exit(EXIT_FAILURE);
+  }
+
+  WienerQuestion.setup();
+  assert(WienerQuestion.test(crt));
+  assert(WienerQuestion.ask(crt));
+  WienerQuestion.teardown();
+}
+
 int main(int argc, char ** argv)
 {
   test_cf();
   test_BN_sqrtmod();
+  test_wiener();
 
   return 0;
 }

+ 10 - 0
src/questions/test/wiener_test.crt

@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBWzCCAU+gAwIBAgIJAO0CRfiHioXRMAMGAQAwUTELMAkGA1UEBhMCSVQxDjAM
+BgNVBAgMBUl0YWx5MQ8wDQYDVQQHDAZUcmVudG8xITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDAeFw0xMzEyMDEwOTIyMjVaFw0xMzEyMzEwOTIyMjVa
+MFExCzAJBgNVBAYTAklUMQ4wDAYDVQQIDAVJdGFseTEPMA0GA1UEBwwGVHJlbnRv
+MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwIDANBgkqhkiG9w0B
+AQEFAAMPADAMAgQJkWRTAgQDnqaNo1AwTjAdBgNVHQ4EFgQUfCWIgzopf97JPQrs
+h2MlJhPvQy0wHwYDVR0jBBgwFoAUfCWIgzopf97JPQrsh2MlJhPvQy0wDAYDVR0T
+BAUwAwEB/zADBgEAAwEA
+-----END CERTIFICATE-----

+ 69 - 19
src/questions/wiener.c

@@ -138,12 +138,24 @@ bigfraction_t* cf_next(cf_t *f)
   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, *bbn2dec;
+  char *abn2dec;
   int g[100];
-  long al, bl;
+  long al;
   long x = 0, r = 0;
   int i, j;
   int d;
@@ -174,8 +186,6 @@ int BN_sqrtmod(BIGNUM* dv, BIGNUM* rem, BIGNUM* a, BN_CTX* ctx)
   BN_dec2bn(&rem, abn2dec);
   sprintf(abn2dec, "%ld", x);
   BN_dec2bn(&dv, abn2dec);
-
-
   OPENSSL_free(abn2dec);
 
   return BN_is_zero(rem);
@@ -196,42 +206,82 @@ int wiener_question_test(X509* cert) { return 1; }
 int wiener_question_ask(X509* cert)
 {
   RSA *rsa;
+  /* key data */
   BIGNUM *n, *e, *d, *phi;
-  BIGNUM *t, *tmp, *rem;
+  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();
-  rsa = X509_get_pubkey(cert)->pkey.rsa;
   n = rsa->n;
   e = rsa->e;
-
-  cf = cf_init(NULL, n, 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_sub(tmp, phi, BN_value_one());
+    BN_usub(tmp, phi, BN_value_one());
     BN_div(phi, rem, tmp, t, cf->ctx);
-
-    /* test 1: there shall be no rem */
     if (!BN_is_zero(rem)) continue;
-
-    printf("Found? ");
-    BN_print_fp(stdout, e);
-    printf(" ");
-    BN_print_fp(stdout, d);
-    printf(" ");
-    BN_print_fp(stdout, phi);
+    // 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);
-  return 0;
+  BN_free(rem);
+  BN_free(tmp);
+  BN_free(b2);
+  BN_free(delta);
+  BN_free(phi);
+
+  return i;
 }