2022-11-12 23:18:06 +01:00
|
|
|
# RSA
|
|
|
|
|
2024-02-18 21:23:15 +01:00
|
|
|
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](https://en.wikipedia.org/wiki/Euler's_totient_function) or [greatest
|
|
|
|
common divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) via
|
|
|
|
[euclidean
|
|
|
|
algorithm](https://crypto.stanford.edu/pbc/notes/numbertheory/euclid.html)
|
|
|
|
|
2024-02-18 21:52:35 +01:00
|
|
|
$$
|
|
|
|
\phi(n) = (p-1)(q-1)
|
|
|
|
$$
|
2024-02-18 21:23:15 +01:00
|
|
|
|
2024-02-18 21:52:35 +01:00
|
|
|
and further
|
2022-11-12 23:18:06 +01:00
|
|
|
|
2023-04-05 19:45:15 +02:00
|
|
|
$$
|
2023-04-11 17:39:31 +02:00
|
|
|
1 < \phi < n
|
2023-04-05 19:45:15 +02:00
|
|
|
$$
|
|
|
|
|
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
Encryption, public key `e` is a prime between 2 and phi
|
2023-04-05 19:45:15 +02:00
|
|
|
$$
|
2023-04-11 17:37:55 +02:00
|
|
|
2 < e < \phi
|
2023-04-05 19:45:15 +02:00
|
|
|
$$
|
|
|
|
|
2024-02-18 21:52:35 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2022-11-12 23:18:06 +01:00
|
|
|
```python
|
|
|
|
possible_e = []
|
|
|
|
for i in range (2, phi):
|
|
|
|
if gcd(n, i) == 1 and gcd(phi, i) == 1:
|
2024-02-18 21:09:29 +01:00
|
|
|
possible_e.append()
|
2022-11-12 23:18:06 +01:00
|
|
|
```
|
|
|
|
|
|
|
|
```python
|
|
|
|
possible_d = []
|
|
|
|
for i in range (phi + 1, phi + foo):
|
|
|
|
if i * e mod phi == 1 :
|
|
|
|
possible_d.append()
|
|
|
|
```
|
2024-02-18 21:09:29 +01:00
|
|
|
|
2022-11-12 23:18:06 +01:00
|
|
|
## Euklid
|
2022-11-14 22:51:12 +01:00
|
|
|
|
|
|
|
Just a short excourse:
|
2024-02-18 21:09:29 +01:00
|
|
|
A greatest common divisior out of an example a = 32 and b = 14 would be the
|
|
|
|
groups of the following divisors
|
|
|
|
|
2022-11-14 22:51:12 +01:00
|
|
|
```sh
|
|
|
|
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.
|
2024-02-18 21:09:29 +01:00
|
|
|
|
2022-11-12 23:18:06 +01:00
|
|
|
```python
|
|
|
|
def gcd(a, b):
|
|
|
|
if b == 0:
|
|
|
|
return a
|
|
|
|
return gcd(b, a % b)
|
|
|
|
```
|
|
|
|
|
2022-11-14 22:51:12 +01:00
|
|
|
### Extended GCD
|
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
\#TODO
|
2022-11-14 22:51:12 +01:00
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
## Fermat`s Little Theorem
|
2022-11-17 00:12:56 +01:00
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
If modulus $p$ is a prime and and modulus $n$ is not a prime, p defines a
|
|
|
|
finite field (ring).
|
2022-11-17 00:12:56 +01:00
|
|
|
$$
|
|
|
|
n \in F_{p} \{0,1,...,p-1\}
|
|
|
|
$$
|
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
The field consists of elements $n$ which have an inverse $m$ resulting in $n +
|
|
|
|
m = 0$ and $n * m = 1$.
|
2022-11-17 00:12:56 +01:00
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
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
|
2022-11-17 00:12:56 +01:00
|
|
|
$$
|
|
|
|
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.
|
2022-11-14 22:51:12 +01:00
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
So a porperty of quad res are, if Quadratic Residue $QR = 1$ and Quadratic
|
|
|
|
NonResidue $QN = -1$
|
2022-11-22 00:57:32 +01:00
|
|
|
|
|
|
|
$$
|
|
|
|
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\}
|
|
|
|
$$
|
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
Legendre Symbol test via Python with
|
|
|
|
|
2022-11-22 00:57:32 +01:00
|
|
|
```python
|
|
|
|
pow(a,(p-1)/2,p)
|
|
|
|
```
|
|
|
|
|
|
|
|
[Finding the square root of integer a which is quadratic residue](http://mathcenter.oxford.emory.edu/site/math125/findingSquareRoots/)
|
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
Given $p \equiv 3\ mod\ 4$ the square root is calculated through
|
|
|
|
|
2022-11-22 00:57:32 +01:00
|
|
|
```python
|
|
|
|
pow(a,((p+1)//4),p)
|
|
|
|
```
|
|
|
|
|
|
|
|
## Tonelli-Shanks - Modular Square Root
|
|
|
|
|
|
|
|
* Find elliptic curve co-ordinates
|
|
|
|
* Precondition: modulus is not a prime
|
|
|
|
* TBD
|
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
## RSA PublicKey Extraction
|
|
|
|
|
|
|
|
### Extract n and e from RSA public key
|
|
|
|
|
|
|
|
```python
|
|
|
|
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](https://github.com/murtaza-u/zet/tree/main/20220808171808/README.md)
|
|
|
|
|
|
|
|
```python
|
|
|
|
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
|
2024-02-18 21:23:15 +01:00
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
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
|
|
|
|
|
|
|
|
```python
|
|
|
|
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
|
2024-02-18 21:23:15 +01:00
|
|
|
|
2024-02-18 21:09:29 +01:00
|
|
|
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'))
|
|
|
|
```
|
|
|
|
|
2022-11-12 23:18:06 +01:00
|
|
|
## Links
|
|
|
|
|
|
|
|
* [Encryption+Decryption](https://www.cs.drexel.edu/~jpopyack/Courses/CSP/Fa17/notes/10.1_Cryptography/RSA_Express_EncryptDecrypt_v2.html)
|
2022-11-14 22:51:12 +01:00
|
|
|
* [Extended GCD](http://www-math.ucdenver.edu/~wcherowi/courses/m5410/exeucalg.html)
|