破解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