【愚公系列】2021年12月 攻防世界-简单题-CRYPTO-011(Normal_RSA)

2021-12-27 08:15:41 浏览数 (1)

文章目录

  • 前言
  • 一、Normal_RSA
  • 二、使用步骤
    • 1.下载附件
    • 2.openssl
    • 3.生成私钥
    • 4.解密文件
  • 总结

前言

题目描述:你和小鱼走啊走走啊走,走到下一个题目一看你又一愣,怎么还是一个数学题啊 小鱼又一笑,hhhh数学在密码学里面很重要的!现在知道吃亏了吧!你哼一声不服气,我知道数学 很重要了!但是工具也很重要的,你看我拿工具把他解出来!你打开电脑折腾了一会还真的把答案 做了出来,小鱼有些吃惊,向你投过来一个赞叹的目光


提示:以下是本篇文章正文内容,下面案例可供参考

一、Normal_RSA

题目链接:https://adworld.xctf.org.cn/task/answer?type=crypto&number=5&grade=0&id=5109&page=1

二、使用步骤

1.下载附件

flag.enc 看后缀enc,分析是一个通过openssl加密后生成的文件

pubkey.pem 应该是一个公钥信息文件

2.openssl

这里我使用kali系统,因为kali系统自带了openssl

先进入openssl 输入 rsa -pubin -text -modulus -in warmup -in pubkey.pem 查看信息

Exponent:指的是RSA中的e Modulus:指的是N,即pq相乘

代码语言:javascript复制
Exponent:00:c2:63:6a:e5:c3:d8:e4:3f:fb:97:ab:09:02:8f:
    1a:ac:6c:0b:f6:cd:3d:70:eb:ca:28:1b:ff:e9:7f:
    be:30:dd
Modulus:65537

先将16进制转为10进制,接着在线质因数分解 分解网址:http://www.factordb.com/

现在已得到的信息:

代码语言:javascript复制
p=275127860351348928173285174381581152299
q=319576316814478949870590164193048041239
e=65537

3.生成私钥

restool脚本代码

代码语言:javascript复制
#!/usr/bin/env python3
import base64
import fractions
import argparse
import random
import sys

try:
    import gmpy
except ImportError as e:
    try:
        import gmpy2 as gmpy
    except ImportError:
        raise e

if sys.version_info >= (3,5):
    from math import gcd
else:
    from fractions import gcd

from pyasn1.codec.der import encoder
from pyasn1.type.univ import Sequence, Integer

PEM_TEMPLATE = b'-----BEGIN RSA PRIVATE KEY-----n%s-----END RSA PRIVATE KEY-----n'
DEFAULT_EXP = 65537


def factor_modulus(n, d, e):
    """
    Efficiently recover non-trivial factors of n
    See: Handbook of Applied Cryptography
    8.2.2 Security of RSA -> (i) Relation to factoring (p.287)
    http://www.cacr.math.uwaterloo.ca/hac/
    """
    t = (e * d - 1)
    s = 0

    while True:
        quotient, remainder = divmod(t, 2)

        if remainder != 0:
            break

        s  = 1
        t = quotient

    found = False

    while not found:
        i = 1
        a = random.randint(1, n-1)

        while i <= s and not found:
            c1 = pow(a, pow(2, i-1, n) * t, n)
            c2 = pow(a, pow(2, i, n) * t, n)

            found = c1 != 1 and c1 != (-1 % n) and c2 == 1

            i  = 1

    p = gcd(c1-1, n)
    q = n // p

    return p, q


