5.6 KiB
RSA
What is interesting about an RSA key:
e
is a constant, often it is 65537
n
is the modulus, p * q = n
through factorization
Coprime phi
is calculated either by Euler
Totient or greatest
common divisor via
euclidean
algorithm
\phi(n) = (p-1)(q-1)
and further
1 < \phi < n
Encryption, public key e
is a prime between 2 and phi
2 < e < \phi
Decryption, private key d
d\ e\ mod\ \phi(n) \equiv 1
d\ e \equiv 1\ (mod\ \phi(n))
d
is the modular inverse of e and phi and makes the private key.
Cipher = msg^{d}\ mod\ \phi
Cleartext = cipher^{e}\ mod\ \phi
e
and d
may be found through the following Python snippets
possible_e = []
for i in range (2, phi):
if gcd(n, i) == 1 and gcd(phi, i) == 1:
possible_e.append()
possible_d = []
for i in range (phi + 1, phi + foo):
if i * e mod phi == 1 :
possible_d.append()
Euklid
Just a short excourse:
A greatest common divisior out of an example a = 32 and b = 14 would be the
groups of the following divisors
a = 32, b = 24
a = {1, 2, 4, 8, 16}
b = {1, 2, 3, 8, 12}
gcd(a,b) = 8
Greatest Common Divisor (GCD)
Two values are prime and have themselves and only 1
as a divisor are called coprime.
To check if a and b have a greatest common divisor do the euclidean algorithm.
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
Extended GCD
#TODO
Fermat`s Little Theorem
If modulus p
is a prime and and modulus n
is not a prime, p defines a
finite field (ring).
n \in F_{p} \{0,1,...,p-1\}
The field consists of elements n
which have an inverse m
resulting in $n +
m = 0$ and n * m = 1
.
So , n^p - n
is a multiple of p then n^p \equiv n\ mod\ p
and therefore $ n
= n^p\ mod\ p$. An example
4 = 4^{31}\ mod\ 31
Further, p
while still a prime results in 1 = n^{p-1} mod\ p
. An example
1 = 5^{11-1}\ mod\ 11
Modular Inverse
Coming back to the modular inverse n
, it can be found in the following way
n^{p-1} \equiv 1\ mod\ p
n^{p-1} * n^{-1} \equiv n^{-1}\ mod\ p
n^{p-2} * n * n^-1 \equiv n^{-1}\ mod\ p
n^{p-2} * 1 \equiv n^{-1}\ mod\ p
n^{p-2} \equiv n^{-1}\ mod\ p
Quadratic Residue
m
is a quadratic residue when \pm n^2 = m\ mod\ p
with two solutions.
Otherwise it is a quadratic non residue.
So a porperty of quad res are, if Quadratic Residue QR = 1
and Quadratic
NonResidue QN = -1
QR * QR = QR\\
QR * QN = QN\\
QN * QN = QR\\
Legendre
\frac{a}{p} =
\begin{cases}
1, & if\ a\ quadratic\ residue\ mod\ p\ and\ not\ a\ \equiv\ 0\ (mod\ p),\\
-1, & if\ a\ is\ a\ non\ residue\ mod\ p,\\
0, & if\ a\ \equiv 0\ (mod\ p)\\
\end{cases}
\frac{a}{p} \equiv a^{p-1/2}\ (mod\ p)\ and\ \frac{a}{p} \in \{-1,0,1\}
Legendre Symbol test via Python with
pow(a,(p-1)/2,p)
Finding the square root of integer a which is quadratic residue
Given p \equiv 3\ mod\ 4
the square root is calculated through
pow(a,((p+1)//4),p)
Tonelli-Shanks - Modular Square Root
- Find elliptic curve co-ordinates
- Precondition: modulus is not a prime
- TBD
RSA PublicKey Extraction
Extract n and e from RSA public key
from Crypto.PublicKey import RSA
with open("./id_rsa.pub", 'r') as _f:
pub_k = RSA.importKey(_f.read())
print(f"n:\n{pub_k.n}\n")
print(f"\ne:\n{pub_k.e}\n")
Extract p and q from PublicKey
Modified from d4rkvaibhav
from Crypto.PublicKey import RSA
with open("./id_rsa.pub", 'r') as _f:
pub_k = RSA.importKey(_f.read())
def isqrt(n):
x=n
y=(x+n//x)//2
while(y<x):
x=y
y=(x+n//x)//2
return x
def fermat(n):
t0=isqrt(n)+1
counter=0
t=t0+counter
temp=isqrt((t*t)-n)
while((temp*temp)!=((t*t)-n)):
counter+=1
t=t0+counter
temp=isqrt((t*t)-n)
s=temp
p=t+s
q=t-s
return p,q
p,q = fermat(pub_k.n)
print(f"\np: {p}\n")
print(f"\nq: {q}\n")
print(f"\np-q: {p-q}\n")
Generate PrivateKey
from Crypto.PublicKey import RSA
with open("./id_rsa.pub", 'r') as _f:
pub_k = RSA.importKey(_f.read())
def isqrt(n):
x=n
y=(x+n//x)//2
while(y<x):
x=y
y=(x+n//x)//2
return x
def fermat(n):
t0=isqrt(n)+1
counter=0
t=t0+counter
temp=isqrt((t*t)-n)
while((temp*temp)!=((t*t)-n)):
counter+=1
t=t0+counter
temp=isqrt((t*t)-n)
s=temp
p=t+s
q=t-s
return p,q
def extended_euclid(a, b):
if a == 0:
return b, 0, 1
else:
g, y, x = extended_euclid(b % a, a)
return g, x - (b // a) * y, y
def modular_inverse(e, phi):
g, x, y = extended_euclid(e, phi)
if g != 1 :
raise Exception("No modular inverse")
else:
return x % phi
p,q = fermat(pub_k.n)
phi = (p-1) * (q-1)
d = modular_inverse(pub_k.e, phi)
print(f"\np: {p}\n")
print(f"\nq: {q}\n")
print(f"\np-q: {p-q}\n")
print(f"\nd: {d}\n")
priv_k = RSA.construct((pub_k.n, pub_k.e, d))
with open ("./priv_id_rsa", "wb") as _f:
_f.write(priv_k.export_key('PEM'))