【Neepuctf】Crypto部分writeup

Crypto方向

1.RSA

先看一下代码,分析一下逻辑,要想得到flag,不仅要知道n的分解方式,还需要知道e是多少,那么把目标分解为两步,而这两者都和encode(p,q,e)有关。

分析到encode(p,q,e)里面,发现这个函数里面,S是e的模逆,(m*e-1)%(p+1)==0

那么就知道一定要先搞定m和e就可以搞定p了

 

求e的过程

这是明显的padding Oracle攻击可以用富兰克林算法搞定

注意以下脚本并非python脚本而是sagemath脚本,需要在sagemathNotebook中运行

算法代码如下:

 Franklin-Reiter attack against RSA.
# If two messages differ only by a known fixed difference between the two messages
# and are RSA encrypted under the same RSA modulus N
# then it is possible to recover both of them.

# Inputs are modulus, known difference, ciphertext 1, ciphertext2.
# Ciphertext 1 corresponds to smaller of the two plaintexts. (The one without the fixed difference added to it)
def franklinReiter(n,e,r,c1,c2):
    R.<X> = Zmod(n)[]
    f1 = X^e - c1
    f2 = (X + r)^e - c2
    # coefficient 0 = -m, which is what we wanted!
    return Integer(n-(compositeModulusGCD(f1,f2)).coefficients()[0])

  # GCD is not implemented for rings over composite modulus in Sage
  # so we do our own implementation. Its the exact same as standard GCD, but with
  # the polynomials monic representation
def compositeModulusGCD(a, b):
    if(b == 0):
        return a.monic()
    else:
        return compositeModulusGCD(b, a % b)

def CoppersmithShortPadAttack(e,n,C1,C2,eps=1/30):
    """
    Coppersmith's Shortpad attack!
    Figured out from: https://en.wikipedia.org/wiki/Coppersmith's_attack#Coppersmith.E2.80.99s_short-pad_attack
    """
    import binascii
    P.<x,y> = PolynomialRing(ZZ)
    ZmodN = Zmod(n)
    g1 = x^e - C1
    g2 = (x+y)^e - C2
    res = g1.resultant(g2)
    P.<y> = PolynomialRing(ZmodN)
    # Convert Multivariate Polynomial Ring to Univariate Polynomial Ring
    rres = 0
    for i in range(len(res.coefficients())):
        rres += res.coefficients()[i]*(y^(res.exponents()[i][1]))

    diff = rres.small_roots(epsilon=eps)
    recoveredM1 = franklinReiter(n,e,diff[0],C1,C2)
    print(recoveredM1)
    print("Message is the following hex, but potentially missing some zeroes in the binary from the right end")
    print(hex(recoveredM1))
    print("Message is one of:")
    for i in range(8):
        msg = hex(Integer(recoveredM1*pow(2,i)))
        if(len(msg)%2 == 1):
            msg = '0' + msg
        if(msg[:2]=='0x'):
            msg = msg[:2]
        print(binascii.unhexlify(msg))

def testCoppersmithShortPadAttack(eps=1/25):
    from Crypto.PublicKey import RSA
    import random
    import math
    import binascii
    M = "flag{This_Msg_Is_2_1337}"
    M = int(binascii.hexlify(M),16)
    e = 3
    nBitSize =  8192
    key = RSA.generate(nBitSize)
    #Give a bit of room, otherwhise the epsilon has to be tiny, and small roots will take forever
    m = int(math.floor(nBitSize/(e*e))) - 400
    assert (m < nBitSize - len(bin(M)[2:]))
    r1 = random.randint(1,pow(2,m))
    r2 = random.randint(r1,pow(2,m))
    M1 = pow(2,m)*M + r1
    M2 = pow(2,m)*M + r2
    C1 = Integer(pow(M1,e,key.n))
    C2 = Integer(pow(M2,e,key.n))
    CoppersmithShortPadAttack(e,key.n,C1,C2,eps)

def testFranklinReiter():
    p = random_prime(2^512)
    q = random_prime(2^512)
    n = p * q # 1024-bit modulus
    e = 11

    m = randint(0, n) # some message we want to recover
    r = randint(0, n) # random padding

    c1 = pow(m + 0, e, n)
    c2 = pow(m + r, e, n)
    print(m)
    recoveredM = franklinReiter(n,e,r,c1,c2)
    print(recoveredM)
    assert recoveredM==m
    print("They are equal!")
    return True
e=7
n=91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543
c1=10186066785511829759164194803209819172224966119227668638413350199662683285189286077736537161204019147791799351066849945954518642600518196927152098131117402608793752080104402893792812059620726950782670809837962606250674588612783027976958719051829085903720655233948024280118985875980227528403883475592567727892
c2=46182103994299145562022812023438495797686077104477472631494150222038404419414100727667171290098624214113241032861128455086601197239761085752413519627251290509474327611253599768650908336142621210005389246714504358370629231557080301516460985022782887233790302054696967900384601182742759555421864610431428746119
CoppersmithShortPadAttack(e,n,c1,c2,1 / 80)#最后这个参数老是要调一调