class RSA:
    def __init__(self, p=None, q=None, n=None, d=None, e=DEFAULT_EXP):
        """
        Initialize RSA instance using primes (p, q)
        or modulus and private exponent (n, d)
        """

        self.e = e

        if p and q:
            assert gmpy.is_prime(p), 'p is not prime'
            assert gmpy.is_prime(q), 'q is not prime'

            self.p = p
            self.q = q
        elif n and d:
            self.p, self.q = factor_modulus(n, d, e)
        else:
            raise ArgumentError('Either (p, q) or (n, d) must be provided')

        self._calc_values()

    def _calc_values(self):
        self.n = self.p * self.q

        if self.p != self.q:
            phi = (self.p - 1) * (self.q - 1)
        else:
            phi = (self.p ** 2) - self.p

        self.d = gmpy.invert(self.e, phi)

        # CRT-RSA precomputation
        self.dP = self.d % (self.p - 1)
        self.dQ = self.d % (self.q - 1)
        self.qInv = gmpy.invert(self.q, self.p)

    def to_pem(self):
        """
        Return OpenSSL-compatible PEM encoded key
        """
        return PEM_TEMPLATE % base64.encodebytes(self.to_der())

    def to_der(self):
        """
        Return parameters as OpenSSL compatible DER encoded key
        """
        seq = Sequence()

        for idx, x in enumerate([0, self.n, self.e, self.d, self.p, self.q, self.dP, self.dQ, self.qInv]):
            seq.setComponentByPosition(idx, Integer(x))

        return encoder.encode(seq)

    def dump(self, verbose):
        vars = ['n', 'e', 'd', 'p', 'q']

        if verbose:
            vars  = ['dP', 'dQ', 'qInv']

        for v in vars:
            self._dumpvar(v)

    def _dumpvar(self, var):
        val = getattr(self, var)

        def parts(s, l): return 'n'.join(
            [s[i:i l] for i in range(0, len(s), l)])

        if len(str(val)) <= 40:
            print('%s = %d (%#x)n' % (var, val, val))
        else:
            print('%s =' % var)
            print(parts('%x' % val, 80)   'n')


if __name__ == '__main__':
    parser = argparse.ArgumentParser()

    parser.add_argument('-n', help='modulus. format : int or 0xhex', type=lambda x: int(x, 0))
    parser.add_argument('-p', help='first prime number. format : int or 0xhex', type=lambda x: int(x, 0))
    parser.add_argument('-q', help='second prime number. format : int or 0xhex', type=lambda x: int(x, 0))
    parser.add_argument('-d', help='private exponent. format : int or 0xhex',
                        type=lambda x: int(x, 0))
    parser.add_argument('-e', help='public exponent (default: %d). format : int or 0xhex' %
                        DEFAULT_EXP, default=DEFAULT_EXP, type=lambda x: int(x, 0))
    parser.add_argument('-o', '--output', help='output filename')
    parser.add_argument('-f', '--format', help='output format (DER, PEM) (default: PEM)',
                        choices=['DER', 'PEM'], default='PEM')
    parser.add_argument('-v', '--verbose', help='also display CRT-RSA representation',
                        action='store_true', default=False)

    args = parser.parse_args()

    if args.p and args.q:
        print('Using (p, q) to initialise RSA instancen')
        rsa = RSA(p=args.p, q=args.q, e=args.e)
    elif args.n and args.d:
        print('Using (n, d) to initialise RSA instancen')
        rsa = RSA(n=args.n, d=args.d, e=args.e)
    else:
        parser.print_help()
        parser.error('Either (p, q) or (n, d) needs to be specified')

    rsa.dump(args.verbose)

    if args.format == 'PEM':
        data = rsa.to_pem()
    elif args.format == 'DER':
        data = rsa.to_der()

    if args.output:
        print('Saving %s as %s' % (args.format, args.output))

        fp = open(args.output, 'wb')
        fp.write(data)
        fp.close()

    else:
        sys.stdout.buffer.write(data)

这里我使用了如下命令:

代码语言:javascript复制
python3 -m pip install gmpy

安装好需要的模块后输入命令:

代码语言:javascript复制
python3 rsatool.py -f PEM -o private.pem -p 275127860351348928173285174381581152299 -q 319576316814478949870590164193048041239 -e 65537

即可生成private.pem文件

4.解密文件

代码语言:javascript复制
openssl rsautl -decrypt -in flag.enc -inkey private.pem

得到flag:PCTF{256b_i5_m3dium}


总结

  • openssl
  • gmpy

0 人点赞