点击蓝字 关注我们
日期:2023-04-19 作者:jgk01 介绍:之前在 RSA
题目中遇到过的e和phi
不互素的问题,可以采用AMM
开根算法来解决这个问题,本篇来了解有限域上的AMM
开根算法。
0x00 前言
去年年末的比赛中遇到过多次AMM
开根的题目,这类题目特征还是比较明显,所以学习整理记录一下相应的算法与原理。
0x01 AMM算法详解
1.1 开2次方
以开2
次方为例我们来看一下AMM
开根方法思路。
首先对于2
次方式子我们有:
把上面的p-1
的变式代入可得到:
对于一个非二次剩余Y
:
此时如果t=1
,那么上式为:
此时我们两边同乘x
在开根得到:
此时代入密文c
就可以求出明文:
所以明文m
就等于:
举一个简单的例子:
这里的2
就是明文,4
就是密文。
我们继续看⬇️
对上式开根,可以得到两种结果:
这里的k
是为了控制是否引入非二次剩余项,我们开出正根k=0
,开出负根k=1
,之后不断对x
开根,一直到2
的指数为0
,一共t-1
个k
:
此时,乘二次剩余x
然后两边取平方:
和上面一样把c
带入就可以求出明文了:
0x02 例题介绍
2.1 题目
题目是一个组合题,前面的解密步骤就让我们得到了如下信息:
e = 1531793
p = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509191077550351496973264159350455849525747355370985161471258126994336297660442739951587911017897809328177973473427538782352524239389465259173507406981248869793
q = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509185464641520736454955410019736330026303289754303711165526821866422766844554206047678337249535003432035470125187072461808523973483360158652600992259609986591
n = p * q
c = 23129683905221590810931073733257240695491909600600821626110967741991475952367362466435001712032183901737453265086024660692796844392297498997208235843621067335947024294793917437465567235097523891328309930140339168673282959013006525102332444767839426566939309039615858490944730603509080574471734733118066791730903874584695936232044353090855494398794086718463881637739165577843547326511641921822024263267673375341299485422153934060527418515955523844699687688348603999820720218160844840953001023840468960215702467203343095303314120059019184362079713388502293450806476408625709403546751299379519145557188933345613844133126
得到这些信息后,首先我们发现e
比较小,按常理有了这些数据应该用常规的rsa
解密解出flag
了,但是这里你就会发现求d
的时候会报错,我们可以发现,e
和(p-1)
是不互素的,(p-1)
正好是e
的倍数,此时,就符合了我们AMM
算法的第二种情况,可以利用AMM
算法求解。
2.2 解题思路
解题脚本:
from Crypto.Util.number import *
import gmpy2
import time
import random
from tqdm import tqdm
e = 1531793
p = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509191077550351496973264159350455849525747355370985161471258126994336297660442739951587911017897809328177973473427538782352524239389465259173507406981248869793
q = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509185464641520736454955410019736330026303289754303711165526821866422766844554206047678337249535003432035470125187072461808523973483360158652600992259609986591
n = p * q
c = 23129683905221590810931073733257240695491909600600821626110967741991475952367362466435001712032183901737453265086024660692796844392297498997208235843621067335947024294793917437465567235097523891328309930140339168673282959013006525102332444767839426566939309039615858490944730603509080574471734733118066791730903874584695936232044353090855494398794086718463881637739165577843547326511641921822024263267673375341299485422153934060527418515955523844699687688348603999820720218160844840953001023840468960215702467203343095303314120059019184362079713388502293450806476408625709403546751299379519145557188933345613844133126
def AMM(o, r, q):
start = time.time()
g = GF(q)
o = g(o)
p = g(random.randint(1, q))
while p ^ ((q-1) // r) == 1:
p = g(random.randint(1, q))
Find p:{}'.format(p))
t = 0
s = q - 1
while s % r == 0:
t += 1
s = s // r
Find s:{}, t:{}'.format(s, t))
k = 1
while (k * s + 1) % r != 0:
k += 1
alp = (k * s + 1) // r
Find alp:{}'.format(alp))
a = p ^ (r**(t-1) * s)
b = o ^ (r*alp - 1)
c = p ^ s
h = 1
for i in range(1, t):
d = b ^ (r^(t-1-i))
if d == 1:
j = 0
else:
Calculating DLP...')
j = - discrete_log(d, a)
Finish DLP...')
b = b * (c^r)^j
h = h * c^j
c = c^r
result = o^alp * h
end = time.time()
in {} seconds.".format(end - start))
one solution: {}'.format(result))
return result
def onemod(p,r):
t=p-2
while pow(t,(p-1) // r,p)==1:
t -= 1
return pow(t,(p-1) // r,p)
def solution(p,root,e):
g = onemod(p,e)
may = set()
for i in range(e):
* pow(g,i,p)%p)
return may
def union(x1, x2):
m1 = x1
m2 = x2
d = gmpy2.gcd(m1, m2)
assert (a2 - a1) % d == 0
m1 // d,m2 // d =
gmpy2.gcdext(p1,p2) =
k = -((a1 - a2) // d) * l1
lcm = gmpy2.lcm(m1,m2)
ans = (a1 + k * m1) % lcm
return ans,lcm
def excrt(ai,mi):
tmp = zip(ai,mi)
return reduce(union, tmp)
cp = c % p
mp = AMM(cp,e,p)
mps = solution(p,mp,e)
for mpp in tqdm(mps):
ai = [int(mpp)]]
mi =
m = CRT_list(ai,mi)
flag = long_to_bytes(m)
if b'flag' in flag:
print(flag)
exit(0)
0x03 后记
AMM
开根算法在密码学中还算最近是比较常见的题型,大家有兴趣可以看一些这方面的文章进一步学习一下。
Reference
https://clingm.github.io/2022/10/02/AMM-Algorithm/
https://www.anquanke.com/post/id/262634
免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。
原文始发于微信公众号(宸极实验室):『CTF』AMM 算法详解与应用
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论