在sagemathNotebook上跑出来结果如下:

这里解出来的就是m了

 

得到m后求e就是在1到1000之间爆破了,脚本比较简单,就不贴在这里了。

爆破出来e=71

 

得到m和e之后m*e-1的值也就确定了,而这个数是(p+1)的整数倍,换言之,(p+1)必定是m*e-1的一个因数。

分解m*e-1如下:

写脚本得到m*e-1的因数表,其中减1能被n整除的就是那个p+1,很快就可以爆破出来

p=9177215422297381825967471053981450571672240109122150680398479445336314265061337438267922531089924707618900751022832689463127277685808847706199614701200987

相应的q=n//p

q=10024312244386152630443892832111687314701424463815465976984920410112216871656493234507415778564425602570104608214155934348740925379994140819324233347

366189

整个解密脚本如下:


from Crypto.Util.number import *
from sympy import nextprime
import gmpy2
n=91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543
m=0x277cafa456beba0f916b725a92f28868138cb99a2d457a0d9ea6212bec789d6e87a1152278c5fd21df5f57b2a7c8247aee8709a57764cf769b0b3c5bb29fa3b
e=71
c=78543767285872349029076059073458316000847341792088805258173041942425687239313215276670106926320359777962661495032475004417723103701253550583245518206305422982968675291500865382213182669036827898932991063338163290845510339896689210314509493839746410486257998875782496654704288722251878269643040214139429715671

p=9177215422297381825967471053981450571672240109122150680398479445336314265061337438267922531089924707618900751022832689463127277685808847706199614701200987
q=10024312244386152630443892832111687314701424463815465976984920410112216871656493234507415778564425602570104608214155934348740925379994140819324233347366189
d = gmpy2.invert(e, (p-1)*(q-1))
print(long_to_bytes(gmpy2.powmod(c,d,n)))


#运行得到flag:Neepu{Have-a-g00d-day12138}

 

 

2.中国古代加密

直到这个题出了第三个hint,这题才开始能做了起来。

现在拿不到原题了,只能文字描述解题过程

题目给的第一首词是乾隆年间写的一首词,这首词有它产生的背景,是祝贺一个140岁的古稀老人生日时写下的,前后两片都是指向一个数字--141,结合下面描述说让flag有了头尾,猜想flag的数字部分的头部和尾部应该都是141。

下面一首诗给了对应表之后,反应过来应该是反切码:

 

 

但是这还不够下面的描述中这首诗让flag有声有调,这其实只有声,搜了半天反切码,搜到一条回答让人顿时开悟

知乎上一位答主回答相关问题时提到了音调的识别问题

然后通过排列组合,有多个对应项的:令ch取8,an取10,u取12

就得到了最后的flag

Neepu{141181832310414124141}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Node.js 中的 crypto 是一个内置模块,用于提供加密和解密功能。它支持各种加密算法和操作,包括哈希函数、对称加密和非对称加密。你可以使用 crypto 模块来实现数据的加密、解密、签名和验证等操作。 要使用 crypto 模块,你需要在你的代码中引入它,例如: ```javascript const crypto = require('crypto'); ``` 一些常见的 crypto 操作包括: 1. 哈希函数:crypto 模块提供了多个哈希函数,如 MD5、SHA-1、SHA-256 等。你可以使用这些函数对数据进行哈希处理,生成唯一的摘要。例如: ```javascript const hash = crypto.createHash('sha256'); hash.update('Hello, world!'); const digest = hash.digest('hex'); console.log(digest); // 输出生成的摘要 ``` 2. 对称加密:crypto 模块支持对称加密算法,如 AES、DES、3DES 等。你可以使用这些算法对数据进行加密和解密。例如: ```javascript const cipher = crypto.createCipher('aes192', 'password'); let encrypted = cipher.update('Hello, world!', 'utf8', 'hex'); encrypted += cipher.final('hex'); console.log(encrypted); // 输出加密后的数据 const decipher = crypto.createDecipher('aes192', 'password'); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); console.log(decrypted); // 输出解密后的数据 ``` 3. 非对称加密:crypto 模块还支持非对称加密算法,如 RSA。你可以使用这些算法生成公钥和私钥,进行加密和解密。例如: ```javascript const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); console.log(publicKey); // 输出生成的公钥 console.log(privateKey); // 输出生成的私钥 const encrypted = crypto.publicEncrypt(publicKey, Buffer.from('Hello, world!')); console.log(encrypted.toString('base64')); // 输出加密后的数据 const decrypted = crypto.privateDecrypt(privateKey, encrypted); console.log(decrypted.toString('utf8')); // 输出解密后的数据 ``` 这只是 crypto 模块的一小部分功能,你可以查阅 Node.js 文档以获取更详细的信息和使用方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值