# RSA What is interesting about an RSA key: The modulus is `N` and it is `p * q = N` through factorization. `p` and `q` are primes. 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). There is: $$ \phi(N) = (p-1)(q-1) $$ and further $$ 1\ <\ \phi < N $$ The public key is `(N, e)`. If you create a real key e.g. through OpenSSH, the default for `e` (encryption) is `65537` or `0x10001` in hex. The private key is `(N, d)` and `d` (decryption) is the modular multiplicative inverse of `e` and $\phi$. $$ Cipher = msg^{d}\ mod\ \phi $$ $$ Cleartext = cipher^{e}\ mod\ \phi $$ Further properties: public key `e` is a prime between 2 and phi $$ 2 < e < \phi $$ Private key `d` is the multiplicative inverse modulo $\phi(N)$ $$ 1\ \equiv de\ mod\ \phi(N) $$ $$ de\ \equiv 1\ mod\ \phi(N) $$ This means `d` can be calculated by $$ d \equiv\ e^{-1}\ mod\ \phi(N) $$ --- `e` and `d` may be found through the following Python snippets ```python possible_e = [] for i in range (2, phi): if gcd(n, i) == 1 and gcd(phi, i) == 1: possible_e.append() ``` ```python 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 ```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. ```python 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 ```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/) Given $p \equiv 3\ mod\ 4$ the square root is calculated through ```python 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 ```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