HGAME Crypto WEEK1-4

HGAME Crypto

WEEK1

Dancing Line

略了(

Easy RSA

from Crypto.Util.number import*
r=[(12433, 149, 197, 104), (8147, 131, 167, 6633), (10687, 211, 197, 35594), (19681, 131, 211, 15710), (33577, 251, 211, 38798), (30241, 157, 251, 35973), (293, 211, 157, 31548), (26459, 179, 149, 4778), (27479, 149, 223, 32728), (9029, 223, 137, 20696), (4649, 149, 151, 13418), (11783, 223, 251, 14239), (13537, 179, 137, 11702), (3835, 167, 139, 20051), (30983, 149, 227, 23928), (17581, 157, 131, 5855), (35381, 223, 179, 37774), (2357, 151, 223, 1849), (22649, 211, 229, 7348), (1151, 179, 223, 17982), (8431, 251, 163, 30226), (38501, 193, 211, 30559), (14549, 211, 151, 21143), (24781, 239, 241, 45604), (8051, 179, 131, 7994), (863, 181, 131, 11493), (1117, 239, 157, 12579), (7561, 149, 199, 8960), (19813, 239, 229, 53463), (4943, 131, 157, 14606), (29077, 191, 181, 33446), (18583, 211, 163, 31800), (30643, 173, 191, 27293), (11617, 223, 251, 13448), (19051, 191, 151, 21676), (18367, 179, 157, 14139), (18861, 149, 191, 5139), (9581, 211, 193, 25595)]
flag=''
for i in r:
    e,p,q,c=i
    phi=(p-1)*(q-1)
    d=inverse(e,phi)
    m=pow(c,d,p*q)
    flag+=chr(m)
print(flag)

输出:hgame{L00ks_l1ke_y0u've_mastered_RS4!}

Matryoshka

略了(摩斯密码还要先逆序真ex

English Novel

根据文件大小找到字节数和格式基本相同的文件

b=" if Rqesysz', bvjv bjxsh szr uaaxivjd zlcdbc mnirb."
a=" of England', with which the meetings always ended."
k=[]
for i in range(len(a)):
	if(a[i]<='z' and a[i]>='a') or (a[i]<='Z' and a[i]>='A'):
		x=ord(b[i])-ord(a[i])+26
		x%=26
		k.append(x)
	else:
		k.append(-1)
print(k)

然后得到一串key,但要注意的是在这串key中是存在一些位置是标点或空格,这些地方需要再多找几个对应明文密文补全

补全后,把加密脚本改一改就是解密脚本了:

k=[16, 20, 0, 10, 13, 3, 24, 7, 24, 5, 22, 17, 17, 18, 5, 13, 16, 14, 9, 5, 2, 15, 16, 0, 20, 25, 18, 13, 7, 8, 22, 22, 4, 0, 8, 3, 11, 23, 25, 0, 6, 3, 3, 10, 2, 8, 0, 5, 13, 24, 0]
def decrypt(data, key):
    assert len(data) <= len(key)
    result = ""
    for i in range(len(data)):
        if data[i].isupper():
            result += chr((ord(data[i]) - ord('A') - key[i]) % 26 + ord('A'))
        elif data[i].islower():
            result += chr((ord(data[i]) - ord('a') - key[i]) % 26 + ord('a'))
        else:
            result += data[i]
    return result
f="xaawr{B0_d0l_cs0m_'Pp0mn-odn1vpabt_deqzcq'?}"
f=decrypt(f,k)
print(f)

输出:hgame{D0_y0u_kn0w_'Kn0wn-pla1ntext_attack'?}

WEEK2

RSA Attack

factordb分解\(n\)得到\(p,q\)

然后就没有然后了......

Chinese Character Encryption

题目附件给出了这么奇奇怪怪的一大组汉字

陉萏俦蘭貑謠祥冄剏髯簧凰蕆秉僦笆鼣雔耿睺渺仦殣櫤鄽偟壮褃劳充迧蝔镁樷萾懴雈踺猳钔緲螩蝒醢徣纒漐
瑢蚇魫灡麚踲儣硖剏竊蝗鍠綳瑊臼渣璎賍併沚坕昉進糧玤黄羌顺瓜茺笻飯爦撵階檦嚀箭瓮佩覫螩幒魛蘲壥赞
屝疳蹮髕魛溫嫜贪怆贴垯艎睁瑊搇皶费铦蛟词撚鶭哉粱缠鐄鏘瞬颲浺訦笴蠻鯍嵅汴繕籢虥厨尦螩漖猆尻蝉嬼
梥粓賍襴餥磘鞤珃剙肰脌癀烝鈵溔騢榕皗鲠妣婃瓬脃絳蝉垯锖琻酹榋蔯晗鳗糆梒纲巩翴藵櫥冡螩鐐腵褦缠毐
孾騡鍚幱鳵飖囆騢刱篋凰広惼柄冊癱琜讅绠彽鍴猠擾醬涱锽崈糉铹茺貥稭檈徖烗玣彋諓佳捫鸫螩専猳纝爂丨
鑍诞忺萲輚遙蠆擹瀮箧簧徨潮餅雯巹橰栦嬌躁詗昉噘梁涱穔玱幮悬珫殿邗鵷昸勧堈纮廉脡矝懐螩緜摛水飙趀
韺坩鸉媗烶藈傽菫刱垖餭簧谠姦芠冄褣酬鲛麏埬豋嫩樑谗瑝獇諙噻憃睘牶峠矒街辫赡蒗誜狍溕螩瑼攡輫鄽穩
烾搼諹玫摛伅粻皰剙槊丄獚謿戋嘊礟废伡鐎瞹腫仦壣椋纏凰輲闹髝川辰蓪歄塚煯牨畋硁矰画鯟螩忠鴇錻棎贊
罂钾忺粩侙磘橳黜剏叛緔艎罺豜蒥厙来甠鳯篌詗忄瓫櫤飊楻壮鏙寃嘃霃蜬擁篎萾圵碵莾齝鬊稉螩嘂塰皜怊讚
来煋先郿緥渰幫琡剙獸広蟥巅麉廏缀馠屳蓈睺賨覴涛弜账煌状話煭沖迸萤悬檬崡剛槎踐瓣澅塚螩衳瓂顥猋哥
虇猩菜鱝寶错鞤巹瀮髯鷬脌嘣柄舅烚翉棾骾嫒巑俵睵辌扙遑焋磪頪憃麎塋瓜稉飰鼦歚饤浃巾賩螩鐐裶曍飇戈
犬悱黥諠媸笉璋欇瀮壽鍠犷骣炳嘊癱婴菤锒問麺舫鱗袶帳喤猐蕏痨珫塵眹瞒氋碝錶狯蝊葢舿碾螩颛侹徣欩瓒
蒈襙砗瀾漑淛橳蔎怆貼垯喤谠殱姲懾嵘蛼勆裹泾驓婒糧蜯锽状鬊噻摏窮傇雍秒筨韂鳤籨犌舜礞螩胮輚痛婵濽
壖騂羘礨甕汣獐侭剙鑻墶媓筝鰹暥厍雴躚鹪鄙晶昉褷酱涱犷壵慛跒忡電皆癕泾軟剛慏詾扉爮囨螩刣曹庎磛鿔
熔卶鰑譋瞝嚲蠆疤剙三墶煌徰柄钩饶孆暹焨謴秒蒧晋櫤纏諻牄鶵涙茺煢瀯浖麫鋡蟀掽鑬齝津簐螩轎譄镭鏢刎
畎巏臇鹛緥謡蕂黜剏犙獚繨徰艱驑谨曧覾稂鹨媏嚸繖辌讒癀锖婳磱瑏塣膼哰篎炵堽碰鲢鵄幮京螩蟟槪戒颷虐

开始以为是OTP

但经过了无数尝试并不是

直到给出hint:根据pycrypto包进行加密

后面就简单了

根据pycrypto包把汉字转换成相应拼音然后将拼音每一位都转换成ASCII码相加再模128,之后再通过ASCII码转换成字符

因为每一行都是对应的不同加密,那只要取第一行就可以了

from pypinyin import lazy_pinyin, Style
a='陉萏俦蘭貑謠祥冄剏髯簧凰蕆秉僦笆鼣雔耿睺渺仦殣櫤鄽偟壮褃劳充迧蝔镁樷萾懴雈踺猳钔緲螩蝒醢徣纒漐'
flag=""
style = Style.TONE3
py=(lazy_pinyin(a, style=style))
for pinyin in py:
	sum=0
	for c in pinyin:
		sum+=ord(c)
	flag+=chr(sum%128)
print(flag)

RSA Attack 2

一共有三部份

part1

两个模数使用了相同的素数\(q\),这时的我们可以通过\(gcd(n1,n2)\)得到\(q\)

part2

我们发现此处采用了较小模数\(e = 7\),所以对\(k\)进行爆破(然而\(k=0\)不需要爆破)

直接\(iroot(c,7)\)得到明文

part3

共模攻击,套个脚本走人(逃

三段明文合起来就是\(flag\)

The Password Plus Pro Max Ultra

翻了翻去年的wp找到了一道题目The Password,显然这题是去年的那道魔改了一番。

根据去年的思路,将每次随机的几个数构造成相应的\(GF(2)\)内的变换矩阵然后取逆,再与密文进行运算得到明文

SageMath进行矩阵的运算(代码嫖了hx

D=[2656224875120172108 , [8, 35], 
1261711348908201279 , [19, 29, 30, 45], 
18219282869614004824 , [6, 16, 18, 21, 44, 55], 
15279054981769814589 , [10, 26, 30, 46, 51, 54, 58, 63], 
7966355346882200701 , [5, 13, 25, 29, 37, 39, 43, 52, 53, 59], 
5641592208539483808 , [1, 26, 31, 39, 40, 41, 43, 45, 49, 52, 54, 62], 
1502927090219059154 , [8, 12, 19, 20, 30, 32, 34, 40, 41, 45, 46, 49, 55, 58], 
3996223120734273799 , [2, 3, 5, 6, 8, 10, 15, 19, 26, 27, 33, 40, 42, 47, 52, 61], 
18295033054788808618 , [1, 16, 17, 27, 28, 30, 32, 36, 37, 38, 39, 48, 49, 51, 55, 57, 59, 62], 
18126228466291248047 , [5, 11, 12, 20, 22, 23, 25, 27, 31, 32, 33, 37, 44, 45, 49, 52, 53, 59, 61, 62], 
9413762634844369954 , [2, 7, 10, 12, 18, 19, 20, 22, 26, 29, 33, 34, 38, 40, 41, 45, 46, 51, 54, 56, 57, 60], 
8964324149921197550 , [3, 4, 5, 9, 12, 13, 18, 19, 21, 23, 24, 25, 30, 33, 34, 35, 37, 39, 43, 44, 46, 49, 50, 53], 
6962485320551449848 , [1, 3, 6, 7, 10, 11, 13, 14, 23, 27, 32, 33, 35, 37, 39, 41, 46, 48, 49, 50, 51, 53, 54, 56, 58, 62], 
]
def movematrix(n):
    n=(n+64)%64
    E=[[0 for i in range(64)] for j in range(64)]
    for i in range(64):
        E[i][i]=1
    M=[]
    for i in range(64):
        M.append(E[(i+n)%64])
    return matrix(GF(2),M)
def decrypt(C,L):
    M=[[0 for i in range(64)] for j in range(64)]
    for i in range(64):
        M[i][i]=1
    M=matrix(GF(2),M)
    for i in L:
        M+=movematrix(i)
    v=[]
    for i in range(64):
        v.append(1 if C&(1<<i)!=0 else 0)
    v=vector(GF(2),v)
    v=v*(M**-1)
    M=0
    v=vector(ZZ,v)
    for i in range(64):
        M+=v[i]*(1<<i)
    return M

f=[]
for i in range(13):
    f.append(decrypt(D[2*i],D[2*i+1]))
print(f)

然后再回到python搞出flag

from Crypto.Util.number import*
f=[7523088825027614799, 8249559255509004879, 7817203812207576402, 6423086823251996526, 3045112109557445445, 2616398305166447721, 5723558670868965747, 2697452167550086213, 5639438386741921138, 4991160919341822841, 5570219726961468223, 7308888588581631049, 5197437]
flag=b""
for i in f:
	flag+=long_to_bytes(i)
print(flag)

下次一定好好撸脚本(555

WEEK3

Block Cipher

读完代码知道,该加密是将\(flag\)分为\(8\)个一组,第一组与\(key\)\(iv\)异或,之后每组与上一组的结果和\(key\)异或。

读代码读了好久解题只要一分钟(

import operator

def xor(a, b):
    assert len(a) == len(b)
    print(bytes(map(operator.xor, a, b)))
    return bytes(map(operator.xor, a, b))

flag=b''
iv = b'Up\x14\x98r\x14%\xb9'
key = b'\r\xe8\xb86\x9c33^'

parts = [b'0\xff\xcd\xc3\x8b\\T\x8b', b'RT\x1e\x89t&\x17\xbd', b'\x1a\xee\x8d\xd6\x9b>w\x8c', b'9CT\xb3^pF\xd0']
parts[3]=reduce(xor,[parts[2],parts[3],key])
parts[2]=reduce(xor,[parts[1],parts[2],key])
parts[1]=reduce(xor,[parts[0],parts[1],key])
parts[0]=reduce(xor,[parts[0],iv,key])
for i in parts:
	flag+=i
print(flag)

因为就这么四组也就懒得循环了(

Multi Prime RSA

本题的考点在于多素数乘幂下\(φ(n)\)的求法

\(n=p_1^{k_1}p_2^{k_2}...p_r^{k_r}\)

\(φ(n)=\prod_{i=1}^rp_i^{k_i-1}(p_i-1)\)

from Crypto.Util.number import*

p = 109056753224725357860050862987465749131702509174531265860789564184166504627089
q = 64871884070495743485110397060920534297122908609816622599229579748089451488127
r = 73817195552029165561107245309535744382442021553254903166961729774806232509583
s = 89907870347457693114161779597928900080173728317019344960807644151097370118553
n = 337945247991531188630780631650822497552908401425959508214145019590891175999570651678385514599227649321033438265588883204645721459926338248032512615537333971869461679586403649697114789385472197685140603238299768873935137939123021910982793481655218061907401584383081422244812725080939394854989735528833013780919908024635812696998644603525843637686545709789908672408993923182946718279531020289767042649725545073526307769817097790005360720650079676982379162926484355121626302801800589993422729725583400678081766553017405965706770238634252836827793877622715474210575752508172785712202444441372140501379422725172250199713113954442223362073485143579617841236442644760494913432967541691532709842303408702693199269606594116690052170245340072114122287646793344327315326489574192325790848798131621842606487734721409882742631176999703502149639410263361145441889337623403361569958342141903891414217371443118527025041591219747780100510414268546884029077010164415049298406632069845430841542680166802473749172801804659277821899576403669845353379213803866969800665351300325701817179936198902427032684058452719607840314873315299975603264092020097224735237221994922702705781103002327285724125001893421030923788361576161461965707958695720464547129911053732747399113017747456439027947305796290572816318795181398935020951025833913
e = 65537
c = 281020926647419736778465777714512241989738235339105762863874725870511725155101862585192241287617168165290485944476735304459717602798728005687755713662466866091315959960168862035396245078850168822145228676116894754613436735897122137945552880864031115366493898382809812977280234389519365119627504653135151731589924405933589175425427189436855517194951589952822691774400942764910734054237756669945324833759799471068481769516338068810710333940167779043544371586185132920304774984746129764220081092726473696111126293966890901487735046101991609292612206984184161394385767762455321150541601949740631911175736268756408775307673610842645555513631617648877296855194327486811545670357137463942744122553468603244298691801028147147418563982169678640270746871085722092365159546820433098926679284504740402248142173715649451061037156261913601096905601577932894877435316535261789072594174871292814951406337447799051502635390866434813419165738873787323716033378045850292413169255965421404580559241351577058726176436504950558398769061998430771982995850759810867299728407860522399699076192754977454139708618158667289120827143703464056583125568576691058753072898162981956883451252542611323974071518397220203389962420073122776649094369816178685947397943358134020598211306649724455966463885765977564934172273334309312046278116760547

phi=p*(p-1)*q**2*(q-1)*r**4*(r-1)*s**6*(s-1)
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))

RSA Attack 3

\(d\)很小\(e\)很大猜测是\(Wiener's attack\)

直接上脚本:

import gmpy2
from Crypto.Util.number import*
def transform(x,y):       #使用辗转相处将分数 x/y 转为连分数的形式
    res=[]
    while y:
        res.append(x//y)
        x,y=y,x%y
    return res
    
def continued_fraction(sub_res):
    numerator,denominator=1,0
    for i in sub_res[::-1]:      #从sublist的后面往前循环
        denominator,numerator=numerator,i*numerator+denominator
    return denominator,numerator   #得到渐进分数的分母和分子,并返回

    
#求解每个渐进分数
def sub_fraction(x,y):
    res=transform(x,y)
    res=list(map(continued_fraction,(res[0:i] for i in range(1,len(res)))))  #将连分数的结果逐一截取以求渐进分数
    return res

def get_pq(a,b,c):      #由p+q和pq的值通过维达定理来求解p和q
    par=gmpy2.isqrt(b*b-4*a*c)   #由上述可得,开根号一定是整数,因为有解
    x1,x2=(-b+par)//(2*a),(-b-par)//(2*a)
    return x1,x2

def wienerAttack(e,n):
    for (d,k) in sub_fraction(e,n):  #用一个for循环来注意试探e/n的连续函数的渐进分数,直到找到一个满足条件的渐进分数
        if k==0:                     #可能会出现连分数的第一个为0的情况,排除
            continue
        if (e*d-1)%k!=0:             #ed=1 (mod φ(n)) 因此如果找到了d的话,(ed-1)会整除φ(n),也就是存在k使得(e*d-1)//k=φ(n)
            continue
        
        phi=(e*d-1)//k               #这个结果就是 φ(n)
        px,qy=get_pq(1,n-phi+1,n)
        if px*qy==n:
            p,q=abs(int(px)),abs(int(qy))     #可能会得到两个负数,负负得正未尝不会出现
            d=gmpy2.invert(e,(p-1)*(q-1))     #求ed=1 (mod  φ(n))的结果,也就是e关于 φ(n)的乘法逆元d
            return d
    print("该方法不适用")
    
    
e = 77310199867448677782081572109343472783781135641712597643597122591443011229091533516758925238949755491395489408922437493670252550920826641442189683907973926843505436730014899918587477913032286153545247063493885982941194996251799882984145155733050069564485120660716110828110738784644223519725613280140006783618393995138076030616463398284819550627612102010214315235269945251741407899692274978642663650687157736417831290404871181902463904311095448368498432147292938825418930527188720696497596867575843476810225152659244529481480993843168383016583068747733118703000287423374094051895724494193455175131120243097065270804457787026492578916584536863548445813916819417857064037664101684455000184987531252344582899589746272173970083733130106407810619258077266603898529285634495710846838011858287024329514491058790557305041389614650730267774482954666726949886313386881066593946789460028399523245777171320319444673551268379126203862576627540177888290265714418064334752499940587750374552330008143708562065940245637685833371348603338834447212248648869514585047871442060412622164276894766238383894693759347590977926306581080390685360615407766600573527565016914830132066428454738135380178959590692145577418811677639050929791996313180297924833690095
n = 507419170088344932990702256911694788408493968749527614421614568612944144764889717229444020813658893362983714454159980719026366361318789415279417172858536381938870379267670180128174798344744371725609827872339512302232610590888649555446972990419313445687852636305518801236132032618350847705234643521557851434711389664130274468354405273873218264222293858509477860634889001898462547712800153111774564939279190835857445378261920532206352364005840238252284065587291779196975457288580812526597185332036342330147250312262816994625317482869849388424397437470502449815132000588425028055964432298176942124697105509057090546600330760364385753313923003549670107599757996810939165300581847068233156887269181096893089415302163770884312255957584660964506028002922164767453287973102961910781312351686488047510932997937700597992705557881172640175117476017503918294534205898046483981707558521558992058512940087192655700351675718815723840568640509355338482631416345193176708501897458649841539192993142790402734898948352382350766125000186026261167277014748183012844440603384989647664190074853086693408529737767147592432979469020671772152652865219092597717869942730499507426269170189547020660681363276871874469322437194397171763927907099922324375991793759
d=wienerAttack(e,n)
print("d=",d)
f=pow(165251729917394529793163344300848992394021337429474789711805041655116845722480301677817165053253655027459227404782607373107477419083333844871948673626672704233977397989843349633720167495862807995411682262559392496273163155214888276398332204954185252030616473235814999366132031184631541209554169938146205402400412307638567132128690379079483633171535375278689326189057930259534983374296873110199636558962144635514392282351103900375366360933088605794654279480277782805401749872568584335215630740265944133347038070337891035560658434763924576508969938866566235926587685108811154229747423410476421860059769485356567301897413767088823807510568561254627099309752215808220067495561412081320541540679503218232020279947159175547517811501280846596226165148013762293861131544331444165070186672186027410082671602892508739473724143698396105392623164025712124329254933353509384748403154342322725203183050328143736631333990445537119855865348221215277608372952942702104088940952142851523651639574409075484106857403651453121036577767672430612728022444370874223001778580387635197325043524719396707713385963432915855227152371800527536048555551237729690663544828830627192867570345853910196397851763591543484023134551876591248557980182981967782409054277224,d,n)
print(long_to_bytes(f))

WEEK4

ECC

from Crypto.Util.number import getPrime
from libnum import s2n
from secret import flag

p = 74997021559434065975272431626618720725838473091721936616560359000648651891507
a = 61739043730332859978236469007948666997510544212362386629062032094925353519657
b = 87821782818477817609882526316479721490919815013668096771992360002467657827319
E = EllipticCurve(GF(p),[a,b])
m = E.random_point()
G = E.random_point()
k = 93653874272176107584459982058527081604083871182797816204772644509623271061231
K = k * G
r = getPrime(256)
c1 = m + r * K
c2 = r * G
cipher_left = s2n(flag[:len(flag)//2]) * m[0]
cipher_right = s2n(flag[len(flag)//2:]) * m[1]

print(f"p = {p}")
print(f"a = {a}")
print(f"b = {b}")
print(f"k = {k}")
print(f"E = {E}")
print(f"c1 = {c1}")
print(f"c2 = {c2}")
print(f"cipher_left = {cipher_left}")
print(f"cipher_right= {cipher_right}")

通过花间我们可以得到:\(c1=m+r*K=m+r*k*G=m+k*c2\),这就相当于将\(c2\)作为基点,而\(k\)是我们已知的,那么就可以通过\(m=c1-k*c2\)求得明文。

求出\(m\)之后要注意的是不能将\(m[0],m[1]\)直接用于除法(但在sage中\(m[0],m[1]\)本来就是\(GF(p)\)的所以没事),应当是对\(p\)求逆元再运算

(什么为什么我会解释这个?因为真的有人闲着没事在\(m[0],m[1]\)前面加了个\(int()\)

PRNG

看到伪随机数生成算法想到\(LCG\)去了(谁叫本fw只学过这个捏

然后知道是\(MT19937\)

找到脚本通过前面\(624\)个随机数恢复了内置的\(state\)之后继续预测接下来的\(21\)个数再和后面的数组分别异或拼出flag

posted @ 2022-02-21 08:45  上辰  阅读(269)  评论(0编辑  收藏  举报