破解RSA中一些特殊的公开模数N

破解RSA中一些特殊的公开模数N

实验内容:

在公开的N没有被正确的生成时破解RSA。通常在RSA中构成模数N的素数q和p,应该独立生成。如果开发者使用一个随机数R,并选择R附近的两个素数作为q和p,那么这种情况情况下生成的RSA模数N就很容易被破解。

任务1

假设给定合数N和两个彼此很接近的素数q和p,q和p满足以下关系:

令A为q和p的算数平均值,由于p和q都是奇数,所以A一定为整数。观察式子(*)可得
,那么A 可能会非常接近,那么任务1中就有以下信息存在:

q,p,A,的关系如下图:

由于A为整数,我们可以去A = ceil(sqrt(N)),其中ceil()是向上取整的函数。在GMP中mpz_sqrt()默认是向下取整的,那么。
由于p和q在A的附近,我们可以取整数x,满足以下条件。

那么我们可以反推,那么我们根据x和A就可以得到q和p了。

任务1代码实现

  void solve_question_one(const mpz_class& N, mpz_class& q, mpz_class& p){
    //计算ceil(sqrt(N))
    mpz_class A;
    mpz_sqrt(A.get_mpz_t(),N.get_mpz_t());//sqrt向下取整
    A++;

    // N  = A^2 - X^2 = (A - x)(A + X)  ->  x = sqrt(A^2 - N)
    mpz_class AA,x;
    AA = A*A - N;
    mpz_sqrt(x.get_mpz_t(),AA.get_mpz_t());
    q = A - x;
    p = A + x;
}

这里的mpz_sqrt()函数是向下取整的,所以只需要在上加1,就行了。mpz_class 是对mpz_t 的封装,比用c类型mpz_t要好一点,mpz_t类型首先要调用init,其次再使用完毕后还需要调用clear()函数。还有就是mpz_class 转mpz_t可以使用get_mpz_t()函数,也可以使用(mpz_t)map_class对象,进行类型转换。这里给出mpz_class 的类的定义:

/**************** mpq_class -- wrapper for mpq_t ****************/

template <>
class __gmp_expr<mpq_t, mpq_t>
{
private:
  typedef mpq_t value_type;
  value_type mp;
  // Helper functions used for all arithmetic types
  void assign_ui(unsigned long l) { mpq_set_ui(mp, l, 1); }
  void assign_si(signed long l)
  {
    if (__GMPXX_CONSTANT_TRUE(l >= 0))
      assign_ui(l);
    else
      mpq_set_si(mp, l, 1);
  }
  void assign_d (double d)        { mpq_set_d (mp, d); }
  void init_ui(unsigned long l) { mpq_init(mp); get_num() = l; }
  void init_si(signed long l) { mpq_init(mp); get_num() = l; }
  void init_d (double d)  { mpq_init(mp); assign_d (d); }
public:
  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
  void canonicalize() { mpq_canonicalize(mp); }
  // constructors and destructor
  __gmp_expr() { mpq_init(mp); }
  __gmp_expr(const __gmp_expr &q)
  {
    mpz_init_set(mpq_numref(mp), mpq_numref(q.mp));
    mpz_init_set(mpq_denref(mp), mpq_denref(q.mp));
  }
#if __GMPXX_USE_CXX11
  __gmp_expr(__gmp_expr &&q)
  { *mp = *q.mp; mpq_init(q.mp); }
#endif
  template <class T>
  __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
  { mpq_init(mp); __gmp_set_expr(mp, expr); }
  template <class T>
  __gmp_expr(const __gmp_expr<mpq_t, T> &expr)
  { mpq_init(mp); __gmp_set_expr(mp, expr); }
  template <class T, class U>
  explicit __gmp_expr(const __gmp_expr<T, U> &expr)
  { mpq_init(mp); __gmp_set_expr(mp, expr); }
  __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
  explicit __gmp_expr(const char *s, int base = 0)
  {
    mpq_init (mp);
    // If s is the literal 0, we meant to call another constructor.
    // If s just happens to evaluate to 0, we would crash, so whatever.
    if (s == 0)
      {
  // Don't turn mpq_class(0,0) into 0
  mpz_set_si(mpq_denref(mp), base);
      }
    else if (mpq_set_str(mp, s, base) != 0)
      {
        mpq_clear (mp);
        throw std::invalid_argument ("mpq_set_str");
      }
  }
  explicit __gmp_expr(const std::string &s, int base = 0)
  {
    mpq_init(mp);
    if (mpq_set_str (mp, s.c_str(), base) != 0)
      {
        mpq_clear (mp);
        throw std::invalid_argument ("mpq_set_str");
      }
  }
  explicit __gmp_expr(mpq_srcptr q)
  {
    mpz_init_set(mpq_numref(mp), mpq_numref(q));
    mpz_init_set(mpq_denref(mp), mpq_denref(q));
  }
  __gmp_expr(const mpz_class &num, const mpz_class &den)
  {
    mpz_init_set(mpq_numref(mp), num.get_mpz_t());
    mpz_init_set(mpq_denref(mp), den.get_mpz_t());
  }
  ~__gmp_expr() { mpq_clear(mp); }
  void swap(__gmp_expr& q) __GMPXX_NOEXCEPT { std::swap(*mp, *q.mp); }
  // assignment operators
  __gmp_expr & operator=(const __gmp_expr &q)
  { mpq_set(mp, q.mp); return *this; }
#if __GMPXX_USE_CXX11
  __gmp_expr & operator=(__gmp_expr &&q) noexcept
  { swap(q); return *this; }
  __gmp_expr & operator=(mpz_class &&z) noexcept
  { get_num() = std::move(z); get_den() = 1u; return *this; }
#endif
  template <class T, class U>
  __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
  { __gmp_set_expr(mp, expr); return *this; }
  __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
  __gmp_expr & operator=(const char *s)
  {
    if (mpq_set_str (mp, s, 0) != 0)
      throw std::invalid_argument ("mpq_set_str");
    return *this;
  }
  __gmp_expr & operator=(const std::string &s)
  {
    if (mpq_set_str(mp, s.c_str(), 0) != 0)
      throw std::invalid_argument ("mpq_set_str");
    return *this;
  }
  // string input/output functions
  int set_str(const char *s, int base)
  { return mpq_set_str(mp, s, base); }
  int set_str(const std::string &s, int base)
  { return mpq_set_str(mp, s.c_str(), base); }
  std::string get_str(int base = 10) const
  {
    __gmp_alloc_cstring temp(mpq_get_str(0, base, mp));
    return std::string(temp.str);
  }
  // conversion functions
  // casting a reference to an mpz_t to mpz_class & is a dirty hack,
  // but works because the internal representation of mpz_class is
  // exactly an mpz_t
  const mpz_class & get_num() const
  { return reinterpret_cast<const mpz_class &>(*mpq_numref(mp)); }
  mpz_class & get_num()
  { return reinterpret_cast<mpz_class &>(*mpq_numref(mp)); }
  const mpz_class & get_den() const
  { return reinterpret_cast<const mpz_class &>(*mpq_denref(mp)); }
  mpz_class & get_den()
  { return reinterpret_cast<mpz_class &>(*mpq_denref(mp)); }
  mpq_srcptr __get_mp() const { return mp; }
  mpq_ptr __get_mp() { return mp; }
  mpq_srcptr get_mpq_t() const { return mp; }
  mpq_ptr get_mpq_t() { return mp; }
  mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); }
  mpz_ptr get_num_mpz_t() { return mpq_numref(mp); }
  mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); }
  mpz_ptr get_den_mpz_t() { return mpq_denref(mp); }
  double get_d() const { return mpq_get_d(mp); }
