费马小定理的两道ctf题目 [祥云杯2022 little little fermat]

野题

题目来源:B站风二西老师!
链接: B站参考视频

考点:费马小定理 RSA

解题:

题目源代码:

from Crypto.Util.number import *
from random import *
from flag import FLAG

BITS = 1024
flag = bytes_to_long(FLAG)

p = getPrime(BITS)
q = getPrime(BITS)
n = p*q
#得到一个1到n之间的随机整数
g = randint(1,n)
a1 = randint(1,n)
a2 = randint(1,n)

k1 = pow(g,a1*(p-1),n)
k2 = pow(g,a2*(q-1),n)

print("n = %s"%n)
print("k1 = %s"%k1)
print("k2 = %s"%k2)

b1 = randint(1,n)
b2 = randint(1,n)

c1 = (pow(k1,b1,n)*flag)%n
c2 = (pow(k1,b2,n)*flag)%n
#断言语句提示 flag是小于n的
assert flag < n

print("c1 = %d"%c1)
print("c2 = %d"%c2)

'''
n = 9858036118742475059433629759400140149605427966433887001108914046633590983713890376353399251885596714047941627222518567515364827340623251995233155278723954926352575221234142199002389819918370754455018819109203109519495493316781422680537687252828642561153832774006286448224016306003631037545643746379044035822029246823483754854602215035869280453855199171915302879406862793807947285344105991067005185493038370882005106069286893165426035453262949739088328689761676541415552066845538243916687080015277379248062286846119847500455125785281216888979581104100416760176854106890525904804003871967844912776926419778292365918733
k1 = 4961356980843219227031667558158760111429474781353239042846946454889308337426649950562701556812878479419482114480334396560017050901408543482904510839046375272618911899662922000275482705215097956326853000314956770940510205507508883917322367747195211326932972446951696070952604655668087834669239815290687449340666091764203568518066586476150861542456340936303824392273004883320273039066213750777751436497551151274574369325153858390731248298056433816285354182588883715211738843801326831297181947562239993323202961410530072969013398669658073337273085171642258091164822631807295793886169033827781164115751086585872189121242
k2 = 8943660577405892997099415246000964332413663135286363632645590478753346989578467429954062835807609942851365774880023144520942029315601785638267996044694835031239940919206726351387647791985293576677117144309222345482756402074345845506698221273703274410853004407629888264128027446878663894377503365831077629911487977796118893231354280680598325548327444053575447407791091256260091884824630356121390983373431984667887019137026219503921285289004358685317477667095203722657823621429988685962573778350234701781053232256494914398637744373081735647622790113318562356606831868682912936768762749860591989864642992367932846710665
c1 = 4115578106197062017294044310891024039554438131787269391154862526142866937938155870549829472424386226484625850457327387070755337288822640509004443484397234720914851433620556887385729540499953724033259937785600491548446806766462413179765702810698096381537513314758346885921106310631278002150697458246447235914052771405341899822588463120295331632180131956205362147784798497203957828308109092025630961803808101730731656980785388965672073473370194469269645377465298620585379296063436880502566076330461976785816470877632107769103280243111778113065038163250625042092690628478547757779278811188187028242267396799577953511519
c2 = 1069417390392712224013484466911946251479515132512683148923109806683426116132220974153759944203026795479272077929265429391851629949467649257513543604050970026412281764244254971122378729482985044535740328359563865949603944075625096242664299209143911115287867129678168308056632406522013494918385694044348658310785409548526884085469813804712945302487796400392901241763662852123731910949146709219711388725430757562836225353975933990961286601256351973981732004724397292031523206145692402321288085912884435326461626793886145952474077975796841103796283781865005879515976167187625178845457630564285181509041968859289264784559
'''

我们首先关注到flag所在语句 找到和已知变量和前式的关系

k1 = pow(g,a1*(p-1),n)

k1 = ga1*(p-1) %n = (ga1)(p-1) %n

当我们看到一个数的(p-1)次方 自然联想到费马小定理

p是素数,有

a(p-1) % p = 1

ap % p = a % p

所以对k1继续操作

k1 = (ga1)(p-1) + k*n

两边同时模p

k1%p = ((ga1)(p-1) + kn)%p = (ga1)(p-1) %p+ kn%p

因为n=p*q

k1%p = (ga1)(p-1) %p

此时ga1就相当于费马小定理中的a 故k1%p = 1

即有 k1 = 1 + k*p

故k1 - 1 = k * p

