CTF--RSA--p-1光滑

RSA--p-1光滑

对于CTF--Crypto--RSA中的p-1光滑问题,在此记录本人的学习记录以及心得。欢迎各位师傅斧正。

前备知识:

光滑数(Smooth number):可以分解成小素数的正整数。

费马小定理

\[\begin{flalign} &(a,p)=1\Longrightarrow a^{p-1}≡1(mod\quad p)\\ &费马小定理证明:\\ &首先你要知道剩余类的概念,不知道的师傅可以去补一下。\\ &对于素数p,它的剩余类是\{0,1,2,\cdots,p-1\},不再讨论0的情况。那么对于\{a,2a,\cdots,(p-1)a\}.\\ &现证明\{a,2a,\cdots,(p-1)a\}中没有相同的元素。就可以说明\{0,a,2a,\cdots,(p-1)a\}也是p的剩余类。\\ &假设有a_i,a_j元素,a_i=a_j(1≤i,j≤p-1)\rightarrow a(i-j)≡0(mod\quad p)\rightarrow p|a(i-j)\\ &这与i,j\in\{0,1,2,\cdots,p-1\}且(a,p)=1矛盾,故\{a,2a,\cdots,(p-1)a\}中没有相同的元素.\\ &则有(p-1)!≡a^{p-1}(p-1)(mod\quad p)且(p,(p-1)!)=1\rightarrow a^{p-1}≡1(mod\quad p)& \end{flalign} \]

B-Smooth:

\[\begin{flalign} &可设p-1 = p_1p_2\cdots p_s(\forall1≤i≤s)\\ &若p_1p_2\cdots p_s两两不同,则p_1p_2\cdots p_s|B!\Longrightarrow B!=k(p - 1).因此a^{B!}≡a^{k(p-1)}≡1(mod p).\\ &假设N=pq,计算gad(a^{B!}-1,N)=p即可.& \end{flalign} \]

理论代码:

from Crypto.Util.number import *
from gmpy2 import *
a = 2   # 这个就是费马小定理中的a,我们直接取素数2即可
n = 2   # n用来计算B-Smooth中的B!
while True: # 利用循环找到满足gcd(a^{B!}-1,N) = p的情况
    a = pow(a, n, N)
    res = GCD(a-1, N)
    if res != 1 and res != N:
        q = N // res
        print("p=",res)
        print("q=",q)
        break
    n += 1

典型例题:

2024SHCTFWeek2--魔鬼的步伐

      
from Crypto.Util.number import *
from random import choice
from enc import flag

m = bytes_to_long(flag)
def get_primes(limit):
    primes = []
    is_prime = [True] * (limit + 1)
    for num in range(2, limit + 1):
        if is_prime[num]:
            primes.append(num)
            for multiple in range(num * num, limit + 1, num):
                is_prime[multiple] = False
    return primes

def get_Prime(bits):
    while True:
        n = 2
        while n.bit_length() < bits:
            n *= choice(primes)
        if isPrime(n + 1):
            return n + 1

e = 65537
primes = get_primes(e)
p = get_Prime(512)
q = get_Prime(512)
n = p*q
c = pow(m,e,n)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
'''
n = 779579301738188606639541475585479048662338414978423162511086618350581959037809676355175033940672838358216296034989613684765924879020007985463372880378958453235938149726732804842653385407460552866449233717559756619739481517089434393605029261842182116054349584175198599481092380973944251651872382058614325364639417
e = 65537
c = 547032040563518540116157223879027303340872416038133089003193905244978422560735616179910978730578423924420033057963791332760379132346877909806353927165538096867865399527460216074519919572776729647581400118345644864260152466704275743378828075020134070702051989890847762735538767329450466068109132805742740564390842
'''

Analysis:

欧拉函数φ(n): 给定一个正整数 n,欧拉函数就是求在 [1,n) 区间上,与 n互质的整数的个数。举例来说,设m = 8,则与8互质的正整数集合A={1, 3, 5, 7},此集合共有4个元素,所以 φ ( 8 ) = 4。

\[\forall n\in \mathbb{N^+},φ(n)=∣A∣,whereA=\{m|1≤m≤n,(m,n)=1\}\\ |S|表示集合S中的元素个数 \]

欧拉定理: 对任意两个正整数 a , n ,若两者互素,则:对比费马小定理,实际上就是欧拉定理的特殊情况。因为素数p的φ(p)=p-1

\[a^{φ(n)}≡1(mod\ \ n)=>a^{kφ(n)}=(a^{φ(n)})^k≡1^k≡1(mod\ \ n) \]

所以只要指数是模数n的欧拉函数的倍数,在模n下就等于1.

对于本题中的情况:

\[p = p_1p_2\cdots p_s+1;q=q_1q_2\cdots q_t+1\\ φ(p)=p_1p_2\cdots p_s;φ(q)=q_1q_2\cdots q_t\\ n = pq;φ(n)=p_1p_2\cdots p_sq_1q_2\cdots q_t\\ 所以只需要遍历get\_primes()得到的素数表就可以得到数a的计算指数.\\ 得,a^{k*φ(n)}≡1(mod\ \ n)\\ a^{k*φ(n)}-1≡0(mod\ \ p)=>gcd(a^{k*φ(n)}-1,n)=p \]

exp:

from Crypto.Util.number import *
# Given values
n = 779579301738188606639541475585479048662338414978423162511086618350581959037809676355175033940672838358216296034989613684765924879020007985463372880378958453235938149726732804842653385407460552866449233717559756619739481517089434393605029261842182116054349584175198599481092380973944251651872382058614325364639417
e = 65537
c = 547032040563518540116157223879027303340872416038133089003193905244978422560735616179910978730578423924420033057963791332760379132346877909806353927165538096867865399527460216074519919572776729647581400118345644864260152466704275743378828075020134070702051989890847762735538767329450466068109132805742740564390842

# 初始化生成光滑数的列表get_primes(e)
def get_primes(limit):
    primes = []
    is_prime = [True] * (limit + 1)
    for num in range(2, limit + 1):
        if is_prime[num]:
            primes.append(num)
            for multiple in range(num * num, limit + 1, num):
                is_prime[multiple] = False
    return primes
# 由于n = p * q ,而p,q分别由一个get_primes生成,所以最终n的列表应该是2*get_primes(e)
primes_value = get_primes(e) + get_primes(e)

# 求解φ(n)
def Solve(n):
    counter = 0
    for p in primes_value:
        if n % p == 0:
            counter += 1
    return n - counter - 2  # 减去1和n的两种情况
# 取素数2当作最初的a,在φ(n)的范围内不断增大指数寻找GCD(a^{k*φ(n)}-1,n) != 0和 != n
a = 2
for _ in range(2,Solve(n)):
    a = pow(a,_,n)
    p = GCD(a-1,n)
    if p !=1 and p != n:
        q = n // p
        break
phi_n = (p-1)*(q-1)
d = inverse(e,phi_n)
flag = long_to_bytes(pow(c,d,n))
print(flag)
#SHCTF{1rlCTioN_is_ThE_d3vils_st3P_4s}

写在最后:

例题不多,但是我觉得这道题的质量足以锻炼RSA中p-1光滑的题型的考点以及应对策略,我们的最终目的就是寻找到φ(n),之后取a=2利用费马小定理或者欧拉定理进行求解得到a^{φ(n)}≡1(mod p) => gcd(n,a^{φ(n)}-1) = p,判断条件就是gcd(n,a^{φ(n)}-1) !=1 and gcd(n,a^{φ(n)}-1) != n.

posted @ 2024-11-05 17:50  chen_xing  阅读(9)  评论(0编辑  收藏  举报