#if __GMPXX_USE_CXX11
  explicit operator bool() const { return mpq_numref(mp)->_mp_size != 0; }
#endif
  // compound assignments
  __GMP_DECLARE_COMPOUND_OPERATOR(operator+=)
  __GMP_DECLARE_COMPOUND_OPERATOR(operator-=)
  __GMP_DECLARE_COMPOUND_OPERATOR(operator*=)
  __GMP_DECLARE_COMPOUND_OPERATOR(operator/=)
  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=)
  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=)
  __GMP_DECLARE_INCREMENT_OPERATOR(operator++)
  __GMP_DECLARE_INCREMENT_OPERATOR(operator--)
};

任务2

模数N是q和p的乘积,满足条件,在的情况下可以从向上搜索,求解q和p。

任务2代码实现

void solve_question_two(const mpz_class& N,mpz_class& q, mpz_class& p)
{
    //模数N 是两个素数q,p 的乘积,满足|p-q| < 2^11 *N^{1/4}

    mpz_class A;
    mpz_sqrt(A.get_mpz_t(),N.get_mpz_t());//sqrt向下取整
    // 从sqrt(N) 向上寻找A 
    int i_max = pow(2,19);
    mpz_class x;
    for(int i = 1 ; i < i_max;i++ ){
        A ++;
        mpz_class temp = A*A - N;
        mpz_sqrt(x.get_mpz_t(),temp.get_mpz_t());
        q = A - x;p = A + x;
        if(q*p == N){
            cout<<"此时A = "<<A<<endl;
            break;
        }
    }
}

代码的意思就相隔很近,从向上暴力破解,直到搜索到满足条件,就终止循环。

实验结果

代码地址

https://github.com/cyssmile/cplus/blob/master/密码学实验部分/solve_RSA_N.cpp

编译命令自己修改

 D:\cygwin64\bin\g++.exe d:\win_worksapce\solve_RSA_N.cpp -o d:\win_worksapce\main.exe  -lgmpxx -lgmp 
posted @ 2020-06-09 19:15  cyssmile  阅读(1249)  评论(0编辑  收藏  举报