问题:
Question 1
Your goal in this project is to break RSA when the public modulus
N
is generated incorrectly. This should serve as yet another reminder not to implement crypto primitives yourself.
Normally, the primes that comprise an RSA modulus are generated independently of one another. But suppose a developer decides to generate the first prime
p
by choosing a random number
R
and scanning for a prime close by. The second prime
q
is generated by scanning for some other random prime also close to
R
. We show that the resulting RSA modulus
N=pq
can be easily factored.
Suppose you are given a composite
N
and are told that
N
is a product of two relatively close primes
p
and
q
, namely
p
and
q
satisfy
|p−q|<2N1/4
(*)
Your goal is to factor
N
.
Let
A
be the arithmetic average of the two primes, that is
A=p+q2
. Since
p
and
q
are odd, we know that
p+q
is even and therefore
A
is an integer.
To factor
N
you first observe that under condition (*) the quantity
N−−√
is very close to
A
. In particular
A−N−−√<1
as shown below. But since
A
is an integer, rounding
N−−√
up to the closest integer reveals the value of
A
. In code,
A=ceil(sqrt(N))
where "ceil" is the ceiling function. Visually, the numbers
p,q,N−−√
and
A
are ordered as follows:
Since
A
is the exact mid-point between
p
and
q
there is an integer
x
such that
p=A−x
and
q=A+x
. But then
N=pq=(A−x)(A+x)=A2−x2
and therefore
x=A2−N−−−−−−√
Now, given
x
and
A
you can find the factors
p
and
q
of
N
since
p=A−x
and
q=A+x
.
In the following challenges, you will factor the given moduli using the method outlined above. To solve this assignment it is best to use an environment that supports multi-precision arithmetic and square roots. In Python you could use the gmpy2 module. In C you can use GMP.
Factoring challenge #1: The following modulus
N
is a products of two primes
p
and
q
where
|p−q|<2N1/4
. Find the smaller of the two factors and enter it as a decimal integer.
N = 17976931348623159077293051907890247336179769789423065727343008115 \ 77326758055056206869853794492129829595855013875371640157101398586 \ 47833778606925583497541085196591615128057575940752635007475935288 \ 71082364994994077189561705436114947486504671101510156394068052754 \ 0071584560878577663743040086340742855278549092581Factoring challenge #2: The following modulus N is a products of two primes p and q where |p−q|<211N1/4 . Find the smaller of the two factors and enter it as a decimal integer.
Hint: in this case A−N−−√<220 so try scanning for A from N−−√ upwards, until you succeed in factoring N .
N = 6484558428080716696628242653467722787263437207069762630604390703787 \ 9730861808111646271401527606141756919558732184025452065542490671989 \ 2428844841839353281972988531310511738648965962582821502504990264452 \ 1008852816733037111422964210278402893076574586452336833570778346897 \ 15838646088239640236866252211790085787877Factoring challenge #3: (extra credit) The following modulus N is a products of two primes p and q where |3p−2q|<N1/4 . Find the smaller of the two factors and enter it as a decimal integer.
Hint: use the calculation below to show that 6N−−−√ is close to 3p+2q2 and then adapt the method above to factor N .
N = 72006226374735042527956443552558373833808445147399984182665305798191 \ 63556901883377904234086641876639384851752649940178970835240791356868 \ 77441155132015188279331812309091996246361896836573643119174094961348 \ 52463970788523879939683923036467667022162701835329944324119217381272 \ 9276147530748597302192751375739387929The only remaining mystery is why A−N−−√<1 . This follows from the following simple calculation. First observe that
A2−N=(p+q2)2−N=p2+2N+q24−N=p2−2N+q24=(p−q)2/4
Now, since for all x,y: (x−y)(x+y)=x2−y2 we obtain
A−N−−√=(A−N−−√)A+N√A+N√=A2−NA+N√=(p−q)2/4A+N√
and since N−−√≤A it follows that
A−N−−√≤(p−q)2/42N√=(p−q)28N√
By assumption (*) we know that (p−q)2<4N−−√ and therefore
A−N−−√≤4N√8N√=1/2
as required.
Further reading:the method described above is a greatly simplified version of a much more general result on factoring when the high order bits of the prime factor are known.
Question 2
The challenge ciphertext provided below is the result of encrypting a short secret ASCII plaintext using the RSA modulus given in the first factorization challenge. The encryption exponent used is
e=65537
. The ASCII plaintext was encoded using PKCS v1.5 before the RSA function was applied, as described in Lecture 11.4.
Use the factorization you obtained for this RSA modulus to decrypt this challenge ciphertext and enter the resulting English plaintext in the box below. Recall that the factorization of
N
enables you to compute
φ(N)
from which you can obtain the RSA decryption exponent.
Challenge ciphertext (as a decimal integer): 22096451867410381776306561134883418017410069787892831071731839143676135600120538004282329650473509424343946219751512256465839967942889460764542040581564748988013734864120452325229320176487916666402997509188729971690526083222067771600019329260870009579993724077458967773697817571267229951148662959627934791540After you use the decryption exponent to decrypt the challenge ciphertext you will obtain a PKCS1 encoded plaintext. To undo the encoding it is best to write the decrypted value in hex. You will observe that the number starts with a '0x02' followed by many random non-zero digits. Look for the '0x00' separator and the digits following this separator are the ASCII letters of the plaintext. (note: the separator used here is '0x00', not '0xFF' as stated in the lecture)
代码:
import gmpy2
from gmpy2 import mpz
from gmpy2 import ceil
from gmpy2 import sqrt
from gmpy2 import invert
from gmpy2 import powmod
gmpy2.get_context().precision = 1200
n1=mpz('179769313486231590772930519078902473361797697894230657273430081157732675805505620686985379449212982959585501387537164015710139858647833778606925583497541085196591615128057575940752635007475935288710823649949940771895617054361149474865046711015101563940680527540071584560878577663743040086340742855278549092581')
n2=mpz('648455842808071669662824265346772278726343720706976263060439070378797308618081116462714015276061417569195587321840254520655424906719892428844841839353281972988531310511738648965962582821502504990264452100885281673303711142296421027840289307657458645233683357077834689715838646088239640236866252211790085787877')
n3=mpz('720062263747350425279564435525583738338084451473999841826653057981916355690188337790423408664187663938485175264994017897083524079135686877441155132015188279331812309091996246361896836573643119174094961348524639707885238799396839230364676670221627018353299443241192173812729276147530748597302192751375739387929')
cipher=mpz('22096451867410381776306561134883418017410069787892831071731839143676135600120538004282329650473509424343946219751512256465839967942889460764542040581564748988013734864120452325229320176487916666402997509188729971690526083222067771600019329260870009579993724077458967773697817571267229951148662959627934791540')
e=mpz('65537')
def factor1(n):
a=mpz(ceil(sqrt(n)))
x=sqrt(a**2-n)
return mpz(a-x)
def factor2(n):
square_n=mpz(ceil(sqrt(n)))
for idx in range(2**20):
a=square_n+idx
x=mpz(sqrt(a**2-n))
if (a-x)*(a+x)==n:
break
return a-x
def factor3(n):
a=ceil(sqrt(6*n))-0.5
x_square=a**2-6*n
x=sqrt(x_square)
if (a-x)%3==0: # 3p<2q => p<q
return mpz((a-x)/3)
elif (a-x)%2==0: # 2q<3p
q=(a-x)/2
if q<n/q:
return mpz(q)
else:
return mpz(n/q)
def de_rsa(c,e,n):
p=factor1(n)
q=n/p
phi_n=(p-1)*(q-1)
d=invert(e,phi_n)
message_hex=hex(powmod(c,d,n))
message_hex=message_hex[2:]
if len(message_hex)%2!=0:
message_hex='0'+message_hex
message_pkcs=message_hex.decode('hex')
for idx in range(len(message_pkcs)):
if message_pkcs[idx]=='00'.decode('hex'):
message=message_pkcs[idx+1:]
return message
print factor1(n1)
print factor2(n2)
print factor3(n3)
print de_rsa(cipher,e,n1)
思路:
分解第一个和第二个数时安装题目里的公式做就行,要注意的是gmpy2模块的精度要取得足够大,否则sqrt()函数的参数为mpfr型时,即使该参数的平方根也是整数,得出的结果可能是很趋近那个平方根的浮点数,导致最终结果错误,所以计算x值时要注意确认设定的精度可以得到正确的x。程序中精度取的是1200(gmpy2.get_context().precision = 1200)。
分解第三个数时,要注意A=(3p+2q)/2,即A是3p和2q的中点,并且3p是奇数,2q是偶数,所以A一定不是整数,并且因为除以2,A的小数部分是0。通过公式的推导,可以知道 A和sqrt(6N)差距小于1/(8*sqrt(6)),所以A的值等于 ceil(sqrt(6N))-0.5,取得A值后,计算x=sqrt(a^2-6N),计算出x后,A-x可能为3p或2q,判断一下A-x是否被3除尽就可确定。
最后一个问题是RSA解密,通过对N的分解因式可以计算 φ(N) ,然后可以计算出私钥,解密的结果是很长一串数,将其转换成16进制编码的字符串,decode('hex')以后就是PKCS1编码后的明文,分隔符之后的就是原始信息。