【CTF-Crypto】格密码基础(例题较多,非常适合入门!)
格密码相关
格密码基本概念(属于后量子密码)
后量子密码指的是对抗未来量子计算快速解决的问题
==向量空间:==
==格:==
格本身就是一个系数为整数的向量空间
-
一系列向量集合(vector)v1 , v2 , v3 , vn
-
一系列整数a1 , a2 ,…, an
-
上面两个东西进行向量的线性组合就得到了格子(Lattices)即L = {a1v1+…+anvn}
直观感受一个最简单的格:
在上面这个图中,每一个交点都是格上的一个格点,其基向量是(0,1)和(1,0)
该格用数学符号表示为:
根据不同的基向量,我们可以得到不同的格点:
比如选择(1,1)和(1,-1)作为基向量,因为系数要取整数,所以(1,0)这个点就是这两个基向量张成的格中不存在的格点
格的维数:即向量的个数,上面这个就表示二维的格
然后根据整数系数a的不同 就可以形成很多个不同的L集合
假定v1 , v2 , … , vn (称为张成空间)是格L的基 然后存在不同个集合属于L 即w1 , w2 ,… , wm
则有(属于线性组合)
到此格的问题转化为矩阵的运算
线性无关(linearly independence)v1 , v2 , … , vn线性无关,当且仅当方程a1v1+…+anvn=0的唯一解是a全部为0;否则线性相关(linearly dependent)
正交基(orthogonal basis)v1 , v2 , … , vn 中任意不同的两个v点积的结果为0
规范正交(orthonormal) 上面的每一个v的**欧几里得范数(类似于模 长度)**为1
据此在上面的w的||w||2 = 所有系数a的平方和
基础的格运算(行列式运算)
举栗子:
选定基向量生成格子L:
将其作为行向量写成矩阵:
假设L的其他向量组为:
提取其系数a 形成矩阵:
得到w的值(对应每一列列向量代表w):
B = (w1,w2,w3)
所以A = B * U-1
故v1 = 4w1 -2w2 -w3
代码验证:
1 | #sage |
SVP(shortest Vector Problem)最短向量问题
我们根据开篇的内容可以看到一个格L这个集合中会存在无线多个向量集合v
所以最短向量问题 就是指在这一个格L中最短的非零向量 即寻找一个v满足欧几里得范数最小(指该集合的每一个元素的平方和再开方)范数就是指长度
此外格中的最短向量可能不止一个,举个例子:
向量(0,1)和(1,0)张成的格
求解前置知识:
==基:==
在向量空间的每一个点,都可以通过对基的线性组合变化得到,叫做基向量
一个格可能会有很多个基 不唯一
==正交基:==
基相互垂直,就是正交基
==格基规约:==
目的就是:找到最接近正交基的基向量
random basis也是一组基,可以构成这个格子中的所有点 但是不是正交基
通过LLL或BKZ算法 得到正交基或者是最接近正交基
此时思考:我们找这个正交基目的是什么,为什么要找这个正交基呢,它有什么用吗?
目的在于:寻找最短向量v 也就是SVP问题
先找到正交基或者最接近正交基的基 进而证明我们的最短向量一定在这组基上
存在两种关系:
- 假设v是这个基中的某个向量,在其他向量上的投影长度为0,两两垂直,符合SVP
- 假设v不是基中的向量,此刻该向量一定可以通过在其他基向量方向的投影来得到一个更短的向量
垂直投影更短
CVP(Closet Vector Problem)最近向量问题
格外向量w和格内向量v的差值的欧几里得范数最小
- 与SVP的关系:有些问题可以通过对CVP加上一维之后转变为SVP问题,因为SVP相比CVP稍微简单一些
做题要点(Key)超重点!!!!!! 明白这个到底是在干什么
经过前面基础知识的铺垫与学习,下面就要进行实战操作了,但是在实战开始之前,我们得把我们学到的内容转化成武器,这一过程非常重要。
首先在求解格密码的问题的时候,我们经常用到LLL算法,但是我们需要思考这个LLL算法的本质,为什么通过 LLL算法后得到的结果,就是我们想要得到的结果,这个进行LLL算法的格有什么要求吗,如何构造这样一个格呢,如果每次看到题目套模板,能做的题目真的是寥寥无几,所以要明白这个算法到底是在干什么的,如何去构造!
下面的学习内容是从DexterJie师傅的博客
1 | import gmpy2 |
分析一下题目:
目标求f
构造完这个式子之后,对二维矩阵进行LLL算法的结果就是我们想求的值
那么为什么会这样呢
这个时候就要回顾到LLL算法的作用,把(1,h)和(0,p)这组基变成正交化程度最大的一组基,去求解最短向量,所以只需要证明这个(f‘,g)是最短向量,那么我们上面的式子就全部讲的通了
Hermite定理
引入Hermite定理,给出了最短向量的上界 参考:格密码笔记
其中n表示维度,也就是基向量的个数,在本题中n = 2
det(L) = 行列式的值 = 1 * p = p
故:
向量v = (f’, g)
其长度为
其中 p = 512bit g = 128bit
一般flag长度43左右(uuid) 即f’约等于 335bit 但是很不幸 这个题目不是这样的
demo:
1 | b = 2**128 |
满足该定理,所以是可解的
所以这个长度len是我们可以构造的,而上界是固定的,越接近上界,值越精确,所以可以通过系数调整len的值从而使得和上界更接近,但是存在问题,如果系数过大,使得长度超过了上界,则无法求解
注意我们的行列式也在乘b进行变化
1 | b = 2**248 |
如:
但是可以根据bit适当扩大,当过于大 比如1024bit的时候
会发现下面的值变大了 也就不满足Hermite定理了,所以也就无法求解咯
为了更好的理解这个道理,继续看下面的这个例题,easyLattice就需要进行配平
格相关的大类型
NTRU密码
该密码类似于RSA、DSA也是属于一种密码体系
easyLattice
考点:格密码 NTRU 配平
解题:
1 | from Crypto.Util.number import * |
普通的NTRU入门格是解不了的
因为f太大,找不到,这就涉及到一个非常巧妙的构造格的方法了,那就是对格中的基向量进行配平,使得各方向长度接近一点。
那么什么情况下才能配平成功,就要搬出我们上面学习的Hermite定理咯,这里非常贴心的公布了flag的长度47
那么bit数大约是375左右
如果不配平的话,使用我们的Hermite测试demo!!保存 去测试发现是不满足的
257 < 375
存一下Hermite测试板:
1 | import gmpy2 |
所以进行配平
此时满足Hermite定理,可以进行求解
exp:
1 | def GaussLatticeReduction(v1, v2): |
flag:
1 | 512 512 |
Reference:
https://xenny.wiki/posts/crypto/Lattice/lattice-based.html#ntru
学完LLL的作用之后再回顾,给出了更简洁的实现脚本
1 | import libnum |
ez_ntru
做爽了,再来一题,这是2024山警黄河流域的题目
1 | from secret import flag |
题目思路是一模一样的,
首先梳理一下该题中解决ntru问题的各bit数
q = 2048bit
f = 1535
g = 511
如果不配平,显然不符合Hermite定理,所以要配平
显然 当配上1024bit的系数 1535 < 1537 这个格子的最短向量可求,符合Hermite定理。
解决完上面的ntru 拿到了f和g 继续进行Part2,其中
1 | r = random_prime(2^(3*bits//4 - 1)) |
推导:
尤其注意一个点,就是在mod q的情况下继续模g 注意区分开,最终的f的-1次方是在模g下的逆元
拿下:
完整exp:
1 | import libnum |
b'flag{7c95453a-e577-40d8-9ad0-993655b83b69}'
Easy_3L
题目源代码:
1 | from gmpy2 import * |
对题目进行分析 很明显get_key一点用没有直接忽略
然后在encrypt1中捕捉到关键代码:
1 | s[0] = seed |
这是一个lcg流密码伪随机数生成
其中已知s1、s2、s4、s5
然后最终的flag就是s0
想要恢复出初始的种子seed 就需要有连续的lcg生成数
所以锁定目标,求解s3
从而进入到encrypt2进行解密获得s3
1 | c = (s * h + msg) % p |
关键加密代码如上
进行变形:c = s * h + m - k * p
已知c,h,p 并且这三项位数相同 是1400位 比较大
然后s未知是512位
需要构建格密码求解m
将已知的内容作为构建格子M的内容 其系数提取到该格子的系数进行相乘
c - s * h + k * p = m
构造格子:
其系数:
两矩阵相乘结果:
我们构造盒子的标准在于其生成的结果要接近,且较小,起初使用2行2列的格式构建格子我们发现c会在结果中出现,因为c的长度过大,所以无法生成合适的规约数!!
代码实现:
1 | #sage |
到此获得s3
最后根据s1到上s5反推s0
1 | from Crypto.Util.number import * |
简单的NTRU(只有常数项)
1 | #构造格就行 |
一般多项式NTRU
1 | 构造的格仍然是 |
1 | N = |
脚本2
1 | from Crypto.Util.number import * |
ntru变形
重新推一下关系式构造格 不变形的ntru是
c 同余 rf^-1g + m mod p
构造[[1,h],[0,p]]
能解出f g 然后数学推导回m就行
背包密码
参数:
- 私钥:超递增序列 每一个数要比前面的全部数之和还要大
- 模数:m 大于超递增序列的全部和
- 乘数:w 满足和模数m互素 即gcd(w,m)=1
- 公钥:b 同余 wai mod m
超递增序列举个例子:
1、2、4、8、16 这个你可以发现每个数都是大于前面的全部和
加密
明文是一系列的0和1组成的二进制数据v
生成一个大整数c c是选入的超级递增序列私钥的和 再模m
解密
恢复v
构造格:把问题 归结到格上
HNP
基于DSA签名算法生成公式:
M相当于构造格子的基向量 然后乘系数m 得到的结果就是一系列格子的基向量
构造格子的注意事项
1 | M = matrix(QQ,40,40) #表示在有理数域中创建40*40的格子 默认初始为0 |
举个栗子:
MTCTF2022 strange_rsa3
1 | from Crypto.Util.number import * |
首先对n0和n1进行分析
n0 = p0 * q + r0 512bits 2048bits 1024bits
n1 = p1 * q + r1
n0/n1 = p0/p1 +r0/q/r1/q 约等于p0/p1
第二个栗子:
NPUCTF2020-babyLCG
考点:closed_lock_with_key::LCG随机数生成器 AES加密 HNP
题目:
1 | from Crypto.Util.number import * |
首先是lcg随机数的生成
给出了密钥k m b
lcg随机数的生成公式:si+1 = a * si + b (mod m)
并且已知每一个随机数泄露的高64bits的数据
所以将s分为高位h和低位部分l
(hi+1 + li+1) = a * (hi + li)+ b (mod m)
li+1 = a * li + a * hi + b - hi+1 (mod m)
其中li+1 和 li 未知 其他均已知
每次相乘保证li存在则需要设置相应的Ai和Bi
构造为:
因为这个数是128bits的 然后高64位已知 所以低位l最大是64bits 右下角K是轮密钥的上界 所以构造格子
使得存在一个向量与M相乘 得到的结果向量内各元素大小接近
这样构建了格子之后 对格子使用LLL()算法 取出第0行倒数第二列的数值 成功获得第一个低位的数值
然后和高位拼接 恢复原始s1 从而获得seed
代码如下:
1 | #sage |
获取seed之后就是去解决AES问题了
注意AES是对称加密体系中的算法 所以其加密程序和解密程序是有非常密切的关系的
我们只需要和加密时使用相同的算法获得密钥key 和初始向量iv即可构建相同的AES密码器
1 | from Crypto.Util.number import * |
第二个栗子:chestnut::
WMCTF-2023-Crypto signin
考点: p高位泄露
1 | from Crypto.Util.number import * |
解题:
首先是获取p 高位泄露了十六位 虽然这16位未知 但是可以通过设置16bit长度的所有情况进行爆破
1 | N = 73112325447718419004547130726695718285793085958231107892863489717428446716838799849309454056415849869930556787026583737635045001044331824958338557356039885155281113144595678795533444159689102603206422423835572911701365510630670709050480182217561850257781379648014791821272434711481938951190881233041060596523 |
上面的脚本来源于DASCTF的比赛中
然后获得
1 | bs = [5677770056347952821075508113035756036186750810935744246746174143756447222899456626676391801166125401365094827195531579218729867555316702975753784979244872, 2809620694316973743070419046517422880935575351562028606467262358149044880922143772187834653369648207268652362409857479009595884652141674028997687008458065, 3730270319847639205056610760089899175546681287012108868443801789244300006477333256569065708981917617890953379697372414414912864801523329022800590644960859, 5821308517313693876194723672109113624898735347480525042736754342702714857466473605555360227316768264216216522199834049459503113541382232261257078279373457, 7447756417909132324727804644545090515712348538866555221605506449994661595686624719179141597003925585021790315500290856582501600080206760793845807465435020, 2105762400848182586132539753964540320116345826242628146908489443753704312166929959947252892375240925912179106904028258517572657190458322323487967161677844, 154222298643104769325471310127340263916626139056136380962227349123299727085462094219564859503955889867523024467685219898520433147625254371592982600111385, 367828597395145770863382274648759911062421189249171333962353712349023993039851982532446913020406236969002463928822493235022843178244026427116420194632581, 1744200243856922563638772245369402677344028894603176201806040819068039225056278405389760818145017936368618817981571303260147110007739148296698937928843957, 5670406830778390730892641103362280301437252102865399395897422175624950243883078098199467864852521793872723428112979163916452992415911855252561215571391096, 4961373637791936223513400147782916563460190344580138422212799905208967588487213074873328658685093590342512783917670377711041783156851600713671476077404515, 5698904648841393994633450812750517199427982232619699696607698886438569980287267613186832256695574376500824006722753065479452944587472798782966294826498729, 2626611375827255664624275815248180600584539394441361715415622910267378140077728375819890115849477614869513835180911315948024350530246241990148027000003247, 4322432241215029052699237939341147131781420863250895517172680568672381909970064344040583613368923347568958321349659728727935451755378705244016710439641158, 1928419605038168764733449488709516192222335662921906459617704643151339384031358440020680276054871198671008628593620415807919003359787851822611275504761125, 758298969674788958681232125590769643791657077138037129139238209955794187834098615443521161703003644497548029106392839914740987840120821133758808191162464, 3026120713365180411884841936693672667286076351283725117739841509938175342066894932925924493822077276291978462795149635713410275262432016154092995131815069, 2639116385581133273068720849577714988914606374248136639831733592282012712583006465901110461383725143920082598753614952697933130060915300957054627629274585, 4938477885775391845441227660717435985351368416989649995935420783949796408027814914819890996906576154691050558257513298894204488415414648705103499910642769, 2586664093376881328787412631902927222753380482805791009422685269787127535644112074624071376797161243100602355098533019790821633292169346061029222356230765, 5553524741480099301054134204590300647682160064680815429649202130132178700086891659413819279328100036520027466610196402070124870933103957456304029253248732, 2827265379921181842866192519714225788148235787193890010891768669101713572608744951067703090450722162825909298999736141026042400464118472320665041675681263, 1882191527950117171689633117483662158586807501384802095608221879095319572751646959308080890743755189350869028885412995726442493419408160192448934636247969, 2624940783149957630052421415813956884561052534178680577595486675851951652761799600473953641982211067073776832889577908624789277943579205813592153885774787, 4557357589224938072027907497871251728077025399913277406228025890486316538978785358037884170649353496980491294290693236049954003081546235618935408233617781, 7503029892737975260686578470850749871382063215806103289417981959410942610953159314048524316989907513945454856136605901215014386958175836168455433495976840, 1481777615800981231353277825715461294317126131020372161819681326609658389423517292725626585141062920702092668619196067362128544725577006335263310427517720, 4195773140329253432252020288295924419191899561410667997498026712138128661788879368987893473405403124672999850771991585172310110744585123235362358448299402, 2003064111894296519054159734832793727058000516309777321077086228674560695531194066337528308841114906348141481465145488329210441174025042039646886744834307, 4508799626502269807611012496586770184190543351868505425146984121925038328927083771111700038861067084320342153568829171227980347727670336894671033305242053, 7141804680199937247962418027088222230735127547115123066765929692165221036432525181252245983667408692953252722174487387892809455275282654904239693974086313, 5386588055094784356165732781468142654808326535838628874938909372336169451891308083974558803497079135496650858231780699255029869995091026814783880851641095, 3782247624308335907897302856903747821512994875858417290191847604012849621190843084580777781441506763452934236540908617447821210352445344355717216720464659, 6527778172523455296666844889020389423098061136790050978799819429528238066483905902635991546245979582351890944412859630132736333005922929043047216254655955, 5307533726050766654822554741434396225884902691951304818603268654194614151318601582366056716061741240768755295434943924934683158909386226742299206040764766, 6680436528531848639646280824606034416195797982786801625729333386638769190461881575679794466409308819912401578516938662856219054823471163813941387223410656, 4887886672739126992557813239689644986751862892155246272416338920125998621231513182487516658592072003303553787101714685075776658032850821479355562756508038, 5265204245228171606770934463863274787963598538267041606291043095828239507419258123084718784524021414827606114852174671998385402424450055415134204339454340] |
利用hnp 获得secret
1 | secret = randrange(0,P) |
根据上式得到利用hnp的公式:ri % 2**16 = bi * secret (mod p)
ri = bi * secret % p % 2**16
ri = bi * secret + kp + l * 2**16
l * 2**16 = ri - bi * secret - kp
l = ri * inverse - bi * secret * inverse - kp (其中k和l以乘任何其他数都可以用k和l表示作为任意倍数关系)
inverse = inverse(2**16,p)
两边同时乘-1
l = bi * inverse * secret - ri * inverse + kp
ki = Ai * x + Bi 到此成功构造hnp式子
其中
p是512bits
bi secret 小于512bits
ri 16bits
l 小于 p bit位数就行 作为密钥 设为496bits
K是轮密钥的上界
构造格子
1 | from gmpy2 import * |
M作为基向量 l作为系数a 相乘构建出L的其他基向量m (多解) 选择其中第二短的v
NSS工坊刷题
因是NSS工坊里面的题目,所以就不放数据啦,想学的师傅真心推荐去工坊买一下,十几块钱真的不贵,而且学格这一块,自己有数据多调调参数才有意义,自己拿到flag,才能提高学习的积极性,师傅们冲冲冲!
P1 :弱化版NTRU
1 | from Crypto.Util.number import * |
整个题目和上面的ez_ntru是完全一样的
首先是构造格 使用Hermite定理判断一下
1 | #python |
本身就满足 所以不需要调平
具体原理参考上面的ez_ntru
exp:
1 | #sage |
成功获得flag 注意是sage哦
P2 :背包密码
task.py 注意注释是自己加的,可以根据注释了解一下背包密码加密的大体流程
1 | from Crypto.Util.number import * |
根据解密格
跑完后
可以发现对格Ge进行LLL之后 这个有无数组值 但是我们需要的是全部为0或者1的一组
特别需要注意 因为我们在构造格的时候是n+1 多加了一行 所以这一组值选出来之后 要去掉最后的一个数
在筛选的时候注意提取每一行的元素 有个地方需要注意一下,就是必须转换成列表才能对当前行的每一个元素操作,因为其本身是一个元组,没法提取单个元素
例如:
1 | M = res.row(i).list() #提取矩阵第i行转换成列表 |
1 | [33, 184, 123, 68, -41, -182, 171, 330, 115, -108, -160, 252, -31, 163, -79, 96, -36, -90, 264, -174, 52, -43, -272, -129, 73, 7, 134, 75, -65, -272, -181, -42, 126, 69, -159, 52, -263, 45, 10, 13, -103, 161, -61, 47, 54, -77, -13, 124, -209, 204, 148, -85, -85, -62, 192, 84, -47, -99, 175, -338, -107, -45, -415, -245, -228, 125, 187, 267, -9, 170, -172, 39, 99, -47, -136, -80, -58, -87, 96, 161, -133, -18, 199, -245, 6, -46, -9, -110, -70, 17, -91, 68, 111, 44, 8, 40, 11, -12, -9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] |
exp:
1 | #sage |
上面找到的结果 就是flag的二进制数据 拼起来即可
1 | flag = int(''.join(list(map(str, flag))), 2) |
想要拼接 需要把列表内的东西转化成字符型 才能使用join 最后成功拿到flag
p3 :自己构造
题目:
1 | from Crypto.Util.number import * |
exp:
1 | from Crypto.Util.number import * |
疑惑点
- p和q的正负 和r与h的关系
- 格子的构造 LLL之后结果的含义
P4 :自己构造 本意需要调整一下格的值
1 | from Crypto.Util.number import * |
首先补充一个小知识点
r的位数是175 非常小 但是其在逆元下,p的位数非常大,所以逆元的结果其位数接近模数p的 1024位左右
Hermite定理测试
1 | import gmpy2 |
满足的,所以证明构造这样一个格子就可以了 没有限制界
exp.sage:
1 | #sage |
P5 :平衡格基(本质还是Hermite定理的应用)
1 | from Crypto.Util.number import * |
构造格
Hermite定理验证:
1 | import gmpy2 |
exp.sage:
1 | from Crypto.Util.number import * |
P6 :论文题
1 | from Crypto.Util.number import * |
分析一下题目:
根本没给出什么其他条件,只有一个约束条件,多组公钥使用了一个相同的私钥
代码非常短,可能针对某个特定的问题
=>这种一般就确定了 要搜论文,用论文的深入研究的结果去解决问题
=>搜索方式:从题目中提取关键词 可以转化成英文
RSA、相同私钥、格基规约、格
=>锁定论文
Lattice Based Attack on Common Private Exponent RSA
赛后细读论文
赛中直接看格子怎么构造的
P7 :论文题(*)
没太懂怎么构造的 需要再读读论文
exp:
1 | #sage |
P8:格基规约
1 | from Crypto.Util.number import * |
分析构造过程:
exp:
1 | from Crypto.Util.number import * |
格密码入门完结撒花 有点感觉了 但是还是得继续练
2023-08-23——2024-08-02