并且n = q * p

此时我们发现k1-1和n有公约数p 并且k1 - 1和 n均已知

p = gcd(k1-1,n)

此时得到k1的相关式子 然后看flag的相关

c1 = (pow(k1,b1,n)*flag)%n

c1 = ((k1b1 % n)*flag)%n = ((k1b1 % n)*flag) + k*n

同样两边模p

c1%p = ((k1b1 + k*n)*flag) %p

c1%p = ((k1b1 + k*n)%p*flag%p)

c1%p = ((k1b1%p + k*n%p)*flag%p)

c1%p = (k1b1 %p*flag%p)

c1%p = ((k1%p)b1 %p*flag%p)

由第一部分已知k1%p = 1

所以c1%p=flag%p

又因为断言语句assert flag < n 所以flag一定小于p 模p就等于其本身

故 flag = (c1 % p)

exp:

import gmpy2
import libnum

n = 9858036118742475059433629759400140149605427966433887001108914046633590983713890376353399251885596714047941627222518567515364827340623251995233155278723954926352575221234142199002389819918370754455018819109203109519495493316781422680537687252828642561153832774006286448224016306003631037545643746379044035822029246823483754854602215035869280453855199171915302879406862793807947285344105991067005185493038370882005106069286893165426035453262949739088328689761676541415552066845538243916687080015277379248062286846119847500455125785281216888979581104100416760176854106890525904804003871967844912776926419778292365918733
k1 = 4961356980843219227031667558158760111429474781353239042846946454889308337426649950562701556812878479419482114480334396560017050901408543482904510839046375272618911899662922000275482705215097956326853000314956770940510205507508883917322367747195211326932972446951696070952604655668087834669239815290687449340666091764203568518066586476150861542456340936303824392273004883320273039066213750777751436497551151274574369325153858390731248298056433816285354182588883715211738843801326831297181947562239993323202961410530072969013398669658073337273085171642258091164822631807295793886169033827781164115751086585872189121242
k2 = 8943660577405892997099415246000964332413663135286363632645590478753346989578467429954062835807609942851365774880023144520942029315601785638267996044694835031239940919206726351387647791985293576677117144309222345482756402074345845506698221273703274410853004407629888264128027446878663894377503365831077629911487977796118893231354280680598325548327444053575447407791091256260091884824630356121390983373431984667887019137026219503921285289004358685317477667095203722657823621429988685962573778350234701781053232256494914398637744373081735647622790113318562356606831868682912936768762749860591989864642992367932846710665
c1 = 4115578106197062017294044310891024039554438131787269391154862526142866937938155870549829472424386226484625850457327387070755337288822640509004443484397234720914851433620556887385729540499953724033259937785600491548446806766462413179765702810698096381537513314758346885921106310631278002150697458246447235914052771405341899822588463120295331632180131956205362147784798497203957828308109092025630961803808101730731656980785388965672073473370194469269645377465298620585379296063436880502566076330461976785816470877632107769103280243111778113065038163250625042092690628478547757779278811188187028242267396799577953511519
c2 = 1069417390392712224013484466911946251479515132512683148923109806683426116132220974153759944203026795479272077929265429391851629949467649257513543604050970026412281764244254971122378729482985044535740328359563865949603944075625096242664299209143911115287867129678168308056632406522013494918385694044348658310785409548526884085469813804712945302487796400392901241763662852123731910949146709219711388725430757562836225353975933990961286601256351973981732004724397292031523206145692402321288085912884435326461626793886145952474077975796841103796283781865005879515976167187625178845457630564285181509041968859289264784559

p = gmpy2.gcd(k1 - 1, n)
flag = (int)(c1 % p)
print(libnum.n2s(flag))

#b'flag{f4eccf2b-19d2-4470-8c1d-d50839cb38c7}'

[祥云杯 2022]little little fermat

考点:费马小定理 rsa yafu分解

解题:

题目:

from Crypto.Util.number import *
from random import *
from libnum import *
import gmpy2
from secret import x

