Files
CSC110/07-cryptography/05-rsa-cryptosystem-implementation.html
T
Hykilpikonna 6fffdf686a deploy
2021-12-07 22:28:01 -05:00

269 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>7.5 Implementing RSA in Python</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">7.5 Implementing RSA in Python</h1>
</header>
<section>
<p>In the previous section we defined the RSA cryptosystem that used both a public key and private key to send encrypted messages between two parties. In this section, we will see how to implement the RSA cryptosystem in Python. First, we will see how to generate a private key when given two prime numbers. Second, we will see how to encrypt and decrypt a single number. Finally, we will see how to encrypt and decrypt text.</p>
<h2 id="key-generation">Key generation</h2>
<p>Here is our implementation of the first phase of RSA: generating the public-private key pair. In this implementation, we will assume that the prime numbers <span class="math inline">\(p\)</span> and <span class="math inline">\(q\)</span> are given.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> Algorithms do exist for generating these prime numbers, we just wont go over them here.</span></p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">def</span> rsa_generate_key(p: <span class="bu">int</span>, q: <span class="bu">int</span>) <span class="op">-&gt;</span> <span class="op">\</span></span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="bu">tuple</span>[<span class="bu">tuple</span>[<span class="bu">int</span>, <span class="bu">int</span>, <span class="bu">int</span>], <span class="bu">tuple</span>[<span class="bu">int</span>, <span class="bu">int</span>]]:</span>
<span id="cb1-3"><a href="#cb1-3"></a> <span class="co">&quot;&quot;&quot;Return an RSA key pair generated using primes p and q.</span></span>
<span id="cb1-4"><a href="#cb1-4"></a></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> The return value is a tuple containing two tuples:</span></span>
<span id="cb1-6"><a href="#cb1-6"></a><span class="co"> 1. The first tuple is the private key, containing (p, q, d).</span></span>
<span id="cb1-7"><a href="#cb1-7"></a><span class="co"> 2. The second tuple is the public key, containing (n, e).</span></span>
<span id="cb1-8"><a href="#cb1-8"></a></span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="co"> Preconditions:</span></span>
<span id="cb1-10"><a href="#cb1-10"></a><span class="co"> - p and q are prime</span></span>
<span id="cb1-11"><a href="#cb1-11"></a><span class="co"> - p != q</span></span>
<span id="cb1-12"><a href="#cb1-12"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-13"><a href="#cb1-13"></a> <span class="co"># Compute the product of p and q</span></span>
<span id="cb1-14"><a href="#cb1-14"></a> n <span class="op">=</span> p <span class="op">*</span> q</span>
<span id="cb1-15"><a href="#cb1-15"></a></span>
<span id="cb1-16"><a href="#cb1-16"></a> <span class="co"># Choose e such that gcd(e, phi_n) == 1.</span></span>
<span id="cb1-17"><a href="#cb1-17"></a> phi_n <span class="op">=</span> (p <span class="op">-</span> <span class="dv">1</span>) <span class="op">*</span> (q <span class="op">-</span> <span class="dv">1</span>)</span>
<span id="cb1-18"><a href="#cb1-18"></a></span>
<span id="cb1-19"><a href="#cb1-19"></a> <span class="co"># Since e is chosen randomly, we repeat the random choice</span></span>
<span id="cb1-20"><a href="#cb1-20"></a> <span class="co"># until e is coprime to phi_n.</span></span>
<span id="cb1-21"><a href="#cb1-21"></a> e <span class="op">=</span> random.randint(<span class="dv">2</span>, phi_n <span class="op">-</span> <span class="dv">1</span>)</span>
<span id="cb1-22"><a href="#cb1-22"></a> <span class="cf">while</span> math.gcd(e, phi_n) <span class="op">!=</span> <span class="dv">1</span>:</span>
<span id="cb1-23"><a href="#cb1-23"></a> e <span class="op">=</span> random.randint(<span class="dv">2</span>, phi_n <span class="op">-</span> <span class="dv">1</span>)</span>
<span id="cb1-24"><a href="#cb1-24"></a></span>
<span id="cb1-25"><a href="#cb1-25"></a> <span class="co"># Choose d such that e * d % phi_n = 1.</span></span>
<span id="cb1-26"><a href="#cb1-26"></a> <span class="co"># Notice that we&#39;re using our modular_inverse from our work in the last chapter!</span></span>
<span id="cb1-27"><a href="#cb1-27"></a> d <span class="op">=</span> modular_inverse(e, phi_n)</span>
<span id="cb1-28"><a href="#cb1-28"></a></span>
<span id="cb1-29"><a href="#cb1-29"></a> <span class="cf">return</span> ((p, q, d), (n, e))</span></code></pre></div>
<p>The algorithm makes use of both a <code>while</code> loop and the <code>random</code> module. The <code>random</code> module is used to generate an <code>e</code>, but the while loop ensures that the <code>e</code> we finally choose is valid. That is, we continue to randomly generate an <code>e</code> <em>until</em> <code>e</code> and <code>phi_n</code> have a greatest common divisor of 1. Once we have <code>e</code>, we can finally calculate the last part of our private key: <code>d</code>. To do so, we make use of the <code>modular_inverse</code> function we defined in the last chapter (which, in turn, used the <code>extended_gcd</code> function).</p>
<h2 id="encrypting-and-decrypting-a-number">Encrypting and decrypting a number</h2>
<p>Next, lets look at RSA encryption, which only uses the public key. Recall that the plaintext here is a number <span class="math inline">\(m\)</span> between <span class="math inline">\(1\)</span> and <span class="math inline">\(n - 1\)</span> inclusive, and the ciphertext is another number <span class="math inline">\(c = m^e ~\%~ n\)</span>. This mathematical definition translates directly into Python:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">def</span> rsa_encrypt(public_key: <span class="bu">tuple</span>[<span class="bu">int</span>, <span class="bu">int</span>], plaintext: <span class="bu">int</span>) <span class="op">-&gt;</span> <span class="bu">int</span>:</span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">&quot;&quot;&quot;Encrypt the given plaintext using the recipient&#39;s public key.</span></span>
<span id="cb2-3"><a href="#cb2-3"></a></span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="co"> Preconditions:</span></span>
<span id="cb2-5"><a href="#cb2-5"></a><span class="co"> - public_key is a valid RSA public key (n, e)</span></span>
<span id="cb2-6"><a href="#cb2-6"></a><span class="co"> - 0 &lt; plaintext &lt; public_key[0]</span></span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-8"><a href="#cb2-8"></a> n, e <span class="op">=</span> public_key</span>
<span id="cb2-9"><a href="#cb2-9"></a></span>
<span id="cb2-10"><a href="#cb2-10"></a> encrypted <span class="op">=</span> (plaintext <span class="op">**</span> e) <span class="op">%</span> n</span>
<span id="cb2-11"><a href="#cb2-11"></a></span>
<span id="cb2-12"><a href="#cb2-12"></a> <span class="cf">return</span> encrypted</span></code></pre></div>
<p>The implementation for RSA decryption is almost identical, except we use the private key (i.e., <code>d</code>) for exponentiation.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">def</span> rsa_decrypt(private_key: <span class="bu">tuple</span>[<span class="bu">int</span>, <span class="bu">int</span>, <span class="bu">int</span>] ciphertext: <span class="bu">int</span>) <span class="op">-&gt;</span> <span class="bu">int</span>:</span>
<span id="cb3-2"><a href="#cb3-2"></a> <span class="co">&quot;&quot;&quot;Decrypt the given ciphertext using the recipient&#39;s private key.</span></span>
<span id="cb3-3"><a href="#cb3-3"></a></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="co"> Preconditions:</span></span>
<span id="cb3-5"><a href="#cb3-5"></a><span class="co"> - private_key is a valid RSA private key (p, q, d)</span></span>
<span id="cb3-6"><a href="#cb3-6"></a><span class="co"> - 0 &lt; ciphertext &lt; private_key[0] * private_key[1]</span></span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-8"><a href="#cb3-8"></a> p, q, d <span class="op">=</span> private_key</span>
<span id="cb3-9"><a href="#cb3-9"></a> n <span class="op">=</span> p <span class="op">*</span> q</span>
<span id="cb3-10"><a href="#cb3-10"></a></span>
<span id="cb3-11"><a href="#cb3-11"></a> decrypted <span class="op">=</span> (ciphertext <span class="op">**</span> d) <span class="op">%</span> n</span>
<span id="cb3-12"><a href="#cb3-12"></a></span>
<span id="cb3-13"><a href="#cb3-13"></a> <span class="cf">return</span> decrypted</span></code></pre></div>
<h2 id="encrypting-and-decrypting-text-using-rsa">Encrypting and decrypting text using RSA</h2>
<p>The above implementation of RSA is correct, but is a little unsatisfying because it encrypts numbers instead of strings, like we saw with the Caesar cipher and One-Time Pad cryptosystem. So next, well see how to adapt the RSA encryption and decryption algorithms to strings.</p>
<p>Our strategy will be to take a string and break it up into individual characters and encrypt each character, just as we did with the Caesar cipher. Well use this approach for both encryption and decryption, using <code>ord</code>/<code>chr</code> to convert between characters and numbers, and a string accumulator to keep track of the encrypted/decrypted results.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">def</span> rsa_encrypt_text(public_key: <span class="bu">tuple</span>[<span class="bu">int</span>, <span class="bu">int</span>], plaintext: <span class="bu">str</span>) <span class="op">-&gt;</span> <span class="bu">str</span>:</span>
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">&quot;&quot;&quot;Encrypt the given plaintext using the recipient&#39;s public key.</span></span>
<span id="cb4-3"><a href="#cb4-3"></a></span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="co"> Preconditions:</span></span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="co"> - public_key is a valid RSA public key (n, e)</span></span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="co"> - all({0 &lt; ord(c) &lt; public_key[0] for c in plaintext})</span></span>
<span id="cb4-7"><a href="#cb4-7"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb4-8"><a href="#cb4-8"></a> n, e <span class="op">=</span> public_key</span>
<span id="cb4-9"><a href="#cb4-9"></a></span>
<span id="cb4-10"><a href="#cb4-10"></a> encrypted <span class="op">=</span> <span class="st">&#39;&#39;</span></span>
<span id="cb4-11"><a href="#cb4-11"></a> <span class="cf">for</span> letter <span class="kw">in</span> plaintext:</span>
<span id="cb4-12"><a href="#cb4-12"></a> <span class="co"># Note: we could have also used our rsa_encrypt function here instead</span></span>
<span id="cb4-13"><a href="#cb4-13"></a> encrypted <span class="op">=</span> encrypted <span class="op">+</span> <span class="bu">chr</span>((<span class="bu">ord</span>(letter) <span class="op">**</span> e) <span class="op">%</span> n)</span>
<span id="cb4-14"><a href="#cb4-14"></a></span>
<span id="cb4-15"><a href="#cb4-15"></a> <span class="cf">return</span> encrypted</span>
<span id="cb4-16"><a href="#cb4-16"></a></span>
<span id="cb4-17"><a href="#cb4-17"></a></span>
<span id="cb4-18"><a href="#cb4-18"></a><span class="kw">def</span> rsa_decrypt_text(private_key: <span class="bu">tuple</span>[<span class="bu">int</span>, <span class="bu">int</span>, <span class="bu">int</span>], ciphertext: <span class="bu">str</span>) <span class="op">-&gt;</span> <span class="bu">str</span>:</span>
<span id="cb4-19"><a href="#cb4-19"></a> <span class="co">&quot;&quot;&quot;Decrypt the given ciphertext using the recipient&#39;s private key.</span></span>
<span id="cb4-20"><a href="#cb4-20"></a></span>
<span id="cb4-21"><a href="#cb4-21"></a><span class="co"> Preconditions:</span></span>
<span id="cb4-22"><a href="#cb4-22"></a><span class="co"> - private_key is a valid RSA private key (p, q, d)</span></span>
<span id="cb4-23"><a href="#cb4-23"></a><span class="co"> - all({0 &lt; ord(c) &lt; private_key[0] * private_key[1] for c in ciphertext})</span></span>
<span id="cb4-24"><a href="#cb4-24"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb4-25"><a href="#cb4-25"></a> p, q, d <span class="op">=</span> private_key</span>
<span id="cb4-26"><a href="#cb4-26"></a> n <span class="op">=</span> p <span class="op">*</span> q</span>
<span id="cb4-27"><a href="#cb4-27"></a></span>
<span id="cb4-28"><a href="#cb4-28"></a> decrypted <span class="op">=</span> <span class="st">&#39;&#39;</span></span>
<span id="cb4-29"><a href="#cb4-29"></a> <span class="cf">for</span> letter <span class="kw">in</span> ciphertext:</span>
<span id="cb4-30"><a href="#cb4-30"></a> <span class="co"># Note: we could have also used our rsa_decrypt function here instead</span></span>
<span id="cb4-31"><a href="#cb4-31"></a> decrypted <span class="op">=</span> decrypted <span class="op">+</span> <span class="bu">chr</span>((<span class="bu">ord</span>(letter) <span class="op">**</span> d) <span class="op">%</span> n)</span>
<span id="cb4-32"><a href="#cb4-32"></a></span>
<span id="cb4-33"><a href="#cb4-33"></a> <span class="cf">return</span> decrypted</span></code></pre></div>
<!-- ### Putting it all together
Let us use the prime numbers 23 and 31 as $p$ and $q$, respectively, to generate our private and public key.
Next, Bob will send the message that `'Shannon is also cool'` using only the public key.
Alice can decrypt the message using her own private key along with the public key.
```python
if __name__ == '__main__':
# 23 and 31 are prime numbers
private_key, public_key = rsa_generate_key(23, 31)
print(f'Private key: {private_key}')
print(f'Public key: {public_key}')
message = 'Shannon is also cool'
print(f'Message: {message_key}')
# Bob uses only the public key to encrypt the message
encrypted_msg = rsa_encrypt(public_key, message)
print(f'Encrypted: {encrypted_msg}')
# Alice uses her private key to decrypt the message
decrypted_msg = rsa_decrypt(private_key, encrypted_msg)
print(f'Decrypted: {decrypted_msg}')
``` -->
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>