williams+1.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /**
  2. * \file williams+1.c
  3. * \brief An implementation of William's p+1 Attack.
  4. *
  5. * William's attack, published in 1982, describes a factorization algorithm
  6. * based on lucas sequences and Lehmer's theorem.
  7. *
  8. */
  9. #include <stdint.h>
  10. #include <openssl/rsa.h>
  11. #include <openssl/bn.h>
  12. #include "qa/questions/primes.h"
  13. #include "qa/questions/qarith.h"
  14. #include "qa/questions/questions.h"
  15. /**
  16. * \brief Lucas Sequence Multiplier.
  17. *
  18. * Given a pair <Vᵢ, Vᵢ₋₁>, terms of a lucas sequence with parameter τ,
  19. * compute <Vₕᵢ, Vₕᵢ₋₁>
  20. */
  21. void
  22. lucas(BIGNUM *v, BIGNUM *w,
  23. BIGNUM *h, BIGNUM *tau,
  24. BN_CTX *ctx)
  25. {
  26. BIGNUM *vv;
  27. BIGNUM *vw;
  28. BIGNUM *u;
  29. vv = BN_new();
  30. vw = BN_new();
  31. u = BN_new();
  32. for (;
  33. BN_ucmp(h, BN_value_one()) > 0;
  34. BN_rshift1(h, h)) {
  35. if (BN_is_odd(h)) {
  36. BN_sqr(vv, v, ctx);
  37. /* v = τv² - vw - τ */
  38. BN_mul(u, tau, vv, ctx);
  39. BN_mul(vw, v, w, ctx);
  40. BN_sub(u, u, vw);
  41. BN_sub(u, u, tau);
  42. /* w = w² - 2 */
  43. BN_sub(w, vv, BN_value_one());
  44. BN_sub(w, w, BN_value_one());
  45. } else {
  46. BN_sqr(vv, v, ctx);
  47. /* v = v² - 2 */
  48. BN_sub(u, vv, BN_value_one());
  49. BN_sub(u, u, BN_value_one());
  50. /* w = vw - τ */
  51. BN_mul(vw, v, w, ctx);
  52. BN_sub(w, vw, tau);
  53. }
  54. BN_copy(v, u);
  55. }
  56. BN_free(u);
  57. BN_free(vv);
  58. BN_free(vw);
  59. }
  60. /**
  61. * \brief William's p+1 factorization.
  62. *
  63. */
  64. static RSA*
  65. williams_question_ask_rsa(const RSA* rsa)
  66. {
  67. RSA *ret = NULL;
  68. BIGNUM
  69. *v = BN_new(),
  70. *v2 = BN_new(),
  71. *w = BN_new(),
  72. *n = rsa->n,
  73. *tau = BN_new(),
  74. *q = BN_new(),
  75. *p = BN_new(),
  76. *g = BN_new();
  77. int e, k, j, m = 100;
  78. BN_CTX *ctx = BN_CTX_new();
  79. pit_t *pit;
  80. BN_one(g);
  81. BN_one(w); BN_uiadd1(w);
  82. BN_pseudo_rand(tau, 512, 0, 0);
  83. BN_copy(v, tau);
  84. BN_one(q);
  85. for (pit = primes_init();
  86. BN_is_one(g) && primes_next(pit, p);
  87. ) {
  88. e = BN_num_bits(n) / (BN_num_bits(p));
  89. for (k = 0; k < e && BN_is_one(g); k += m) {
  90. for (j = (m > e) ? e : m; j; j--) {
  91. lucas(v, w, p, tau, ctx);
  92. /* XXX. unsafe. */
  93. BN_mod(v, v, n, ctx);
  94. BN_mod(w, w, n, ctx);
  95. /* q = v - 2 */
  96. BN_sub(v2, v, BN_value_one());
  97. BN_sub(v2, v2, BN_value_one());
  98. BN_mod_mul(q, q, v2, n, ctx);
  99. }
  100. /* gcd test */
  101. BN_gcd(g, q, n, ctx);
  102. }
  103. }
  104. if (BN_cmp(g, n))
  105. ret = qa_RSA_recover(rsa, g, ctx);
  106. BN_free(v);
  107. BN_free(v2);
  108. BN_free(w);
  109. BN_free(tau);
  110. BN_free(p);
  111. BN_free(q);
  112. BN_free(g);
  113. prime_iterator_free(pit);
  114. return ret;
  115. }
  116. qa_question_t WilliamsQuestion = {
  117. .name = "p+1",
  118. .pretty_name = "Williams' p+1 factorization",
  119. .ask_rsa = williams_question_ask_rsa
  120. };