flag = b'?????????'
m = bytes_to_long(flag)
def obfuscate(p, k):
    nbit = p.bit_length()
    while True:
        #getRandomRange是指在-1到1的范围中获取一个数 左闭右开 只可能是-1或0
        l1 = [getRandomRange(-1, 1) for _ in '_' * k]
        l2 = [getRandomRange(100, nbit) for _ in '_' * k]
        l3 = [getRandomRange(10, nbit//4) for _ in '_' * k]
        l4 = [getRandomRange(2, 6) for _ in '_' *k]
        #sum是求和函数 把列表中的数值加起来
        A = sum([l1[_] * 2 ** ((l2[_]+l3[_])//l4[_]) for _ in range(0, k)])
        q = p + A
        if isPrime(q) * A != 0:
            return q

p = getPrime(512)
q = obfuscate(p, 5)
e = 65537
n = p*q
print(f'n = {n}')

assert 114514 ** x % p == 1  # 根据断言语句获得x的值
m = m ^ (x**2)
c = pow(m, e, n)
print(f'c = {c}')

'''
n = 141321067325716426375483506915224930097246865960474155069040176356860707435540270911081589751471783519639996589589495877214497196498978453005154272785048418715013714419926299248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393
c = 81368762831358980348757303940178994718818656679774450300533215016117959412236853310026456227434535301960147956843664862777300751319650636299943068620007067063945453310992828498083556205352025638600643137849563080996797888503027153527315524658003251767187427382796451974118362546507788854349086917112114926883
'''

因为q的生成方式 q和p比较接近 而且512位生成的n比较小

本地测试:

from Crypto.Util.number import getPrime, getRandomRange, isPrime


def obfuscate(p, k):
    nbit = p.bit_length()
    while True:
        #getRandomRange是指在-1到1的范围中获取一个数 左闭右开 只可能是-1或0
        l1 = [getRandomRange(-1, 1) for _ in '_' * k]
        l2 = [getRandomRange(100, nbit) for _ in '_' * k]
        l3 = [getRandomRange(10, nbit//4) for _ in '_' * k]
        l4 = [getRandomRange(2, 6) for _ in '_' *k]
        #sum是求和函数 把列表中的数值加起来
        A = sum([l1[_] * 2 ** ((l2[_]+l3[_])//l4[_]) for _ in range(0, k)])
        q = p + A
        if isPrime(q) * A != 0:
            return q
        
p = getPrime(512)
q = obfuscate(p, 5)
print(q.bit_length())
#512

利用yafu工具对n进行分解

D:\qdownload\ctf\crypto>yafu-x64 "factor(141321067325716426375483506915224930097246865960474155069040176356860707435540270911081589751471783519639996589589495877214497196498978453005154272785048418715013714419926299248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393)"


fac: factoring 141321067325716426375483506915224930097246865960474155069040176356860707435540270911081589751471783519639996589589495877214497196498978453005154272785048418715013714419926299248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393
fac: using pretesting plan: normal
fac: no tune info: using qs/gnfs crossover of 95 digits
div: primes less than 10000
fmt: 1000000 iterations
Total factoring time = 0.5614 seconds


***factors found***

P155 = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734648016476153593841839977704512156756634066593725142934001
P155 = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734646483980612727952939084061619889139517526028673988305393

ans = 1

得到p和q

p = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734648016476153593841839977704512156756634066593725142934001
q = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734646483980612727952939084061619889139517526028673988305393

注意嗷!断言语句就是提示!!!

assert 114514 ** x % p == 1  # 根据断言语句获得x的值

这是一个数114514的x次方模p等于1

肯定联想到费马小定理

根据其公式

x = p-1

m = m ^ (x**2)
c = pow(m, e, n)
print(f'c = {c}')

注意rsa解密得到的m不是最终的m 根据异或运算的可逆性对m再进行一次相同的运算即可

exp:

from Crypto.Util.number import getRandomRange
import gmpy2
import libnum

c = 81368762831358980348757303940178994718818656679774450300533215016117959412236853310026456227434535301960147956843664862777300751319650636299943068620007067063945453310992828498083556205352025638600643137849563080996797888503027153527315524658003251767187427382796451974118362546507788854349086917112114926883
p = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734648016476153593841839977704512156756634066593725142934001
q = 11887853772894265642834649929578157180848240939084164222334476057487485972806971092902627112665734646483980612727952939084061619889139517526028673988305393
x = p-1
phi = (p-1)*(q-1)
e = 65537
n = p * q
d = gmpy2.invert(e, phi)
m = pow(c,d,n)
m = (int)(m ^ (x**2))
print(libnum.n2s(m))

#b'flag{I~ju5t_w@nt_30_te11_y0u_how_I_@m_f3ll1ng~}45108#@7++3@79?3328?!!@08#712/+963-60#9-/83#+/1@@=59!/84@?3#4!4=-9542/##'

我是哈皮,祝您每天嗨皮!我们下期再见~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值