zoukankan      html  css  js  c++  java
  • 记一次RSA破解

             前言:最近好久没更新博客,因为在忙着考雅思还有一直也在看CTF(=_=上个星期玩了一下腾讯的CTF。。。。这酸爽,我一直都认为比赛是最容易提升自己实力的一种途径,上次比赛也发现了自己的不足,继续努力吧少年)今天看了一天的RSA算法。以前在上课的时候,记得老师光讲这个算法就讲了有两堂课。现在在看一下其实也不是很难(别骗自己了=_=)所以写这篇文章记录一下,顺便加深一下自己的印象

    0x1

    首先开始之前我们要补充一下关于RSA的一些常识

    (1) 选择一对不同的、足够大的素数p,q。

    (2)计算n=pq。

    (3)计算f(n)=(p-1)(q-1),同时对p, q严加保密,不让任何人知道。

    (4)找一个与f(n)互质的数e,且1<e<f(n)。

    (5)计算d,使得de≡1 mod f(n)。这个公式也可以表达为(d*e-1)% f(n)=0

         这里要解释一下,≡是数论中表示同余的符号。公式中,≡符号的左边必须和符号右边同余,也就是两边模运算结果相同。

         显而易见,不管f(n)取什么值,符号 右边1 mod f(n)的结果都等于1;符号的左边d与e的乘积做模运算后的结果也必须等于1。

         这就需要计算出d的值,让这个同余等式能够成立。

    (6)公钥KU=(e,n),私钥KR=(d,n)。

    (7)加密时,先将明文变换成0至n-1的一个整数M。若明文较长,可先分割成适当的组,然后再进行交换。设密文为C,

         则加密过程为:C≡M^e(mod n)。

    (8)解密过程为:M≡C^d(mod n)。

    同余:数论中的重要概念。给定一个正整数m,如果两个整数a和b满足(a-b)能够被m整除,即(a-b)/m得到一个整数,那么就称整数a与b对模m同余,

    记作a≡b(mod m)。对模m同余是整数的一个等价关系

    有了上面的RSA基础可以知道RSA中的

    p: 第一个大素数

    q: 第二个大素数

    模数n: n = p*q

    f(n):  (p-1)*(q-1)

    公钥指数e: 与 f(n)互质, 且 1 < e < f(n)

    私钥指数d: 满足e * d ≡ 1 (mod f(n))

    公钥 = {n, e},一般公开

    私钥 = {d, e}

    0x2

    就拿实验吧上面的一个题做这个例子吧因为最近也一直在玩CTF

    http://ctf5.shiyanbar.com/crypto/RSAROLL.txt

    第一行我们看到了这样一组数,直觉告诉我们这个很有可能是公钥(当然也不排除出题师傅直接把私钥给你,这样出题师傅是不是就太可爱了呀)

    {920139713,19}

    根据我们上面补充的知识知道要按照步骤来获取私钥

    (1)    n = 920139713  e =19

    (2)    这时候我们要将整数n分解为两个素数,我们可以使用在线网站直接来获取

    http://www.factordb.com/index.php

    当然我们可以写代码来实现

    如下:def divde(n):

           start =2

            while start < math.sqrt(n):

            if (n%start==0):

                record = start

                print(“大整数可以分解为:”,str(start),str(int(n/base)))

                break

             base+=1

             return (start,int(n/base))

    (3)    经过上面的操作我们可以获得

    p = 18443,q = 49891,f(n) = (p-1)*(q-1)/p,q 是上n分解的两个质数,f(n)是欧拉函数

    (4)    根据我们现在已经获得的条件以及前面补充的RSA知识我们知道只要找到一个满足e * d ≡ 1 (mod f(n)) 这个方程式的d,我们就成功获取的私钥(于是我就自己写了一个函数跑了一下,跑了好长时间仍然没有结果,在我快要放弃的时候我忽然想到了gmpy2,其中有一个神奇的函数)

    (g,d,_) = gcdext(e,f(n))  //不知道为什么是这种格式但是它的效果是与e * d ≡ 1 (mod f(n)) 使用此函数只用了不到一秒的时间就获得了私钥d= 96849619

    (5)    至此成功拿到了私钥,剩下的就剩解密密文

    利用pow(i,d,n))解密密文 //这里的i就是密文,d是我们刚才获取的私钥,n公钥如下图一

     

                                                                                                                       图一获取的是ASCII

    (6)    最后将ASCII转化为相应的字符(这里我用了自己写的一个小脚本工具)

    0x3代码部分

    #-*- coding:utf-8 -*-

    from gmpy2 import *

    from Crypto.Util.number import *

    利用gmpy2中的gcdext()函数 实现的功能是 (d*e-1)% f(n)=0从而获取私钥d

     

    def decrypt():

        flag = ''

        n = 920139713

        e =19

        p = 18443

        q = 49891

        phi_n = (p-1)*(q-1)

        (g,d,_) = gcdext(e,phi_n)  #利用此函数可以获取私钥d值

        print("Privcate key:",str(g),str(d))

        plaintext ="""  704796792

                        752211152

                        274704164

                        18414022

                        368270835

                        483295235

                        263072905

                        459788476

                        483295235

                        459788476

                        663551792

                        475206804

                        459788476

                        428313374

                        475206804

                        459788476

                        425392137

                        704796792

                        458265677

                        341524652

                        483295235

                        534149509

                        425392137

                        428313374

                        425392137

                        341524652

                        458265677

                        263072905

                        483295235

                        828509797

                        341524652

                        425392137

                        475206804

                        428313374

                        483295235

                        475206804

                        459788476

                        306220148

        """

        plaintext = plaintext.split()

        for i in plaintext:

            #利用pow(l,d,n) l的d次方然后取n的余数

            i = int(i)

            print((pow(i,d,n)),end=' ')

    if __name__=='__main__':

       decrypt()

    0x4 后记

    嘻嘻,前段时间女朋友闹着分手,上个星期她又打电话个更说对不起,我们重新和好吧。嗯~ o(* ̄▽ ̄*)o知错就改还是好同志嘛!之前好伤心呢,现在一起都过去了。我会以更加昂扬的斗志生活。后后记+_+ pwn好难呀,不会呀!要多多看看这方面的文章。

  • 相关阅读:
    Watir: 当出现错误提示AutoItX3.dll 没有注册的时候,该怎么处理?
    Watir 能够为你做什么?
    第三章:JMeter 常用的测试元件——线程组
    第二章:JMeter 目录结构分析
    第二章:JMeter 工作原理
    第二章:JMeter 测试结果的名词解释
    第二章:JMeter 中常见 的术语
    第二章:JMeter 的介绍
    第一章:性能测试的常见指标
    第一章:性能测试的常见分类
  • 原文地址:https://www.cnblogs.com/baimaoma/p/8718184.html
Copyright © 2011-2022 走看看