<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://oliverkovacs.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://oliverkovacs.dev/" rel="alternate" type="text/html" /><updated>2026-05-07T10:23:59+02:00</updated><id>https://oliverkovacs.dev/feed.xml</id><title type="html">Oliver Kovacs</title><subtitle></subtitle><entry><title type="html">Fast RSA</title><link href="https://oliverkovacs.dev/writeup/2025/07/07/fast-rsa.html" rel="alternate" type="text/html" title="Fast RSA" /><published>2025-07-07T00:00:00+02:00</published><updated>2025-07-07T00:00:00+02:00</updated><id>https://oliverkovacs.dev/writeup/2025/07/07/fast-rsa</id><content type="html" xml:base="https://oliverkovacs.dev/writeup/2025/07/07/fast-rsa.html"><![CDATA[<p><strong>ACSC 2025 - Final</strong></p>

<p>Category: <code class="language-plaintext highlighter-rouge">crypto</code></p>

<h2 id="description">Description</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hey choom! I got my hands on some fresh new hardware, a chip that can do military-grade encryption at lightning speed.

I'm testing out it's signature features, and since you're a god-tier netrunner, maybe you can learn how to sign stuff yourself if you watch my bot do it enough?
</code></pre></div></div>
<p>Attachments: [
<a href="/assets/zip/fast-rsa.zip">fast-rsa.zip</a>
]</p>

<h2 id="problem">Problem</h2>

<p>The program generates an RSA keypair and outputs the modulus \(n\)
and the uppermost 32 bits of \(d\).</p>

<p>It then repeatedly reads \(m, b \in \mathbb Z\) and calculates the signature \(s = m^d \mod n\).
This is done in <a href="https://en.wikipedia.org/wiki/Montgomery_modular_multiplication">Montgomery</a> form.
Then \(s\) and whether any of the two multiplications in the \(b\)th step of exponentiation
required the conditional subtraction is revealed.</p>

<p>The goal is to determine \(d\).</p>

<h2 id="solution">Solution</h2>

<blockquote>
  <p>Disclosure: I was not able to solve this challenge at the competition.</p>
</blockquote>

<p>We can <em>almost</em> use an attack by Walter &amp; Thompson<sup>1</sup>.
You can find my implementation <a href="https://github.com/OliverKovacs/montgomery-sidechannel/">here</a>.</p>

<p>The only difference is that in each step it is not known which of the two
subtractions were needed, i. e. the observation vector is “squashed”.
The solution is simple: the algorithm has to be run on multiple
squashed observation vectors simultaneously.
In practice 2 are enough.
The algorithm calculates \(d\) in ~1 s,
however getting the observation vectors from the remote takes considerably more time.</p>

<h2 id="implementation">Implementation</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env python3
</span>
<span class="kn">import</span> <span class="n">sys</span>
<span class="kn">import</span> <span class="n">time</span>
<span class="kn">import</span> <span class="n">pwn</span>

<span class="n">sys</span><span class="p">.</span><span class="nf">setrecursionlimit</span><span class="p">(</span><span class="mi">2500</span><span class="p">)</span>

<span class="c1"># https://en.wikipedia.org/wiki/Montgomery_modular_multiplication
</span><span class="k">class</span> <span class="nc">Montgomery</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
        <span class="nf">assert</span><span class="p">(</span><span class="n">n</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span>
        <span class="n">self</span><span class="p">.</span><span class="n">N</span> <span class="o">=</span> <span class="n">n</span>
        <span class="n">self</span><span class="p">.</span><span class="n">nbits</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">N</span><span class="p">.</span><span class="nf">bit_length</span><span class="p">()</span>
        <span class="n">self</span><span class="p">.</span><span class="n">R</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">self</span><span class="p">.</span><span class="n">nbits</span>
        <span class="n">self</span><span class="p">.</span><span class="n">R_inv</span> <span class="o">=</span> <span class="nf">pow</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">R</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">N</span><span class="p">)</span>
        <span class="n">self</span><span class="p">.</span><span class="n">N_prime</span> <span class="o">=</span> <span class="o">-</span><span class="nf">pow</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">N</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">R</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">to_montgomery</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="nf">return </span><span class="p">(</span><span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="n">self</span><span class="p">.</span><span class="n">nbits</span><span class="p">)</span> <span class="o">%</span> <span class="n">self</span><span class="p">.</span><span class="n">N</span>

    <span class="k">def</span> <span class="nf">from_montgomery</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="nf">return </span><span class="p">(</span><span class="n">x</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">R_inv</span><span class="p">)</span> <span class="o">%</span> <span class="n">self</span><span class="p">.</span><span class="n">N</span>

    <span class="k">def</span> <span class="nf">multiply</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
        <span class="n">T</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span>
        <span class="n">m</span> <span class="o">=</span> <span class="p">((</span><span class="n">T</span> <span class="o">%</span> <span class="n">self</span><span class="p">.</span><span class="n">R</span><span class="p">)</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">N_prime</span><span class="p">)</span> <span class="o">%</span> <span class="n">self</span><span class="p">.</span><span class="n">R</span>
        <span class="n">t</span> <span class="o">=</span> <span class="p">(</span><span class="n">T</span> <span class="o">+</span> <span class="n">m</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">N</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="n">self</span><span class="p">.</span><span class="n">nbits</span>
        <span class="nf">return </span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="bp">False</span><span class="p">)</span> <span class="k">if</span> <span class="n">t</span> <span class="o">&lt;</span> <span class="n">self</span><span class="p">.</span><span class="n">N</span> <span class="nf">else </span><span class="p">(</span><span class="n">t</span> <span class="o">-</span> <span class="n">self</span><span class="p">.</span><span class="n">N</span><span class="p">,</span> <span class="bp">True</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">parse_res</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="k">return</span> <span class="nf">int</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="n">a</span><span class="p">)[</span><span class="mi">1</span><span class="p">].</span><span class="nf">split</span><span class="p">(</span><span class="n">b</span><span class="p">)[</span><span class="mi">0</span><span class="p">][</span><span class="mi">2</span><span class="p">:],</span> <span class="mi">16</span><span class="p">)</span>

<span class="n">CUTOFF</span> <span class="o">=</span> <span class="mi">3</span>

<span class="k">def</span> <span class="nf">Z_prime_next</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">A_bar</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">bit</span><span class="p">):</span>
    <span class="n">Y</span><span class="p">,</span> <span class="n">z1</span> <span class="o">=</span> <span class="n">M</span><span class="p">.</span><span class="nf">multiply</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>
    <span class="n">z2</span> <span class="o">=</span> <span class="bp">False</span>
    <span class="k">if</span> <span class="n">bit</span><span class="p">:</span>
        <span class="n">Y</span><span class="p">,</span> <span class="n">z2</span> <span class="o">=</span> <span class="n">M</span><span class="p">.</span><span class="nf">multiply</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">A_bar</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">Y</span><span class="p">,</span> <span class="n">z1</span> <span class="ow">or</span> <span class="n">z2</span>

<span class="k">def</span> <span class="nf">attack_bruteforce</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">A_bar</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">S_bar</span><span class="p">,</span> <span class="n">dt</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">CUTOFF</span><span class="p">):</span>
        <span class="n">Y</span><span class="p">,</span> <span class="n">z1</span> <span class="o">=</span> <span class="n">M</span><span class="p">.</span><span class="nf">multiply</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">CUTOFF</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">Y</span> <span class="o">==</span> <span class="n">S_bar</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">True</span><span class="p">,</span> <span class="n">dt</span> <span class="o">+</span> <span class="n">i</span>
        <span class="n">Y</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">M</span><span class="p">.</span><span class="nf">multiply</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">A_bar</span><span class="p">)</span>

    <span class="k">return</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">None</span>

<span class="c1"># inv: first t bits of dt are assumed to be correct
</span><span class="k">def</span> <span class="nf">attack_impl</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">As_bar</span><span class="p">,</span> <span class="n">Ss_bar</span><span class="p">,</span> <span class="n">Zs</span><span class="p">,</span> <span class="n">Ys</span><span class="p">,</span> <span class="n">Zs_prime</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">dt</span><span class="p">,</span> <span class="n">H</span><span class="p">,</span> <span class="n">guess</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">t</span> <span class="o">%</span> <span class="mi">10</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">attack_impl</span><span class="sh">'</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">dt</span><span class="p">)</span>

    <span class="n">nbits</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">Zs</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
    <span class="k">if</span> <span class="n">guess</span> <span class="o">!=</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">t</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="n">dt</span> <span class="o">=</span> <span class="n">dt</span> <span class="o">|</span> <span class="p">(</span><span class="n">guess</span> <span class="o">&lt;&lt;</span> <span class="n">nbits</span> <span class="o">-</span> <span class="n">t</span><span class="p">)</span>
        <span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="nc">Z_prime_next</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">A_bar</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">guess</span><span class="p">)</span> <span class="k">for</span> <span class="n">A_bar</span><span class="p">,</span> <span class="n">Y</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">As_bar</span><span class="p">,</span> <span class="n">Ys</span><span class="p">)]</span>
        <span class="n">Ys</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span> <span class="k">for</span> <span class="n">Y</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">tmp</span><span class="p">]</span>
        <span class="n">Zs_prime</span> <span class="o">=</span> <span class="p">[</span><span class="n">Z_prime</span> <span class="o">+</span> <span class="p">[</span><span class="n">z</span><span class="p">]</span> <span class="k">for</span> <span class="n">Z_prime</span><span class="p">,</span> <span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">Zs_prime</span><span class="p">,</span> <span class="n">tmp</span><span class="p">)]</span>

    <span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="n">nbits</span> <span class="o">-</span> <span class="n">CUTOFF</span><span class="p">:</span>
        <span class="k">return</span> <span class="nf">attack_bruteforce</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">As_bar</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">Ys</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">Ss_bar</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">dt</span><span class="p">)</span>

    <span class="k">if</span> <span class="nf">any</span><span class="p">([</span><span class="n">Z</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">t</span><span class="p">]</span> <span class="o">!=</span> <span class="n">Z_prime</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">t</span><span class="p">]</span> <span class="k">for</span> <span class="n">Z</span><span class="p">,</span> <span class="n">Z_prime</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">Zs</span><span class="p">,</span> <span class="n">Zs_prime</span><span class="p">)]):</span>
        <span class="k">return</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">None</span>

    <span class="k">if</span> <span class="n">t</span> <span class="o">&lt;</span> <span class="mi">32</span><span class="p">:</span>
        <span class="n">guess</span> <span class="o">=</span> <span class="ow">not</span> <span class="ow">not</span> <span class="p">(</span><span class="n">H</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="mi">31</span> <span class="o">-</span> <span class="n">t</span><span class="p">)))</span>
        <span class="k">return</span> <span class="nf">attack_impl</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">As_bar</span><span class="p">,</span> <span class="n">Ss_bar</span><span class="p">,</span> <span class="n">Zs</span><span class="p">,</span> <span class="n">Ys</span><span class="p">,</span> <span class="n">Zs_prime</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">dt</span><span class="p">,</span> <span class="n">H</span><span class="p">,</span> <span class="n">guess</span><span class="p">)</span>

    <span class="n">guess</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="nf">any</span><span class="p">([</span><span class="n">Z</span><span class="p">[</span><span class="n">t</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">Z_prime</span><span class="p">[</span><span class="n">t</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">Z</span><span class="p">,</span> <span class="n">Z_prime</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">Zs</span><span class="p">,</span> <span class="n">Zs_prime</span><span class="p">)]))</span>
    <span class="n">s</span><span class="p">,</span> <span class="n">d</span> <span class="o">=</span> <span class="nf">attack_impl</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">As_bar</span><span class="p">,</span> <span class="n">Ss_bar</span><span class="p">,</span> <span class="n">Zs</span><span class="p">,</span> <span class="n">Ys</span><span class="p">,</span> <span class="n">Zs_prime</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">dt</span><span class="p">,</span> <span class="n">H</span><span class="p">,</span> <span class="n">guess</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">s</span><span class="p">:</span>
        <span class="n">s</span><span class="p">,</span> <span class="n">d</span> <span class="o">=</span> <span class="nf">attack_impl</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">As_bar</span><span class="p">,</span> <span class="n">Ss_bar</span><span class="p">,</span> <span class="n">Zs</span><span class="p">,</span> <span class="n">Ys</span><span class="p">,</span> <span class="n">Zs_prime</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">dt</span><span class="p">,</span> <span class="n">H</span><span class="p">,</span> <span class="ow">not</span> <span class="n">guess</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">s</span><span class="p">,</span> <span class="n">d</span>

<span class="k">def</span> <span class="nf">attack</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">As</span><span class="p">,</span> <span class="n">Ss</span><span class="p">,</span> <span class="n">Zs</span><span class="p">,</span> <span class="n">d_upper</span><span class="p">):</span>
    <span class="n">M</span> <span class="o">=</span> <span class="nc">Montgomery</span><span class="p">(</span><span class="n">N</span><span class="p">)</span>
    <span class="n">As_bar</span> <span class="o">=</span> <span class="p">[</span><span class="n">M</span><span class="p">.</span><span class="nf">to_montgomery</span><span class="p">(</span><span class="n">A</span><span class="p">)</span> <span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">As</span><span class="p">]</span>
    <span class="n">Ss_bar</span> <span class="o">=</span> <span class="p">[</span><span class="n">M</span><span class="p">.</span><span class="nf">to_montgomery</span><span class="p">(</span><span class="n">S</span><span class="p">)</span> <span class="k">for</span> <span class="n">S</span> <span class="ow">in</span> <span class="n">Ss</span><span class="p">]</span>
    <span class="n">Ys</span> <span class="o">=</span> <span class="p">[</span><span class="n">M</span><span class="p">.</span><span class="nf">to_montgomery</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">As</span><span class="p">]</span>
    <span class="n">Zs_prime</span> <span class="o">=</span> <span class="p">[[]</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">As</span><span class="p">]</span>
    <span class="n">s</span><span class="p">,</span> <span class="n">d</span> <span class="o">=</span> <span class="nf">attack_impl</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="n">As_bar</span><span class="p">,</span> <span class="n">Ss_bar</span><span class="p">,</span> <span class="n">Zs</span><span class="p">,</span> <span class="n">Ys</span><span class="p">,</span> <span class="n">Zs_prime</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">d_upper</span><span class="p">)</span>
    <span class="nf">assert</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">d</span>

<span class="k">def</span> <span class="nf">get_sig</span><span class="p">(</span><span class="n">A</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="nf">sendline</span><span class="p">(</span><span class="nf">hex</span><span class="p">(</span><span class="n">A</span><span class="p">).</span><span class="nf">encode</span><span class="p">()</span> <span class="o">+</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\n</span><span class="s">0</span><span class="sh">'</span><span class="p">)</span>
    <span class="k">return</span> <span class="nf">parse_res</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="nf">readuntil</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">challenge: </span><span class="sh">'</span><span class="p">),</span> <span class="sa">b</span><span class="sh">'</span><span class="s">Signature: </span><span class="sh">'</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\n</span><span class="sh">'</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">is_expensive</span><span class="p">(</span><span class="n">res</span><span class="p">):</span>
    <span class="n">GOOD</span> <span class="o">=</span> <span class="p">[</span>
        <span class="sa">b</span><span class="sh">'</span><span class="s"> is a cool number</span><span class="sh">'</span><span class="p">,</span>
        <span class="sa">b</span><span class="sh">'</span><span class="s"> is really quite something</span><span class="sh">'</span><span class="p">,</span>
        <span class="sa">b</span><span class="sh">'</span><span class="s"> likes to save me money</span><span class="sh">'</span>
    <span class="p">]</span>
    <span class="k">return</span> <span class="ow">not</span> <span class="nf">any</span><span class="p">([</span><span class="n">e</span> <span class="ow">in</span> <span class="n">res</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">GOOD</span><span class="p">])</span>

<span class="k">def</span> <span class="nf">get_vec</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">bits</span><span class="p">):</span>
    <span class="n">BATCH</span> <span class="o">=</span> <span class="mi">32</span>
    <span class="n">Z</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">bits</span><span class="p">,</span> <span class="n">BATCH</span><span class="p">):</span>
        <span class="nf">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
        <span class="n">lines</span> <span class="o">=</span> <span class="p">[</span><span class="nf">hex</span><span class="p">(</span><span class="n">A</span><span class="p">)</span> <span class="o">+</span> <span class="sh">'</span><span class="se">\n</span><span class="sh">'</span> <span class="o">+</span> <span class="nf">str</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="n">j</span><span class="p">)</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">BATCH</span><span class="p">)]</span>
        <span class="n">p</span><span class="p">.</span><span class="nf">sendline</span><span class="p">(</span><span class="sh">'</span><span class="se">\n</span><span class="sh">'</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">lines</span><span class="p">).</span><span class="nf">encode</span><span class="p">())</span>

        <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">BATCH</span><span class="p">):</span>
            <span class="n">Z</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">is_expensive</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="nf">readuntil</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">challenge: </span><span class="sh">'</span><span class="p">)))</span>
    <span class="k">return</span> <span class="n">Z</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

<span class="n">p</span> <span class="o">=</span> <span class="n">pwn</span><span class="p">.</span><span class="nf">remote</span><span class="p">(</span><span class="sh">'</span><span class="s">127.0.0.1</span><span class="sh">'</span><span class="p">,</span> <span class="mi">5000</span><span class="p">)</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="nf">readuntil</span><span class="p">(</span><span class="sh">'</span><span class="s">challenge: </span><span class="sh">'</span><span class="p">)</span>
<span class="n">n</span> <span class="o">=</span> <span class="nf">parse_res</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="s">n=</span><span class="sh">'</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\n</span><span class="sh">'</span><span class="p">)</span>
<span class="n">d_upper</span> <span class="o">=</span> <span class="nf">parse_res</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="s">d: </span><span class="sh">'</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\n</span><span class="sh">'</span><span class="p">)</span>         <span class="c1"># crib
</span><span class="n">As</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>                                     <span class="c1"># messages
</span><span class="n">Ss</span> <span class="o">=</span> <span class="p">[</span><span class="nf">get_sig</span><span class="p">(</span><span class="n">A</span><span class="p">)</span> <span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">As</span><span class="p">]</span>                   <span class="c1"># signatures
</span><span class="n">Zs</span> <span class="o">=</span> <span class="p">[</span><span class="nf">get_vec</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">n</span><span class="p">.</span><span class="nf">bit_length</span><span class="p">())</span> <span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">As</span><span class="p">]</span>   <span class="c1"># observation vectors
</span><span class="n">t1</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="nf">time</span><span class="p">()</span>
<span class="n">d</span> <span class="o">=</span> <span class="nf">attack</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">As</span><span class="p">,</span> <span class="n">Ss</span><span class="p">,</span> <span class="n">Zs</span><span class="p">,</span> <span class="n">d_upper</span><span class="p">)</span>
<span class="n">t2</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="nf">time</span><span class="p">()</span>

<span class="n">p</span><span class="p">.</span><span class="nf">sendline</span><span class="p">(</span><span class="sa">b</span><span class="sh">''</span><span class="p">)</span>
<span class="n">msg</span> <span class="o">=</span> <span class="nf">parse_res</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="nf">readline</span><span class="p">(),</span> <span class="sa">b</span><span class="sh">'</span><span class="s">message: </span><span class="sh">'</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\n</span><span class="sh">'</span><span class="p">)</span>
<span class="n">sig</span> <span class="o">=</span> <span class="nf">pow</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
<span class="n">p</span><span class="p">.</span><span class="nf">sendline</span><span class="p">(</span><span class="nf">hex</span><span class="p">(</span><span class="n">sig</span><span class="p">).</span><span class="nf">encode</span><span class="p">())</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">{d_upper = }</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">As</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">Ss</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">n</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">d</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">msg</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">sig</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">CUTOFF</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s"># calculated in </span><span class="sh">'</span><span class="p">,</span> <span class="n">t2</span> <span class="o">-</span> <span class="n">t1</span><span class="p">,</span> <span class="sh">'</span><span class="s">s</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="nf">readline</span><span class="p">())</span>
</code></pre></div></div>

<h2 id="references">References</h2>

<ol>
  <li><em>C. D. Walter and S. Thompson, “<a href="https://link.springer.com/chapter/10.1007/3-540-45353-9_15">Distinguishing exponent digits by observing modular subtractions</a>,” in Topics in Cryptology — CT-RSA 2001, ser. Lecture Notes in Computer Science, vol. 2020. Springer Verlag, 2001, pp. 192–207. subsection 3.3</em></li>
</ol>]]></content><author><name>Oliver Kovacs</name></author><category term="writeup" /><summary type="html"><![CDATA[ACSC 2025 - Final]]></summary></entry><entry><title type="html">Installing Vivado on NixOS</title><link href="https://oliverkovacs.dev/blog/2025/05/02/installing-vivado-on-nixos.html" rel="alternate" type="text/html" title="Installing Vivado on NixOS" /><published>2025-05-02T00:00:00+02:00</published><updated>2025-05-02T00:00:00+02:00</updated><id>https://oliverkovacs.dev/blog/2025/05/02/installing-vivado-on-nixos</id><content type="html" xml:base="https://oliverkovacs.dev/blog/2025/05/02/installing-vivado-on-nixos.html"><![CDATA[<h2 id="introduction">Introduction</h2>

<p>I hate <a href="https://en.wikipedia.org/wiki/Vivado">Vivado</a> but I am forced to use
it at university. It is notoriously complicated to set up on Linux and using
NixOS has caused me extra difficulties.</p>

<p>In this post I will detail how to install Vivado 2019.2 on <code class="language-plaintext highlighter-rouge">nixos-unstable</code>.
Other combinations of versions may or may not work.</p>

<h2 id="installing">Installing</h2>

<ol>
  <li>
    <p>Download <code class="language-plaintext highlighter-rouge">Vivado HLx 2019.2: All OS installer Single-File Download</code> from the
<a href="https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html">Xilinx website</a>.</p>
  </li>
  <li>Extract it using
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~/Downloads <span class="o">&amp;&amp;</span> <span class="nb">tar </span>xzvf Xilinx_Vivado_2019.2_1106_2127.tar.gz
</code></pre></div>    </div>
  </li>
  <li>In the extracted directory create a <code class="language-plaintext highlighter-rouge">shell.nix</code> file with the following content:
    <div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># shell.nix</span>
<span class="p">{</span> <span class="nv">pkgs</span> <span class="o">?</span> <span class="kr">import</span> <span class="o">&lt;</span><span class="nv">nixpkgs</span><span class="o">&gt;</span> <span class="p">{</span> <span class="p">}</span> <span class="p">}:</span>
<span class="p">(</span><span class="nv">pkgs</span><span class="o">.</span><span class="nv">buildFHSEnv</span> <span class="p">{</span>
  <span class="nv">name</span> <span class="o">=</span> <span class="s2">"vivado-env"</span><span class="p">;</span>
  <span class="nv">targetPkgs</span> <span class="o">=</span> <span class="nv">pkgs</span><span class="p">:</span> <span class="p">(</span>
 <span class="kn">with</span> <span class="nv">pkgs</span><span class="p">;</span> <span class="p">[</span>
   <span class="nv">ncurses5</span>
   <span class="nv">zlib</span> <span class="nv">libuuid</span>
   <span class="nv">bash</span> <span class="nv">coreutils</span> <span class="nv">zlib</span> <span class="nv">stdenv</span><span class="o">.</span><span class="nv">cc</span><span class="o">.</span><span class="nv">cc</span>
   <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXext</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libX11</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXrender</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXtst</span>
   <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXi</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXft</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libxcb</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libxcb</span>
   <span class="nv">freetype</span> <span class="nv">fontconfig</span> <span class="nv">glib</span> <span class="nv">gtk2</span> <span class="nv">gtk3</span>
   <span class="nv">graphviz</span> <span class="nv">gcc</span> <span class="nv">unzip</span> <span class="nv">nettools</span>
 <span class="p">]</span>
  <span class="p">);</span>
  <span class="nv">runScript</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2"> env LIBRARY_PATH=/usr/lib \</span><span class="err">
</span><span class="s2">   C_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">   CPLUS_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">   CMAKE_LIBRARY_PATH=/usr/lib \</span><span class="err">
</span><span class="s2">   CMAKE_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">   bash</span><span class="err">
</span><span class="s2">  ''</span><span class="p">;</span>
<span class="p">})</span><span class="o">.</span><span class="nv">env</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Run <code class="language-plaintext highlighter-rouge">nix-shell</code>.</p>
  </li>
  <li>
    <p>Run <code class="language-plaintext highlighter-rouge">./xsetup -b ConfigGen</code>. Select <code class="language-plaintext highlighter-rouge">Vivado HL WebPACK</code>.</p>
  </li>
  <li>Edit the install config:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nvim ~/.Xilinx/install_config.txt
</code></pre></div>    </div>
    <p>It seems advisable to change <code class="language-plaintext highlighter-rouge">Destination</code> to a path that we have read/write permissions for. <br />
I used <code class="language-plaintext highlighter-rouge">&lt;home directory&gt;/opt/Xilinx</code>.</p>
  </li>
  <li>Install Vivado with
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./xsetup <span class="se">\</span>
<span class="nt">-a</span> XilinxEULA,3rdPartyEULA,WebTalkTerms <span class="se">\</span>
<span class="nt">-b</span> Install <span class="se">\</span>
<span class="nt">-c</span> <span class="nv">$HOME</span>/.Xilinx/install_config.txt
</code></pre></div>    </div>
  </li>
  <li>See <a href="/blog/2025/05/02/installing-vivado-on-nixos.html#notes-on-libtinfoso5">Notes on <tt>libtinfo.so.5</tt></a>.
Run
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /usr/lib/libtinfo.so.5 ~/opt/Xilinx/Vivado/2019.2/lib/lnx64.o/libtinfo.so.5
</code></pre></div>    </div>
  </li>
  <li>You can now launch Vivado with
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/opt/Xilinx/Vivado/2019.2/bin/vivado
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="desktop-entry">Desktop Entry</h2>

<ol>
  <li>Create a <code class="language-plaintext highlighter-rouge">shell.nix</code> in <code class="language-plaintext highlighter-rouge">~/opt/Xilinx/Vivado/2019.2/bin/</code> with the following content
    <div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># shell.nix</span>
<span class="p">{</span> <span class="nv">pkgs</span> <span class="o">?</span> <span class="kr">import</span> <span class="o">&lt;</span><span class="nv">nixpkgs</span><span class="o">&gt;</span> <span class="p">{</span> <span class="p">}</span> <span class="p">}:</span>
<span class="p">(</span><span class="nv">pkgs</span><span class="o">.</span><span class="nv">buildFHSEnv</span> <span class="p">{</span>
  <span class="nv">name</span> <span class="o">=</span> <span class="s2">"vivado-env"</span><span class="p">;</span>
  <span class="nv">targetPkgs</span> <span class="o">=</span> <span class="nv">pkgs</span><span class="p">:</span> <span class="p">(</span>
 <span class="kn">with</span> <span class="nv">pkgs</span><span class="p">;</span> <span class="p">[</span>
   <span class="nv">ncurses5</span>
   <span class="nv">zlib</span> <span class="nv">libuuid</span>
   <span class="nv">bash</span> <span class="nv">coreutils</span> <span class="nv">zlib</span> <span class="nv">stdenv</span><span class="o">.</span><span class="nv">cc</span><span class="o">.</span><span class="nv">cc</span>
   <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXext</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libX11</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXrender</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXtst</span>
   <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXi</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXft</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libxcb</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libxcb</span>
   <span class="nv">freetype</span> <span class="nv">fontconfig</span> <span class="nv">glib</span> <span class="nv">gtk2</span> <span class="nv">gtk3</span>
   <span class="nv">graphviz</span> <span class="nv">gcc</span> <span class="nv">unzip</span> <span class="nv">nettools</span>
 <span class="p">]</span>
  <span class="p">);</span>
  <span class="nv">runScript</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2"> env LIBRARY_PATH=/usr/lib \</span><span class="err">
</span><span class="s2">   C_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">   CPLUS_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">   CMAKE_LIBRARY_PATH=/usr/lib \</span><span class="err">
</span><span class="s2">   CMAKE_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">   $HOME/opt/Xilinx/Vivado/2019.2/bin/vivado</span><span class="err">
</span><span class="s2">  ''</span><span class="p">;</span>
<span class="p">})</span><span class="o">.</span><span class="nv">env</span>
</code></pre></div>    </div>
  </li>
  <li>Open the desktop entry for Vivado:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nvim .local/share/applications/Vivado<span class="se">\ </span>2019.2_<span class="k">*</span>.desktop
</code></pre></div>    </div>
    <p>Change the line starting with <code class="language-plaintext highlighter-rouge">Exec</code> to</p>
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">Exec</span><span class="o">=</span>nix-shell &lt;home directory&gt;/opt/Xilinx/Vivado/2019.2/bin/shell.nix
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="notes-on-libtinfoso5">Notes on <tt>libtinfo.so.5</tt></h2>

<p>If step 8. is omitted then running Vivado throws the following error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>application-specific initialization failed: couldn't load file "librdi_commontasks.so":
libtinfo.so.5: cannot open shared object file: No such file or directory
</code></pre></div></div>
<p>This seems to be a common issue and is usually solved by installing <code class="language-plaintext highlighter-rouge">libtinfo-dev</code>
or symlinking <code class="language-plaintext highlighter-rouge">/usr/lib/libtinfo.so.6</code> to <code class="language-plaintext highlighter-rouge">/usr/lib/libtinfo.so.5</code>.
However this is not the solution in this case because <code class="language-plaintext highlighter-rouge">libtinfo.so.5</code> is actually
present at the reasonable locations (<code class="language-plaintext highlighter-rouge">/usr/lib</code>, <code class="language-plaintext highlighter-rouge">/lib</code>, …) but Vivado
refuses to find it for some unknown reason.
The only workaround I found is symlinking/copying <code class="language-plaintext highlighter-rouge">libtinfo.so.5</code>
to <code class="language-plaintext highlighter-rouge">&lt;install dir&gt;/Xilinx/Vivado/2019.2/lib/lnx64.o</code></p>

<h3 id="solution">Solution</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /usr/lib/libtinfo.so.5 ~/opt/Xilinx/Vivado/2019.2/lib/lnx64.o/libtinfo.so.5
</code></pre></div></div>

<h3 id="non-solution-1">Non-solution 1</h3>

<p>I cannot even install <code class="language-plaintext highlighter-rouge">libtinfo</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nix-shell <span class="nt">-p</span> libtinfo
<span class="c"># ...</span>
ERROR: noBrokenSymlinks: the symlink /nix/store/l3sa8c1f03l84zkz6afbzgya3ad4jcmi-ncurses-6.5-dev/lib/pkgconfig/tic.pc points to a missing target: /nix/store/l3sa8c1f03l84zkz6afbzgya3ad4jcmi-ncurses-6.5-dev/lib/pkgconfig/ncurses.pc
ERROR: noBrokenSymlinks: the symlink /nix/store/l3sa8c1f03l84zkz6afbzgya3ad4jcmi-ncurses-6.5-dev/lib/pkgconfig/tinfo.pc points to a missing target: /nix/store/l3sa8c1f03l84zkz6afbzgya3ad4jcmi-ncurses-6.5-dev/lib/pkgconfig/ncurses.pc
ERROR: noBrokenSymlinks: found 2 dangling symlinks, 0 reflexive symlinks and 0 unreadable symlinks
</code></pre></div></div>

<h3 id="non-solution-2">Non-solution 2</h3>

<p>Creating a symlink from <code class="language-plaintext highlighter-rouge">/usr/lib/libtinfo.so.6</code> to <code class="language-plaintext highlighter-rouge">/usr/lib/libtinfo.so.5</code>
in an <code class="language-plaintext highlighter-rouge">FHSEnv</code> is not trivial at all because <code class="language-plaintext highlighter-rouge">/usr</code> is read-only.
Therefore we have to use a package override so that the symlink is already created in the package.</p>
<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># shell.nix</span>
<span class="p">{</span> <span class="nv">pkgs</span> <span class="o">?</span> <span class="kr">import</span> <span class="o">&lt;</span><span class="nv">nixpkgs</span><span class="o">&gt;</span> <span class="p">{</span> <span class="p">}</span> <span class="p">}:</span>
<span class="p">(</span>
<span class="kd">let</span>
  <span class="nv">custom-ncurses</span> <span class="o">=</span> <span class="nv">pkgs</span><span class="o">.</span><span class="nv">ncurses</span><span class="o">.</span><span class="nv">overrideAttrs</span> <span class="p">(</span><span class="nv">finalAttrs</span><span class="p">:</span> <span class="nv">previousAttrs</span><span class="p">:</span>  <span class="p">{</span>
    <span class="nv">postFixup</span> <span class="o">=</span> <span class="nv">previousAttrs</span><span class="o">.</span><span class="nv">postFixup</span> <span class="o">+</span> <span class="s2">''</span><span class="err">
</span><span class="s2">        ln -svf $out/lib/libtinfo.so.6 $out/lib/libtinfo.so.5</span><span class="err">
</span><span class="s2">    ''</span><span class="p">;</span>
  <span class="p">});</span>
<span class="kn">in</span>
  <span class="nv">pkgs</span><span class="o">.</span><span class="nv">buildFHSEnv</span> <span class="p">{</span>
    <span class="nv">name</span> <span class="o">=</span> <span class="s2">"vivado-env"</span><span class="p">;</span>
    <span class="nv">targetPkgs</span> <span class="o">=</span> <span class="nv">pkgs</span><span class="p">:</span> <span class="p">(</span>
      <span class="kn">with</span> <span class="nv">pkgs</span><span class="p">;</span> <span class="p">[</span>
        <span class="nv">custom-ncurses</span>
        <span class="nv">zlib</span> <span class="nv">libuuid</span>
        <span class="nv">bash</span> <span class="nv">coreutils</span> <span class="nv">zlib</span> <span class="nv">stdenv</span><span class="o">.</span><span class="nv">cc</span><span class="o">.</span><span class="nv">cc</span>
        <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXext</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libX11</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXrender</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXtst</span>
        <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXi</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libXft</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libxcb</span> <span class="nv">xorg</span><span class="o">.</span><span class="nv">libxcb</span>
        <span class="nv">freetype</span> <span class="nv">fontconfig</span> <span class="nv">glib</span> <span class="nv">gtk2</span> <span class="nv">gtk3</span>
        <span class="nv">graphviz</span> <span class="nv">gcc</span> <span class="nv">unzip</span> <span class="nv">nettools</span>
      <span class="p">]</span>
    <span class="p">);</span>
    <span class="nv">runScript</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2">      env LIBRARY_PATH=/usr/lib \</span><span class="err">
</span><span class="s2">        C_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">        CPLUS_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">        CMAKE_LIBRARY_PATH=/usr/lib \</span><span class="err">
</span><span class="s2">        CMAKE_INCLUDE_PATH=/usr/include \</span><span class="err">
</span><span class="s2">        $HOME/opt/Xilinx/Vivado/2019.2/bin/vivado</span><span class="err">
</span><span class="s2">    ''</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="nv">env</span>
</code></pre></div></div>
<p>However as mentioned this still does not solve the problem.</p>

<h2 id="uninstalling">Uninstalling</h2>

<blockquote>
  <p>WARNING: This might be overkill for you. Read it carefully and use common sense!</p>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm -rf \
~/opt/Xilinx \
~/.Xilinx \
~/.config/menus/applications-merged/Xilinx\ Design\ Tools.menu \
~/.local/share/applications/*Vivado* \
~/.local/share/applications/*Xilinx* \
~/.local/share/applications/Uninstall\ 2019.2* \
~/.local/share/applications/Add\ Design\ Tools\ or\ Devices\ 2019.2* \
~/.local/share/applications/Documentation\ Navigator* \
~/.local/share/applications/Uninstall\ DocNav*
</code></pre></div></div>

<h2 id="resources">Resources</h2>

<p>This post is largely based on <a href="https://blog.kotatsu.dev/posts/2021-09-14-vivado-on-nixos/">kotatsuyaki’s excellent article</a>
Xilinx Vivado on NixOS.</p>

<p>Also check out <a href="https://bruceroettgers.eu/install-vivado/">Bruce Röttgers’ post</a>
on installing Vivado on Ubuntu.</p>]]></content><author><name>Oliver Kovacs</name></author><category term="blog" /><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">Clandestine VPN split tunneling</title><link href="https://oliverkovacs.dev/blog/2024/07/05/clandestine-vpn-split-tunneling.html" rel="alternate" type="text/html" title="Clandestine VPN split tunneling" /><published>2024-07-05T00:00:00+02:00</published><updated>2024-07-05T00:00:00+02:00</updated><id>https://oliverkovacs.dev/blog/2024/07/05/clandestine-vpn-split-tunneling</id><content type="html" xml:base="https://oliverkovacs.dev/blog/2024/07/05/clandestine-vpn-split-tunneling.html"><![CDATA[<h2 id="overview">Overview</h2>

<p>This post details how to use a virtual private network (VPN) running on a separate (virtual) machine.
This allows us to “pre-filter” the network traffic, effectively split tunneling using a full-tunnel VPN connection.</p>

<p>Some possible use cases include:</p>
<ul>
  <li>You are required to use a full tunnel VPN connection but you don’t want to send all of your traffic through the VPN for privacy or performance reasons.</li>
  <li>You want to connect a machine to multiple VPNs simultaneously.</li>
  <li>You want to connect multiple machines to a VPN simultaneously.</li>
</ul>

<h2 id="setup">Setup</h2>

<p>The simplest setup is to use a virtual machine (VM) to connect to the VPN.
However two different physical computers could also be used.</p>

<p>This post will assume you are running a KVM VM on a Linux host but it should be trivial to adapt it to other situations.</p>

<h3 id="create-the-vm">Create the VM</h3>

<ol>
  <li>Choose a Linux distribution. You can use a distro optimized for networking like <a href="https://openwrt.org/">OpenWRT</a> or a general purpose one like <a href="https://www.debian.org/">Debian</a> or <a href="https://archlinux.org/">Arch</a>.</li>
  <li>Create a VM with for example <code class="language-plaintext highlighter-rouge">virt-manager</code>. If you are paranoid you can enable full disk encryption.</li>
  <li>Install the VPN client you want to use inside the VM.</li>
</ol>

<h3 id="network-interfaces">Network interfaces</h3>

<p>Inspect the network interfaces of the machines using <code class="language-plaintext highlighter-rouge">ip addr</code> or <code class="language-plaintext highlighter-rouge">ifconfig</code>.
There are 3 interfaces of interest:</p>
<ul>
  <li>On the host:
    <ul>
      <li>interface to the LAN:
        <ul>
          <li><code class="language-plaintext highlighter-rouge">wlp1s0</code> or similar if connected to wifi</li>
          <li><code class="language-plaintext highlighter-rouge">enp1s0</code>, <code class="language-plaintext highlighter-rouge">eth0</code> or similar if connected to ethernet</li>
        </ul>
      </li>
      <li>interface like <code class="language-plaintext highlighter-rouge">virbr0</code> to the VM</li>
    </ul>
  </li>
  <li>On the VM:
    <ul>
      <li>interface like <code class="language-plaintext highlighter-rouge">enp1s0</code> to the host</li>
    </ul>
  </li>
</ul>

<p>Furthermore if you start the VPN in the VM a new interface like <code class="language-plaintext highlighter-rouge">tun0</code> should be created.</p>

<p>This is a diagramm of the setup:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>       +------------------------------------------------------+
       |                                                      |
       |    Host                                              |
       |                                                      |
       |    +--------+    +------------------------------+    |
LAN &lt;-----&gt; | wlp1s0 |    |                              |    |
       |    +--------+    |    VM                        |    |
       |                  |                              |    |
       |    +--------+    |    +--------+  +--------+    |    |
       |    | virbr0 | &lt;-----&gt; | enp1s0 |  |  tun0  |    |    |
       |    +--------+    |    +--------+  +--------+    |    |
       |       ...        +------------------------------+    |
       +------------------------------------------------------+
</code></pre></div></div>

<p>The interfaces might be named a bit differently on your machines, you will have to adapt the following commands accordingly.</p>

<h3 id="routing">Routing</h3>

<p>Linux uses a routing table to determine where to send packets.
The routing table can be consulted using the <code class="language-plaintext highlighter-rouge">route</code> command.</p>

<p>Therefore:</p>
<ol>
  <li>The routing table of the host has to be modified so that it sends packets meant for the VPN to the VM.</li>
  <li>The VM has to be adjusted so that it forwards these packets received from the host to the VPN.</li>
</ol>

<h2 id="vm">VM</h2>

<p>Enable IP forwarding:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'1'</span> <span class="o">&gt;&gt;</span> /proc/sys/net/ipv4/ip_forward
</code></pre></div></div>

<p>Adjust the firewall to forward <code class="language-plaintext highlighter-rouge">enp1s0</code> to <code class="language-plaintext highlighter-rouge">tun0</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables <span class="nt">-t</span> nat <span class="nt">-A</span> POSTROUTING <span class="nt">-o</span> tun0 <span class="nt">-j</span> MASQUERADE

iptables <span class="nt">-A</span> FORWARD <span class="nt">-i</span> enp1s0 <span class="nt">-o</span> tun0 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> FORWARD <span class="nt">-o</span> tun0 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> FORWARD <span class="nt">-i</span> tun0 <span class="nt">-m</span> conntrack <span class="nt">--ctstate</span> ESTABLISHED,RELATED <span class="nt">-j</span> ACCEPT

iptables <span class="nt">-A</span> INPUT <span class="nt">-i</span> tun0 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>

<h2 id="host">Host</h2>

<p>There are two ways to set up the host:</p>

<h3 id="static">Static</h3>

<p>This is simpler if you only need to access a few resources.
If there is a website called <code class="language-plaintext highlighter-rouge">site.example</code> that you need to access:</p>
<ol>
  <li>Look up the IP address of <code class="language-plaintext highlighter-rouge">site.example</code> using <code class="language-plaintext highlighter-rouge">dig</code> or <code class="language-plaintext highlighter-rouge">nslookup</code>. Let’s assume it is <code class="language-plaintext highlighter-rouge">10.10.10.10</code>.</li>
  <li>Add an entry to your <code class="language-plaintext highlighter-rouge">/etc/hosts</code> file:
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/hosts</span>
10.10.10.10     site.example
</code></pre></div>    </div>
  </li>
  <li>Find the IP address of the <code class="language-plaintext highlighter-rouge">enp1s0</code> network interface of the VM.
It must be on the same subnet as the <code class="language-plaintext highlighter-rouge">virbr0</code> interface of the host.
Let’s assume it is <code class="language-plaintext highlighter-rouge">192.168.100.100</code>.</li>
  <li>Add an entry to the routing table of the host specifying that packets bound for the IP of the website should use the VM as the gateway.
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>route add 10.10.10.10/32 gw 192.168.100.100 metric 200 dev virbr0
</code></pre></div>    </div>
  </li>
  <li>You should be able to access the website.
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl site.example
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="dns">DNS</h3>

<p>This is more complicated but might be necessary if a static setup would be too tedious.</p>

<ol>
  <li>Find the VPN name server using <code class="language-plaintext highlighter-rouge">dig</code> or <code class="language-plaintext highlighter-rouge">nslookup</code>.</li>
  <li>Configure the host to use it for DNS resolution. The concrete steps to do this depend on your setup, but this is tricky:
    <ul>
      <li>You should restrict usage of the VPN name server to domains that it is actually needed for.</li>
      <li>You might not know all of the domains this applies to.</li>
      <li>You cannot use the name server on your router because it doesn’t have access to the VPN.</li>
      <li>Therefore you might have to run a seperate name server on the host and configure the fallback logic between router and VPN name server there.</li>
      <li>Failing to set this up correctly could leak your DNS queries to the VPN name server and break a DNS sinkholing setup.</li>
    </ul>
  </li>
  <li>Expose the VPN name server as well as the VPN subnets using the host routing table as explained in the <a href="./clandestine-vpn-split-tunneling.html#static">static</a> section.</li>
</ol>

<h4 id="example">Example</h4>

<p>DNS using <code class="language-plaintext highlighter-rouge">systemd-resolved</code> with <code class="language-plaintext highlighter-rouge">systemd-networkd</code></p>

<p>Run on the VM:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig site1.example
<span class="c"># ...</span>
<span class="c"># site1.example.	300	IN	A	10.10.10.10</span>
<span class="c"># ...</span>
<span class="c"># ;; SERVER: 10.10.10.53#53(10.10.10.53) (UDP)</span>
<span class="c"># ...</span>
</code></pre></div></div>
<p>Thus the VPN name server is <code class="language-plaintext highlighter-rouge">10.10.10.53</code>.</p>

<p>Make sure you are actually using resolved for host resolution.
The <code class="language-plaintext highlighter-rouge">/etc/nsswitch.conf</code> file should contain the following line:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hosts:  files resolve dns
</code></pre></div></div>
<p>See also <code class="language-plaintext highlighter-rouge">man nss-resolve</code> and <code class="language-plaintext highlighter-rouge">man nsswitch.conf</code>.</p>

<p>Set the VPN name server as the network DNS server in <code class="language-plaintext highlighter-rouge">/etc/systemd/network/wlp1s0.network</code>.</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Match]</span><span class="w">
</span><span class="py">Name</span><span class="p">=</span><span class="s">wlp1s0</span>
<span class="w">
</span><span class="nn">[Network]</span><span class="w">
</span><span class="py">DNS</span><span class="p">=</span><span class="s">10.10.10.53</span>
<span class="py">Domains</span><span class="p">=</span><span class="s">site1.example site2.example ~example</span>
</code></pre></div></div>
<p>See also <code class="language-plaintext highlighter-rouge">man systemd.network</code>.</p>

<p>Set your prefered non-VPN name server as your global DNS server in <code class="language-plaintext highlighter-rouge">/etc/systemd/resolved.conf</code>:</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Resolve]</span><span class="w">
</span><span class="py">DNS</span><span class="p">=</span><span class="s">8.8.8.8</span>
</code></pre></div></div>
<p>See also <code class="language-plaintext highlighter-rouge">man systemd-resolved.service</code>.</p>

<p>Reload:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl daemon-reload
systemctl restart systemd-networkd
systemctl restart systemd-resolved
</code></pre></div></div>

<p>This has the effect that <code class="language-plaintext highlighter-rouge">host1.site1.example</code> will be resolved using <code class="language-plaintext highlighter-rouge">10.10.10.53</code> but <code class="language-plaintext highlighter-rouge">on.the.internet</code> using <code class="language-plaintext highlighter-rouge">8.8.8.8</code>.</p>

<p>Add routing information for the VPN name server and other resources you need to access:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>route add 10.10.10.53/32 gw 192.168.100.100 metric 200 dev virbr0
route add 10.10.10.10/32 gw 192.168.100.100 metric 200 dev virbr0
</code></pre></div></div>

<p>You can troubleshoot using:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>resolvectl status
</code></pre></div></div>

<p>The output should look something like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Global
         Protocols: <span class="nt">-LLMNR</span> <span class="nt">-mDNS</span> <span class="nt">-DNSOverTLS</span> <span class="nv">DNSSEC</span><span class="o">=</span>no/unsupported
  resolv.conf mode: foreign
Current DNS Server: 8.8.8.8
       DNS Servers: 8.8.8.8

Link 2 <span class="o">(</span>wlp1s0<span class="o">)</span>
    Current Scopes: DNS
         Protocols: <span class="nt">-DefaultRoute</span> +LLMNR <span class="nt">-mDNS</span> <span class="nt">-DNSOverTLS</span> <span class="nv">DNSSEC</span><span class="o">=</span>no/unsupported
Current DNS Server: 10.10.10.53
       DNS Servers: 10.10.10.53
        DNS Domain: site1.example site2.example ~example

<span class="c"># ...</span>
</code></pre></div></div>

<h2 id="persistence">Persistence</h2>

<p>All of the commands are non-persistent.
If you want them to survive a reboot you have to create a startup script running them on boot.</p>

<p>Ideally you want</p>
<ul>
  <li>a startup script on the host setting up the routing table and starting the VM, and</li>
  <li>a startup script on the VM starting the VPN and adjusting the firewall.</li>
</ul>

<p>The specifics will highly depend on your setup and use case.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Notice how you can use these techniques to</p>
<ul>
  <li>split tunnel before a full tunnel VPN,</li>
  <li>share a VPN connection with multiple computers or</li>
  <li>use multiple VPNs simultaneously</li>
</ul>

<p>without the arbiters of the VPN being able to do much about it.</p>]]></content><author><name>Oliver Kovacs</name></author><category term="blog" /><summary type="html"><![CDATA[Overview]]></summary></entry><entry><title type="html">GPU-accelerated real-time rendering of n-dimensional objects</title><link href="https://oliverkovacs.dev/publication/2024/06/25/vwa.html" rel="alternate" type="text/html" title="GPU-accelerated real-time rendering of n-dimensional objects" /><published>2024-06-25T00:00:00+02:00</published><updated>2024-06-25T00:00:00+02:00</updated><id>https://oliverkovacs.dev/publication/2024/06/25/vwa</id><content type="html" xml:base="https://oliverkovacs.dev/publication/2024/06/25/vwa.html"><![CDATA[<p>[
<a href="/assets/pdf/Oliver_Kovacs-VWA.pdf" target="_blank">pdf</a>,
<a href="/assets/pdf/Oliver_Kovacs-VWA-Errata.pdf" target="_blank">errata</a>
]</p>

<p>My pre-scientific thesis (VWA), submitted in 2023.</p>

<h2 id="abstract">Abstract</h2>

<p>N-dimensional rendering is a fascinating but computationally expensive process. This makes it ill-suited for real-time applications. GPUs have been conventionally used to accelerate rendering workloads, however they are heavily optimized for 3D rendering. This thesis explains the mathematics underpinning n-dimensional rendering and takes a look at how it can be optimally realized on modern graphics hardware. It will give some workarounds to overcome the inherent limitations of components designed not with this use case in mind.</p>

<p>A reference implementation written in C++ and utilizing Vulkan is provided in the form of vulkan-xd, exemplifying some of the techniques discussed. Some basic performance analysis was conducted on the project giving a benchmark for the achievable efficiency.</p>

<p>Further research is required to come up with additional optimizations and to
accurately assess the exact performance to be expected.</p>]]></content><author><name>Oliver Kovacs</name></author><category term="publication" /><summary type="html"><![CDATA[[ pdf, errata ]]]></summary></entry><entry><title type="html">Function connecting points with straight lines</title><link href="https://oliverkovacs.dev/blog/2024/06/01/function.html" rel="alternate" type="text/html" title="Function connecting points with straight lines" /><published>2024-06-01T00:00:00+02:00</published><updated>2024-06-01T00:00:00+02:00</updated><id>https://oliverkovacs.dev/blog/2024/06/01/function</id><content type="html" xml:base="https://oliverkovacs.dev/blog/2024/06/01/function.html"><![CDATA[<!--How to find a function that connects a list of points with straight line segments.-->

<blockquote>
  <p>Note: This was originally published on Medium on Mar 31, 2021.
I have since taken a numerics lecture and come to know that this is called
“piecewise linear interpolation”.
I have also learned that solving such a linear system of equations might give awful
precision unless you represent your numbers as rationals.</p>
</blockquote>

<h2 id="problem">Problem</h2>

<p>Given a list of \(n\) Points \(\bold P = (P_1, P_2, …, P_n)\) where \(P_i = (P_{i,x}, P_{i,y})\) ordered along the \(x\)-axis, what function \(f(x)\), when graphed, connects the points in the domain \([P_{1,x}; P_{n,x}]\) with straight lines?</p>

<figure>
    <img src="/assets/img/posts/graph.svg" alt="Graph" />
    <figcaption>
    Example: \(f(x)\) connects the points \((1, 1)\), \((2, 3)\) and \((4, 2)\) in \([1; 4]\).
    </figcaption>
</figure>

<h2 id="solution">Solution</h2>

\[f(x) = \sum_{i = 0}^n a_i \lvert x - P_{i,x} \rvert\]

<p>where</p>

\[\begin{bmatrix}
    a_1    \\
    \vdots \\
    a_n    \\
\end{bmatrix}
=
\begin{bmatrix}
    P_{1,y} \\
    \vdots  \\
    P_{n,y} \\
\end{bmatrix}
\times
\begin{bmatrix}
    \lvert P_{1,x} - P_{1,x} \rvert &amp; \cdots &amp; \lvert P_{1,x} - P_{n,x} \rvert \\
    \vdots                          &amp; \ddots &amp; \vdots                          \\
    \lvert P_{n,x} - P_{1,x} \rvert &amp; \cdots &amp; \lvert P_{n,x} - P_{n,x} \rvert \\
\end{bmatrix}^{-1} \ .\]

<blockquote>
  <p>Note: I came up with this on my own so there are probably better ways to do this.</p>
</blockquote>

<h2 id="explanation">Explanation</h2>

<p>Consider the function \(g(x) = a \lvert x - b \rvert\): it is like a linear function, \(a\) determines the steepness, but it’s mirrored at \(b\) along the \(y\) axis.</p>

<p>If you sum multiple of these functions with different \(a\) and \(b\) values together, you get a zigzagged line, something that could work as the function we are searching for.</p>

<p>Let’s assume we can use the \(x\)-values of the given points as values for \(b\). Then we get:</p>

\[f(x) = \sum_{i = 0}^n a_i \lvert x - P_{i,x} \rvert\]

<p>which is the same as</p>

\[f(x) = a_1 \lvert x - P_{1,x} \rvert + \cdots + a_n \lvert x - P_{n,x} \rvert \ .\]

<p>Now we need to find the values for \(a = (a_1, a_2, \ldots, a_n)\).</p>

<p>We know the values of \(f(x)\) at the given points:</p>

\[\forall p \in P \colon f(p_x) = p_y\]

<p>which in simpler terms just means</p>

\[\begin{cases}
    f(P_{1,x}) = P_{1,y}     \\
    \quad \quad \quad \vdots \\
    f(P_{n,x}) = P_{n,y}     \\
\end{cases} \ .\]

<p>From this we can construct a linear system of equations:</p>

\[\begin{cases}
    a_1 \lvert P_{1,x} - P_{1,x} \rvert + \cdots + a_n \lvert P_{1,x} - P_{n,x} \rvert = P_{1,y}                              \\
    \quad \quad \quad \vdots \quad \quad \quad \ \ \ \ddots \quad \quad \quad \quad \ \vdots \quad \quad \quad \quad \ \vdots \\
    a_1 \lvert P_{n,x} - P_{1,x} \rvert + \cdots + a_n \lvert P_{n,x} - P_{n,x} \rvert = P_{n,y}                              \\
\end{cases} \ .\]

<p>All values for \(P\) are known, so at this point, we could simply use an equation solver to get \(a\).
However, it can also be rewritten as a matrix multiplication:</p>

\[\begin{bmatrix}
    \lvert P_{1,x} - P_{1,x} \rvert &amp; \cdots &amp; \lvert P_{1,x} - P_{n,x} \rvert \\
    \vdots                          &amp; \ddots &amp; \vdots                          \\
    \lvert P_{n,x} - P_{1,x} \rvert &amp; \cdots &amp; \lvert P_{n,x} - P_{n,x} \rvert \\
\end{bmatrix}
\times
\begin{bmatrix}
    a_1    \\
    \vdots \\
    a_n    \\
\end{bmatrix}
=
\begin{bmatrix}
    P_{1,y} \\
    \vdots  \\
    P_{n,y} \\
\end{bmatrix} \ .\]

<p>Solve for \(a\):</p>

\[\begin{bmatrix}
    a_1    \\
    \vdots \\
    a_n    \\
\end{bmatrix}
=
\begin{bmatrix}
    P_{1,y} \\
    \vdots  \\
    P_{n,y} \\
\end{bmatrix}
\times
\begin{bmatrix}
    \lvert P_{1,x} - P_{1,x} \rvert &amp; \cdots &amp; \lvert P_{1,x} - P_{n,x} \rvert \\
    \vdots                          &amp; \ddots &amp; \vdots                          \\
    \lvert P_{n,x} - P_{1,x} \rvert &amp; \cdots &amp; \lvert P_{n,x} - P_{n,x} \rvert \\
\end{bmatrix}^{-1} \ .\]

<p>And that’s it.</p>

<h2 id="example">Example</h2>

<p>Let’s find \(f(x)\) for the points \((1, 1)\), \((2, 3)\) and \((4, 2)\).
First, we need to find the values for \(a\).</p>

<p>Using the above formula, we get:</p>

\[\begin{bmatrix}
    a_1 \\
    a_2 \\
    a_3 \\
\end{bmatrix}
=
\begin{bmatrix}
    1 \\
    3 \\
    2 \\
\end{bmatrix}
\times
\begin{bmatrix}
    \lvert 1 - 1 \rvert &amp; \lvert 1 - 2 \rvert &amp; \lvert 1 - 4 \rvert \\
    \lvert 2 - 1 \rvert &amp; \lvert 2 - 2 \rvert &amp; \lvert 2 - 4 \rvert \\
    \lvert 4 - 1 \rvert &amp; \lvert 4 - 2 \rvert &amp; \lvert 4 - 4 \rvert \\
\end{bmatrix}^{-1} \ .\]

<p>Simplify:</p>

\[\begin{bmatrix}
    a_1 \\
    a_2 \\
    a_3 \\
\end{bmatrix}
=
\begin{bmatrix}
    1 \\
    3 \\
    2 \\
\end{bmatrix}
\times
\begin{bmatrix}
    0 &amp; 1 &amp; 3 \\
    1 &amp; 0 &amp; 2 \\
    3 &amp; 2 &amp; 0 \\
\end{bmatrix}^{-1} \ .\]

<p>Solve using SageMath:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">V</span> <span class="o">=</span> <span class="nf">matrix</span><span class="p">(</span><span class="n">QQ</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span>
<span class="n">M</span> <span class="o">=</span> <span class="nf">matrix</span><span class="p">(</span><span class="n">QQ</span><span class="p">,</span> <span class="p">[[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]])</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">V</span> <span class="o">*</span> <span class="nf">pow</span><span class="p">(</span><span class="n">M</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>

<span class="n">a</span> <span class="c1"># [ 3/2 -5/4  3/4]
</span></code></pre></div></div>

\[a = \left(\frac 3 2, - \frac 5 4, \frac 3 4\right)\]

<p>Now we can use the very first formula to get \(f(x)\):</p>

\[f(x) = \frac 3 2 \lvert x - 1 \rvert - \frac 5 4 \lvert x - 2 \rvert + \frac 3 4 \lvert x - 4 \rvert \ .\]

<figure>
    <img src="/assets/img/posts/graph.svg" alt="Graph" height="450" />
    <figcaption>
    This is the graph of \(f(x)\).
    </figcaption>
</figure>]]></content><author><name>Oliver Kovacs</name></author><category term="blog" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Anti-rev</title><link href="https://oliverkovacs.dev/writeup/2024/05/02/anti-rev.html" rel="alternate" type="text/html" title="Anti-rev" /><published>2024-05-02T00:00:00+02:00</published><updated>2024-05-02T00:00:00+02:00</updated><id>https://oliverkovacs.dev/writeup/2024/05/02/anti-rev</id><content type="html" xml:base="https://oliverkovacs.dev/writeup/2024/05/02/anti-rev.html"><![CDATA[<p><strong>openECSC 2024 - Round 2</strong></p>

<p>Category: <code class="language-plaintext highlighter-rouge">rev</code></p>

<h2 id="description">Description</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Good luck finding the secret word for my super secure program!
</code></pre></div></div>

<p>Attachments: <code class="language-plaintext highlighter-rouge">anti-rev</code></p>

<h2 id="solution">Solution</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">angr</span>

<span class="n">project</span> <span class="o">=</span> <span class="n">angr</span><span class="p">.</span><span class="nc">Project</span><span class="p">(</span><span class="sh">"</span><span class="s">anti-rev</span><span class="sh">"</span><span class="p">,</span> <span class="n">auto_load_libs</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">simgr</span> <span class="o">=</span> <span class="n">project</span><span class="p">.</span><span class="n">factory</span><span class="p">.</span><span class="nf">simulation_manager</span><span class="p">(</span><span class="n">project</span><span class="p">.</span><span class="n">factory</span><span class="p">.</span><span class="nf">full_init_state</span><span class="p">())</span>
<span class="n">simgr</span><span class="p">.</span><span class="nf">explore</span><span class="p">(</span><span class="n">find</span><span class="o">=</span><span class="mh">0x401def</span><span class="p">,</span> <span class="n">avoid</span><span class="o">=</span><span class="mh">0x401df8</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">simgr</span><span class="p">.</span><span class="n">found</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">posix</span><span class="p">.</span><span class="nf">dumps</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
</code></pre></div></div>

<h2 id="bonus">Bonus</h2>

<p>Use <code class="language-plaintext highlighter-rouge">angr</code> to disassemble and find address to search for.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">angr</span>

<span class="n">project</span> <span class="o">=</span> <span class="n">angr</span><span class="p">.</span><span class="nc">Project</span><span class="p">(</span><span class="sh">"</span><span class="s">anti-rev</span><span class="sh">"</span><span class="p">,</span> <span class="n">auto_load_libs</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">cfg</span> <span class="o">=</span> <span class="n">project</span><span class="p">.</span><span class="n">analyses</span><span class="p">.</span><span class="nc">CFG</span><span class="p">(</span><span class="n">normalize</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="nf">sorted</span><span class="p">(</span><span class="n">cfg</span><span class="p">.</span><span class="n">model</span><span class="p">.</span><span class="nf">nodes</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="p">.</span><span class="n">addr</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="p">.</span><span class="n">is_simprocedure</span><span class="p">:</span>
        <span class="n">node</span><span class="p">.</span><span class="n">block</span><span class="p">.</span><span class="nf">pp</span><span class="p">()</span>
</code></pre></div></div>]]></content><author><name>Oliver Kovacs</name></author><category term="writeup" /><summary type="html"><![CDATA[openECSC 2024 - Round 2]]></summary></entry><entry><title type="html">MathMAC</title><link href="https://oliverkovacs.dev/writeup/2024/05/02/mathmac.html" rel="alternate" type="text/html" title="MathMAC" /><published>2024-05-02T00:00:00+02:00</published><updated>2024-05-02T00:00:00+02:00</updated><id>https://oliverkovacs.dev/writeup/2024/05/02/mathmac</id><content type="html" xml:base="https://oliverkovacs.dev/writeup/2024/05/02/mathmac.html"><![CDATA[<p><strong>openECSC 2024 - Round 2</strong></p>

<p>Category: <code class="language-plaintext highlighter-rouge">crypto</code></p>

<h2 id="description">Description</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Why using boring symmetric crypto for MACs when we can use fancy math?
</code></pre></div></div>

<p>Attachments: <code class="language-plaintext highlighter-rouge">mathmac.py</code> (see <a href="#appendix">Appendix</a>)</p>

<h2 id="probem">Probem</h2>

<p>Let \(p = 8636821143825786083\) and \(M = 64\).<br />
Let \(\bold k = k_0, \ldots,k_M\) where \(k_i \in \mathbb Z_{\lt p}\) be a private key chosen at random.<br />
Let \(\bold x  \in \{0, 1\}^M\) with \(\bold x = x_1, \ldots, x_M\) be an \(M\)-bit binary word.<br />
Let \(h \colon \{0, 1\}^M \to \mathbb Z_p\) be a hash function defined as</p>

\[h(\bold x) = 4^{k_0 + x_1 k_1+ \cdots x_M k_M} \mod p \ .\]

<p>The challenge is:</p>

<ul>
  <li>The attacker can request an unlimited amount of word/hash pairs \((\bold x, h(\bold x))\) chosen at random.</li>
  <li>Then the attacker has to submit a word/hash pair \((\bold x ^\prime, h(\bold x ^\prime))\) that has not yet been revealed.
    <ul>
      <li>If the submission is correct the attacker obtains the flag.</li>
      <li>Only a single submission can be made.</li>
    </ul>
  </li>
</ul>

<h2 id="solution">Solution</h2>

<p>The first step involves solving the <a href="https://en.wikipedia.org/wiki/Discrete_logarithm">discrete logarithm problem (DLP)</a>.</p>

<h3 id="dlp">DLP</h3>

<p>Let \(h(\bold x)\) be an element of the cyclic subgroup \(\langle 4 \rangle\) of \(\mathbb Z_p^*\).<br />
If \(4^n \equiv h(\bold x) \mod p\) then \(n\) is the discrete logarithm of \(h(\bold x)\) to the base \(4\) denoted as \(n = \log_4(h(\bold x))\).<br />
Solving this is useful because \(n\) is directly related to \(k_0 + x_1 k_1 + \cdots x_M k_M\).</p>

<p>Some notes:</p>
<ul>
  <li>\(\lvert \mathbb Z_p^*\rvert = p - 1\).</li>
  <li>From <a href="https://en.wikipedia.org/wiki/Lagrange%27s_theorem_(group_theory)">Lagrange’s theorem</a> it follows that \(\lvert4\rvert\) divides \(\lvert \mathbb Z_p^*\rvert\)
    <ul>
      <li>This means that  \(|4|\) is \(1\), \(2\), \(4318410571912893041\) or \(8636821143825786082\).<br />
  It’s easy to see that in practice only the last two are possible.</li>
    </ul>
  </li>
  <li>The DLP is easy to solve if the order of the group is <a href="https://en.wikipedia.org/wiki/Smooth_number">smooth</a> using the <a href="https://en.wikipedia.org/wiki/Pohlig%E2%80%93Hellman_algorithm">Pohlig-Hellman algorithm</a>.
    <ul>
      <li>This is not the case because \(p = 8636821143825786083 = 2 \cdot 4318410571912893041 + 1\) is a safe prime.</li>
    </ul>
  </li>
  <li>The base 4 doesn’t matter. Computing a logarithm to any base \(x\) is sufficient, because</li>
</ul>

\[\log_ba = \log_x a \cdot (\log_xb)^{-1} \ .\]

<p>The fastest known algorithm to compute the DLP in this case is a number field sieve.<br />
One implementation is <a href="https://cado-nfs.gitlabpages.inria.fr/">CADO-NFS</a>.</p>

<h3 id="cado-nfs">CADO-NFS</h3>
<p>Setup:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://gitlab.inria.fr/cado-nfs/cado-nfs
<span class="nb">cd </span>cado-nfs
make
<span class="c"># create paramter files for 19 bit</span>
<span class="nb">cp </span>parameters/dlp/params.p30 parameters/dlp/params.p19
<span class="nb">cp </span>parameters/dlp/p30.hint parameters/dlp/p19.hint
</code></pre></div></div>
<p>Example: Compute the DLP of <code class="language-plaintext highlighter-rouge">4802397593893189429</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ell is the order of ⟨4⟩</span>
./cado-nfs.py <span class="nt">--dlp</span> <span class="se">\</span>
    <span class="nt">--ell</span> 4318410571912893041 <span class="se">\</span>
    <span class="nv">target</span><span class="o">=</span>4802397593893189429 <span class="se">\</span>
    8636821143825786083
<span class="c"># 2192507630663880847</span>

./cado-nfs.py <span class="nt">--dlp</span> <span class="se">\</span>
    <span class="nt">--ell</span> 4318410571912893041 <span class="se">\</span>
    <span class="nv">target</span><span class="o">=</span>4 <span class="se">\</span>
    8636821143825786083
<span class="c"># 941720563644317575</span>
</code></pre></div></div>

<p>Thus \(\log_4 4802397593893189429 = 2192507630663880847 \cdot 941720563644317575^{-1}\)</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># python
</span><span class="n">p</span> <span class="o">=</span> <span class="mi">8636821143825786083</span>
<span class="n">ell</span> <span class="o">=</span> <span class="mi">4318410571912893041</span>
<span class="n">result</span> <span class="o">=</span> <span class="mi">2192507630663880847</span> <span class="o">*</span> <span class="nf">pow</span><span class="p">(</span><span class="mi">941720563644317575</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">ell</span><span class="p">)</span> <span class="c1"># 1234567890
</span>
<span class="c1"># double check the result
</span><span class="nf">pow</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>   <span class="c1"># 4802397593893189429 → correct
</span></code></pre></div></div>

<h3 id="attack">Attack</h3>

<p>Now we need the hashes of three words \(\bold a, \bold b, \bold c\) such that \(\bold a + \bold b - \bold c\) doesn’t under- or overflow any of the individual bits.<br />
Then we can compute the hash of \(\bold z = \bold a + \bold b - \bold c\) as follows:</p>

\[h(\bold z) = 4^{\log_4(h(\bold a)) + \log_4(h(\bold b)) + (\log_4(h(\bold c)))^{-1}} \mod p\]

<p>Note that we need two positive and one negative term so that the secret \(k_0\) contained in every hash occurs exactly once.</p>

<h3 id="conclusion">Conclusion</h3>

<p>A high level overview of the exploit is:</p>
<ul>
  <li>Generate around 1000 (word, hash) pairs.</li>
  <li>Do a bruteforce search to find 3 suitable words \(\bold a, \bold b, \bold c\).</li>
  <li>Compute the discrete logarithm of the hashes using CADO-NFS.</li>
  <li>Forge the hash of \(\bold z = \bold a + \bold b - \bold c\) as explained.</li>
  <li>Submit \((\bold z, h(\bold z))\).</li>
  <li>Profit.</li>
</ul>

<p>A reference implementation can be found in the <a href="#appendix">Appendix</a>.</p>

<h2 id="appendix">Appendix</h2>

<p><code class="language-plaintext highlighter-rouge">solve.py</code></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># this program expects an input file data.txt
# each line should contain a 'value,hash(value)' pair
# around 1000 pairs seem to be ideal
# this program outputs a value,hash(value) pair to submit
</span>
<span class="kn">import</span> <span class="n">subprocess</span>
<span class="kn">from</span> <span class="n">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="kn">from</span> <span class="n">random</span> <span class="kn">import</span> <span class="n">randint</span>

<span class="n">p</span> <span class="o">=</span> <span class="mi">8636821143825786083</span>
<span class="n">q</span> <span class="o">=</span> <span class="mi">4318410571912893041</span>
<span class="n">g</span> <span class="o">=</span> <span class="mi">4</span>

<span class="n">M</span> <span class="o">=</span> <span class="mi">64</span>
<span class="n">N</span> <span class="o">=</span> <span class="mi">1000</span>
<span class="n">MAX</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="n">M</span> <span class="o">-</span> <span class="mi">1</span>

<span class="c1"># change as needed
</span><span class="n">CADO_PATH</span> <span class="o">=</span> <span class="sh">"</span><span class="s">/home/user/opt/cado-nfs</span><span class="sh">"</span>
<span class="n">CADO</span> <span class="o">=</span> <span class="nf">str</span><span class="p">(</span><span class="nc">Path</span><span class="p">(</span><span class="n">CADO_PATH</span><span class="p">,</span> <span class="sh">'</span><span class="s">cado-nfs.py</span><span class="sh">'</span><span class="p">))</span>

<span class="c1"># given the multiplicative group of integers mod p (ℤ/pℤ)^*
# and the subgroup H generated by g where |g| = q and h ∈ H
# find x such that g^x ≡ h (mod p)  
</span><span class="k">def</span> <span class="nf">dlp</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>
    <span class="n">log_h</span> <span class="o">=</span> <span class="nf">cado_nfs</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
    <span class="n">log_g</span> <span class="o">=</span> <span class="nf">cado_nfs</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
    <span class="n">log_g_inv</span> <span class="o">=</span> <span class="nf">pow</span><span class="p">(</span><span class="n">log_g</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">q</span><span class="p">)</span>
    <span class="n">log</span> <span class="o">=</span> <span class="n">log_h</span> <span class="o">*</span> <span class="n">log_g_inv</span> <span class="o">%</span> <span class="n">q</span>
    <span class="k">return</span> <span class="n">log</span>

<span class="c1"># precompute log 4
</span><span class="n">cache</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">4</span><span class="p">:</span> <span class="mi">941720563644317575</span> <span class="p">}</span>

<span class="k">def</span> <span class="nf">cado_nfs</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">o</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>
    <span class="n">cached</span> <span class="o">=</span> <span class="n">cache</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
    <span class="nf">if </span><span class="p">(</span><span class="n">cached</span> <span class="o">!=</span> <span class="bp">None</span><span class="p">):</span> <span class="k">return</span> <span class="n">cached</span>

    <span class="n">cmd</span> <span class="o">=</span> <span class="p">[</span>
        <span class="n">CADO</span><span class="p">,</span>
        <span class="sh">'</span><span class="s">--dlp</span><span class="sh">'</span><span class="p">,</span>
        <span class="sh">'</span><span class="s">--ell</span><span class="sh">'</span><span class="p">,</span> <span class="nf">str</span><span class="p">(</span><span class="n">o</span><span class="p">),</span>
        <span class="sh">'</span><span class="s">target=</span><span class="sh">'</span> <span class="o">+</span> <span class="nf">str</span><span class="p">(</span><span class="n">t</span><span class="p">),</span>
        <span class="nf">str</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
    <span class="p">]</span>

    <span class="n">proc</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="nc">Popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span>
        <span class="n">stdin</span><span class="o">=</span><span class="n">subprocess</span><span class="p">.</span><span class="n">PIPE</span><span class="p">,</span>
        <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="p">.</span><span class="n">PIPE</span><span class="p">,</span>
        <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="p">.</span><span class="n">PIPE</span><span class="p">)</span>

    <span class="n">out</span> <span class="o">=</span> <span class="n">proc</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="nf">readline</span><span class="p">()</span>
    <span class="n">out</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">out</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">ascii</span><span class="sh">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
    <span class="n">cache</span><span class="p">.</span><span class="nf">update</span><span class="p">({</span> <span class="n">t</span><span class="p">:</span> <span class="n">out</span> <span class="p">})</span>
    <span class="k">return</span> <span class="nf">int</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>

<span class="c1"># brute-froce search
</span><span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">arr</span><span class="p">):</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i1</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">i2</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">i1</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
            <span class="n">e1</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i1</span><span class="p">]</span>
            <span class="n">e2</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i2</span><span class="p">]</span>
            <span class="n">AND</span> <span class="o">=</span> <span class="n">e1</span> <span class="o">&amp;</span> <span class="n">e2</span>
            <span class="n">NOR</span> <span class="o">=</span> <span class="n">MAX</span> <span class="o">^</span> <span class="p">(</span><span class="n">e1</span> <span class="o">|</span> <span class="n">e2</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">i3</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
                <span class="nf">if </span><span class="p">(</span><span class="n">i3</span> <span class="o">==</span> <span class="n">i1</span> <span class="ow">or</span> <span class="n">i3</span> <span class="o">==</span> <span class="n">i2</span><span class="p">):</span> <span class="k">continue</span>
                <span class="n">e3</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i3</span><span class="p">]</span>
                <span class="n">INV</span> <span class="o">=</span> <span class="n">MAX</span> <span class="o">^</span> <span class="n">e3</span>
                <span class="nf">if </span><span class="p">(</span><span class="n">AND</span> <span class="o">&amp;</span> <span class="n">e3</span> <span class="o">==</span> <span class="n">AND</span> <span class="ow">and</span> <span class="n">NOR</span> <span class="o">&amp;</span> <span class="n">INV</span> <span class="o">==</span> <span class="n">NOR</span><span class="p">):</span>
                    <span class="nf">return </span><span class="p">(</span><span class="n">i1</span><span class="p">,</span> <span class="n">i2</span><span class="p">,</span> <span class="n">i3</span><span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">failed</span><span class="sh">"</span><span class="p">)</span>
    <span class="nf">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">solve</span><span class="p">(</span><span class="n">array</span><span class="p">):</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">p =</span><span class="sh">"</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">q =</span><span class="sh">"</span><span class="p">,</span> <span class="n">q</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">g =</span><span class="sh">"</span><span class="p">,</span> <span class="n">g</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s"># searching for a, b, c...</span><span class="sh">"</span><span class="p">)</span>

    <span class="n">i1</span><span class="p">,</span> <span class="n">i2</span><span class="p">,</span> <span class="n">i3</span> <span class="o">=</span> <span class="nf">search</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span><span class="nf">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">array</span><span class="p">)))</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">array</span><span class="p">[</span><span class="n">i1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">array</span><span class="p">[</span><span class="n">i2</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">array</span><span class="p">[</span><span class="n">i3</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>

    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">a =</span><span class="sh">"</span><span class="p">,</span> <span class="n">array</span><span class="p">[</span><span class="n">i1</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">b =</span><span class="sh">"</span><span class="p">,</span> <span class="n">array</span><span class="p">[</span><span class="n">i2</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">c =</span><span class="sh">"</span><span class="p">,</span> <span class="n">array</span><span class="p">[</span><span class="n">i3</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">x =</span><span class="sh">"</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">hash_a =</span><span class="sh">"</span><span class="p">,</span> <span class="n">array</span><span class="p">[</span><span class="n">i1</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">hash_b =</span><span class="sh">"</span><span class="p">,</span> <span class="n">array</span><span class="p">[</span><span class="n">i2</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">hash_c =</span><span class="sh">"</span><span class="p">,</span> <span class="n">array</span><span class="p">[</span><span class="n">i3</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s"># solving dlp...</span><span class="sh">"</span><span class="p">)</span>
    
    <span class="n">log_a</span> <span class="o">=</span> <span class="nf">dlp</span><span class="p">(</span><span class="n">array</span><span class="p">[</span><span class="n">i1</span><span class="p">][</span><span class="mi">1</span><span class="p">],</span> <span class="n">g</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
    <span class="n">log_b</span> <span class="o">=</span> <span class="nf">dlp</span><span class="p">(</span><span class="n">array</span><span class="p">[</span><span class="n">i2</span><span class="p">][</span><span class="mi">1</span><span class="p">],</span> <span class="n">g</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
    <span class="n">log_c</span> <span class="o">=</span> <span class="nf">dlp</span><span class="p">(</span><span class="n">array</span><span class="p">[</span><span class="n">i3</span><span class="p">][</span><span class="mi">1</span><span class="p">],</span> <span class="n">g</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
    <span class="n">log_c_inv</span> <span class="o">=</span> <span class="nf">pow</span><span class="p">(</span><span class="n">log_c</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">q</span><span class="p">)</span>
    <span class="n">log_x</span> <span class="o">=</span> <span class="n">log_a</span> <span class="o">*</span> <span class="n">log_b</span> <span class="o">*</span> <span class="n">log_c_inv</span> <span class="o">%</span> <span class="n">q</span>
    <span class="n">hash_x</span> <span class="o">=</span> <span class="nf">pow</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">log_x</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">log_a =</span><span class="sh">"</span><span class="p">,</span> <span class="n">log_a</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">log_b =</span><span class="sh">"</span><span class="p">,</span> <span class="n">log_b</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">log_c =</span><span class="sh">"</span><span class="p">,</span> <span class="n">log_c</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">log_x =</span><span class="sh">"</span><span class="p">,</span> <span class="n">log_x</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">hash_x =</span><span class="sh">"</span><span class="p">,</span> <span class="n">hash_x</span><span class="p">)</span>

    <span class="nf">return </span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">hash_x</span><span class="p">)</span>

<span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">'</span><span class="s">data.txt</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">r</span><span class="sh">'</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">txt</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="nf">read</span><span class="p">()</span>
    <span class="n">lines</span> <span class="o">=</span> <span class="n">txt</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sh">'</span><span class="se">\n</span><span class="sh">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
    <span class="n">arr</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">line</span><span class="p">:</span> <span class="nf">list</span><span class="p">(</span><span class="nf">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="n">line</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sh">'</span><span class="s">,</span><span class="sh">'</span><span class="p">))),</span> <span class="n">lines</span><span class="p">))</span>

<span class="n">x</span><span class="p">,</span> <span class="n">log_x</span> <span class="o">=</span> <span class="nf">solve</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="nf">str</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="sh">'</span><span class="s">,</span><span class="sh">'</span> <span class="o">+</span> <span class="nf">str</span><span class="p">(</span><span class="n">log_x</span><span class="p">))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">mathmac.py</code></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env python3
</span>
<span class="kn">import</span> <span class="n">os</span>
<span class="kn">from</span> <span class="n">random</span> <span class="kn">import</span> <span class="n">randint</span>
<span class="kn">import</span> <span class="n">json</span>

<span class="n">flag</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="nf">getenv</span><span class="p">(</span><span class="sh">'</span><span class="s">FLAG</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">flag{redacted}</span><span class="sh">'</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">MAC</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">p</span> <span class="o">=</span> <span class="mi">8636821143825786083</span>
        <span class="n">self</span><span class="p">.</span><span class="n">n</span> <span class="o">=</span> <span class="n">n</span>
        <span class="n">self</span><span class="p">.</span><span class="n">sk</span> <span class="o">=</span> <span class="p">[</span><span class="nf">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">)]</span>
        <span class="n">self</span><span class="p">.</span><span class="n">base</span> <span class="o">=</span> <span class="nf">pow</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="nf">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">p</span><span class="p">),</span> <span class="n">self</span><span class="p">.</span><span class="n">p</span><span class="p">)</span>
    
    <span class="k">def</span> <span class="nf">sign</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">x</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="o">**</span><span class="n">self</span><span class="p">.</span><span class="n">n</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">None</span>
        <span class="n">x</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nf">bin</span><span class="p">(</span><span class="n">x</span><span class="p">)[</span><span class="mi">2</span><span class="p">:].</span><span class="nf">zfill</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">n</span><span class="p">)))</span>
        <span class="k">assert</span> <span class="nf">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="n">self</span><span class="p">.</span><span class="n">n</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">base</span>
        <span class="k">for</span> <span class="n">ai</span><span class="p">,</span> <span class="n">xi</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">sk</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">xi</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
                <span class="n">res</span> <span class="o">=</span> <span class="nf">pow</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">ai</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">p</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">res</span>


<span class="k">def</span> <span class="nf">menu</span><span class="p">():</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">1. Generate token</span><span class="sh">"</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">2. Validate token</span><span class="sh">"</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">3. Quit</span><span class="sh">"</span><span class="p">)</span>
    <span class="k">return</span> <span class="nf">int</span><span class="p">(</span><span class="nf">input</span><span class="p">(</span><span class="sh">"</span><span class="s">&gt; </span><span class="sh">"</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Welcome to the magic MathMAC. Can you become a wizard and guess tokens?</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">M</span> <span class="o">=</span> <span class="mi">64</span>
    <span class="n">mac</span> <span class="o">=</span> <span class="nc">MAC</span><span class="p">(</span><span class="n">M</span><span class="p">)</span>
    <span class="n">data</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="n">choice</span> <span class="o">=</span> <span class="nf">menu</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">choice</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
            <span class="n">x</span> <span class="o">=</span> <span class="nf">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="o">**</span><span class="n">M</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
            <span class="n">data</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="n">tag</span> <span class="o">=</span> <span class="n">mac</span><span class="p">.</span><span class="nf">sign</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s">,</span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">choice</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
            <span class="n">x</span><span class="p">,</span> <span class="n">tag</span> <span class="o">=</span> <span class="nf">input</span><span class="p">().</span><span class="nf">strip</span><span class="p">().</span><span class="nf">split</span><span class="p">(</span><span class="sh">"</span><span class="s">,</span><span class="sh">"</span><span class="p">)</span>
            <span class="n">x</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="n">tag</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">tag</span><span class="p">)</span>
            <span class="n">actual_tag</span> <span class="o">=</span> <span class="n">mac</span><span class="p">.</span><span class="nf">sign</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">actual_tag</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span> <span class="n">tag</span> <span class="o">!=</span> <span class="n">actual_tag</span><span class="p">:</span>
                <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Unlucky</span><span class="sh">"</span><span class="p">)</span>
                <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
                <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Yup. I know.</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="nf">print</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="nf">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">"</span><span class="s">__main__</span><span class="sh">"</span><span class="p">:</span>
    <span class="nf">main</span><span class="p">()</span>
</code></pre></div></div>]]></content><author><name>Oliver Kovacs</name></author><category term="writeup" /><summary type="html"><![CDATA[openECSC 2024 - Round 2]]></summary></entry><entry><title type="html">Stealing Seeds</title><link href="https://oliverkovacs.dev/writeup/2024/04/06/stealing-seeds.html" rel="alternate" type="text/html" title="Stealing Seeds" /><published>2024-04-06T00:00:00+02:00</published><updated>2024-04-06T00:00:00+02:00</updated><id>https://oliverkovacs.dev/writeup/2024/04/06/stealing-seeds</id><content type="html" xml:base="https://oliverkovacs.dev/writeup/2024/04/06/stealing-seeds.html"><![CDATA[<p><strong>openECSC 2024 - Round 1</strong></p>

<p>Category: <code class="language-plaintext highlighter-rouge">crypto</code></p>

<h2 id="description">Description</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I found an interesting way to generate numbers with someone. Wanna try?
</code></pre></div></div>
<p>Attachments: <code class="language-plaintext highlighter-rouge">stealing-seeds.py</code> (see <a href="#appendix">Appendix</a>)</p>

<h2 id="probem">Probem</h2>

<p>Let \(s \in \mathbb{P}\) and \(k \in \mathbb{Z}\) with \(0 \le s, k \lt 2^{256}\) be two secret numbers chosen at random.</p>

<p>Let \(f_1, f_2 \colon \{0, 1\}^{256} \to \{0, 1\}^{256}\) be</p>

\[f_1(u) = \text{sha256}(((s \oplus u) + s) \oplus k) \\
f_2(u) = \text{sha256}(((s + u) \oplus s) \oplus k)\]

<p>where \(\oplus\) denotes bit-wise XOR.</p>

<p>Given that you can compute \(f_1(u)\) and \(f_2(u)\) for any \(u \in \{0, 1\}^{256}\), find \(s\).</p>

<h2 id="solution">Solution</h2>

<p>This may not be the most elegant solution, however I will explain how to systematically find it without any advanced knowledge of cryptography and semi-formally argue why it is correct.</p>

<p>We first observe that \(\text{sha256} \colon \{0, 1\}^n \to \{0, 1\}^{256}\) is a <em>hash function</em>. It maps every sequence of bits to a sequence of 256 bits. Its outputs are distributed uniformly random, but the same input will always yield the same output. Furthermore we cannot find the pre-image of an output. That is, given  \(\text{sha256}(x)\) there is no way of finding \(x\) other than trying every possible value. This is obviously only feasible if the search space is severly limited.</p>

<p>Let us define \(g_1, g_2\) as</p>

\[\begin{align*}
&amp;g_1(u) = (s \oplus u) + s \\
&amp;g_2(u) = (s + u) \oplus s \ .
\end{align*}\]

<p>Now we observe that the \(f_i\) has the following structure:</p>

\[f_i(u) = \text{sha256}(g_i(u) \oplus k) \  .\]

<p>XOR can be interpreted as conditionally flipping a bit. More precisely, given two bits \(b, k \in \{0, 1\}\)</p>

\[b \oplus k = \begin{cases}
   b &amp;\text{if } k = 0 \\
   \neg\ b &amp;\text{if } k = 1
\end{cases}.\]

<p>This is problematic because it means that even knowing \(g_i(u)\) the term \(g_i(u) \oplus k\) could still be <em>any</em> number.
This implies that doing a brute-force search to find pre-images of \(\text{sha256}\) would require checking \(2^{256}\) (the amount of possible values of \(k\)) elements which is practically impossible.</p>

<p>To closer illustrate this consider that</p>

\[f_2(0) = \text{sha256}(((s + 0) \oplus s) \oplus k) = \text{sha256}((s \oplus s) \oplus k) = \text{sha256}(0 \oplus k) = \text{sha256}(k)\]

<p>could have any possible value depending on \(k\). This rules out a pre-image attack and thus extracting information from a single image is impossible.</p>

<p>But we observe that \(\text{sha256}\) behaves <em>as if</em> it were injective. A function \(f\) with the domain \(X\) is called injective if</p>

\[\forall a, b \in X \colon f(a) = f(b) \implies a = b \ .\]

<p>Technically this is not true for \(\text{sha256}\) as there are infinitely many hash collisions (this is evident by the fact that the output is limited to a finite number of bits) but in practice it is extremely unlikely to observe a hash collision.</p>

<p>If we now define the function</p>

\[x_k(u) = u \oplus k\]

<p>for some constant \(k\) we can see that</p>

\[x_k(x_k(u)) = (u \oplus k) \oplus k = u \oplus (k \oplus k) = u \oplus 0 = u\]

<p>therefore \(x_k = x_k^{-1}\) which implies that \(x_k\) is injective aswell.</p>

<p>It is easy to show that if two function \(f \colon B \to C, g \colon A \to B\) are injective then \(f \circ g \colon A \to C\) must also be injective.</p>

<p>We can now write</p>

\[f_i(u) = \text{sha256}(x_k(g_i(u)) \\\]

<p>and use the definition of injectivity to show that</p>

\[\begin{align*}
\forall u, v \colon &amp;f_1(u) = f_2(v) \\
\iff &amp;\text{sha256}(x_k(g_1(u))) = \text{sha256}(x_k(g_2(v))) \\
\implies &amp;g_1(u) = g_2(v) \ .
\end{align*}\]

<p>It is also worth to note that we can use the same arguments to show that</p>

\[\forall u, v \colon f_i(u) = f_i(v) \implies u = v \ .\\\]

<p>This gives us the crucial hint that we have to create an exploit by comparing the values of two different functions while trying out specific inputs.
To craft this exploit we fix \(s\) to some number and consider \(g_i(0), g_i(1), \ldots\)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>s = 1
u       0   1   2   3   4   5   6   7

g1      2   1   4   3   6   5   8   7
g2      0   3   2   5   4   7   6   9
</code></pre></div></div>

<p>Let \(p_s(u)\) be the number such that \(g_2(u) = g_1(p_s(u))\) or \(-1\) if no such number exists with \(s\) fixed to some value.
This is well defined as from the above result it follows that \(\forall u, v \colon u \neq v \implies g_i(u) \neq g_i(v)\).</p>

<p>We now look at a table of \(p_s(u)\) with the axes \(u\) and odd \(s\). A <code class="language-plaintext highlighter-rouge">.</code> denotes \(-1\).</p>

<blockquote>
  <p>Only odd \(s\) are considered as \(s\) is prime and very unlikely to be \(2\).</p>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u     0   1   2   3   4   5   6   7

p1    .   3   0   5   2   7   4   .
p3    .   7   0   1   2   .   4   5
p5    .   .   .   .   2   .   .   1
p7    .   .   0   1   2   3   4   5
</code></pre></div></div>

<p>We notice that</p>

\[\begin{align*}
&amp;p_3(7) = p_7(7) = 5 \neq p_{1,5}(7) \\
\implies &amp;g_2(7) = g_1(5) \iff f_2(7) = f_1(5) \iff s \in \{3, 7\} \iff s \equiv 3 \quad (\text{mod } 4) \ .
\end{align*}\]

<p>This means that by a single comparison we can halve the search space! A quick look at a larger table suggests that the method can be generalised.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u     0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15

p1    .   3   0   5   2   7   4   9   6  11   8  13  10  15  12   .
p3    .   7   0   1   2  11   4   5   6  15   8   9  10   .  12  13
p5    .   .   .  13   2  15  12   1   6   3   0   .  10   .   .   9
p7    .  15   0   1   2   3   4   5   6   .   8   9  10  11  12  13
p9    .   .   .   .   .   .   .   .   6   .   .   .   .   .   .   1
p11   .   .   .   .   .   .   4   5   6   .   .   .   .   3  12  13
p13   .   .   .   .   2   .   .   1   6   3   0   5  10   7   4   9
p15   .   .   0   1   2   3   4   5   6   7   8   9  10  11  12  13
</code></pre></div></div>

\[s \equiv \begin{cases}
    3 \equiv \begin{cases}
        7 &amp;\text{if } f_2(13) = f_1(11) \\
        3 &amp;\text{if } f_2(13) \neq f_1(11)
    \end{cases} (\text{mod } 8) &amp;\text{if } f_2(15) = f_1(13) \\
    1 \equiv \begin{cases}
        5 &amp;\text{if } f_2(15) = f_1(9) \\
        1 &amp;\text{if } f_2(15) \neq f_1(9)
    \end{cases} (\text{mod } 8) &amp;\text{if } f_2(15) \neq f_1(13)
\end{cases} (\text{mod } 4)\]

<p>To put this more concretely let us look at a slice of the above table:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u     ...   12  13        14  15
                         
p1    ...   10  15        12   .
p3    ...   10   .        12  13 (1)
p5    ...   10   .         .   9 (3)
p7    ...   10  11 (2)    12  13 (1)
p9    ...    .   .         .   1
p11   ...    .   3        12  13 (1)
p13   ...   10   7         4   9 (3)
p15   ...   10  11 (2)    12  13 (1)
</code></pre></div></div>

<p>The first comparison concerns the entries marked with <code class="language-plaintext highlighter-rouge">(1)</code>.</p>

<p>1) If it returns true we get this subtable of possible values and use the comparison marked with <code class="language-plaintext highlighter-rouge">(2)</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u     ...   12  13        14  15
                          
p3    ...   10   .        12  13 (1)
p7    ...   10  11 (2)    12  13 (1)
p11   ...    .   3        12  13 (1)
p15   ...   10  11 (2)    12  13 (1)
</code></pre></div></div>

<p>2) If it returns false we get the opposite subtable and use the comparison marked with <code class="language-plaintext highlighter-rouge">(3)</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u     ...   12  13        14  15
                          
p1    ...   10  15        12   .
p5    ...   10   .         .   9 (3)
p9    ...    .   .         .   1
p13   ...   10   7         4   9 (3)
</code></pre></div></div>

<p>Thus with every comparison one bit is recovered, meaning that \(s\) can be computed with 255 comparisons.
What remains is to reverse engineer the equation for the indices to compare at each step.
One possible solution can be found in the <a href="#appendix">Appendix</a>.
Then some automated way of submitting requests needs to be created to obtain the seed from the remote server.</p>

<p>Visualisation of the \(p_s(u)\) table obtained by coloring \(-1\) white.</p>

<h2 id="appendix">Appendix</h2>

<figure>
    <img src="/assets/img/posts/vis.png" alt="Graph" />
    <figcaption>Visualisation of the \(p_s(u)\) table obtained by coloring \(-1\) white.</figcaption>
</figure>

<p><code class="language-plaintext highlighter-rouge">solve.py</code></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">solve</span><span class="p">(</span><span class="n">k</span><span class="p">):</span>
    <span class="n">last</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="n">k</span> <span class="o">-</span> <span class="mi">1</span>
    <span class="n">out</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="n">index</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="n">delta_x</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">delta_y</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="nf">while </span><span class="p">(</span><span class="n">index</span> <span class="o">&lt;</span> <span class="n">k</span><span class="p">):</span>
        <span class="n">mask</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">**</span> <span class="n">index</span>
        <span class="n">delta_y</span> <span class="o">|=</span> <span class="n">mask</span>
        
        <span class="c1"># x y
</span>        <span class="nf">print</span><span class="p">(</span><span class="n">last</span> <span class="o">-</span> <span class="n">delta_y</span><span class="p">,</span> <span class="n">last</span> <span class="o">-</span> <span class="n">delta_x</span><span class="p">)</span>
    
        <span class="c1"># compute f1(x) == f2(y)
</span>        <span class="c1"># write result to stdin
</span>        <span class="n">equal</span> <span class="o">=</span> <span class="nf">bool</span><span class="p">(</span><span class="nf">int</span><span class="p">(</span><span class="nf">input</span><span class="p">()))</span>
        <span class="nf">if </span><span class="p">(</span><span class="n">equal</span><span class="p">):</span>
            <span class="n">out</span> <span class="o">|=</span> <span class="n">mask</span>
            <span class="n">delta_x</span> <span class="o">|=</span> <span class="n">mask</span>
            <span class="n">delta_y</span> <span class="o">^=</span> <span class="n">mask</span>

        <span class="n">index</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">out</span> <span class="o">=</span> <span class="si">}</span><span class="sh">"</span><span class="p">)</span>

<span class="nf">solve</span><span class="p">(</span><span class="mi">256</span><span class="p">)</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">stealing-seeds.py</code></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env python3
</span>
<span class="kn">import</span> <span class="n">os</span>
<span class="kn">import</span> <span class="n">signal</span>
<span class="kn">import</span> <span class="n">random</span>
<span class="kn">from</span> <span class="n">Crypto.Util.number</span> <span class="kn">import</span> <span class="n">getPrime</span><span class="p">,</span> <span class="n">long_to_bytes</span><span class="p">,</span> <span class="n">bytes_to_long</span>
<span class="kn">from</span> <span class="n">hashlib</span> <span class="kn">import</span> <span class="n">sha256</span>

<span class="nf">assert</span><span class="p">(</span><span class="sh">"</span><span class="s">FLAG</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">)</span>
<span class="n">FLAG</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">[</span><span class="sh">"</span><span class="s">FLAG</span><span class="sh">"</span><span class="p">]</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">FLAG</span><span class="p">.</span><span class="nf">startswith</span><span class="p">(</span><span class="sh">"</span><span class="s">openECSC{</span><span class="sh">"</span><span class="p">))</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">FLAG</span><span class="p">.</span><span class="nf">endswith</span><span class="p">(</span><span class="sh">"</span><span class="s">}</span><span class="sh">"</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>

    <span class="n">seed_size</span> <span class="o">=</span> <span class="mi">256</span>
    <span class="n">seed</span> <span class="o">=</span> <span class="nf">getPrime</span><span class="p">(</span><span class="n">seed_size</span><span class="p">)</span>
    <span class="n">seed</span> <span class="o">=</span> <span class="mi">11</span>

    <span class="c1"># Just to protect my seed
</span>    <span class="n">k</span> <span class="o">=</span> <span class="n">random</span><span class="p">.</span><span class="nf">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="o">**</span><span class="n">seed_size</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">seed_size</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">seed</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">k</span> <span class="o">=</span> <span class="si">}</span><span class="sh">'</span><span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sh">"""</span><span class="s">I have my seed, if you give me yours we can generate some random numbers together!
Just don</span><span class="sh">'</span><span class="s">t try to steal mine...
</span><span class="sh">"""</span><span class="p">)</span>

    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="n">choice</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="nf">input</span><span class="p">(</span><span class="sh">"""</span><span class="s">Which random do you want to use?
1) Secure
2) Even more secure
3) That</span><span class="sh">'</span><span class="s">s enough
&gt; </span><span class="sh">"""</span><span class="p">))</span>
        <span class="k">if</span> <span class="n">choice</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]:</span>
            <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">We don</span><span class="sh">'</span><span class="s">t have that :(</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">continue</span>
        <span class="k">if</span> <span class="n">choice</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
            <span class="k">break</span>
        <span class="n">user_seed</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span>
            <span class="nf">input</span><span class="p">(</span><span class="sh">"</span><span class="s">Give me your seed: </span><span class="sh">"</span><span class="p">))</span>
        <span class="k">if</span> <span class="n">user_seed</span><span class="p">.</span><span class="nf">bit_length</span><span class="p">()</span> <span class="o">&gt;</span> <span class="n">seed_size</span><span class="p">:</span>
            <span class="nf">print</span><span class="p">(</span>
                <span class="sa">f</span><span class="sh">"</span><span class="s">Your seed can be at most </span><span class="si">{</span><span class="n">seed_size</span><span class="si">}</span><span class="s"> bits!</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">continue</span>
        <span class="k">if</span> <span class="n">choice</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
            <span class="n">final_seed</span> <span class="o">=</span> <span class="p">((</span><span class="n">seed</span> <span class="o">^</span> <span class="n">user_seed</span><span class="p">)</span> <span class="o">+</span>
                           <span class="n">seed</span><span class="p">)</span> <span class="o">^</span> <span class="n">k</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">final_seed</span> <span class="o">=</span> <span class="p">((</span><span class="n">seed</span> <span class="o">+</span> <span class="n">user_seed</span><span class="p">)</span> <span class="o">^</span>
                           <span class="n">seed</span><span class="p">)</span> <span class="o">^</span> <span class="n">k</span>

        <span class="n">random_number</span> <span class="o">=</span> <span class="nf">bytes_to_long</span><span class="p">(</span><span class="nf">sha256</span><span class="p">(</span><span class="nf">long_to_bytes</span><span class="p">(</span><span class="n">final_seed</span><span class="p">)).</span><span class="nf">digest</span><span class="p">())</span>

        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Random number:</span><span class="sh">"</span><span class="p">,</span> <span class="n">random_number</span><span class="p">)</span>
    
    <span class="n">guess</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="nf">input</span><span class="p">(</span><span class="sh">"</span><span class="s">Hey, did you steal my seed? </span><span class="sh">"</span><span class="p">))</span>

    <span class="k">if</span> <span class="n">guess</span> <span class="o">==</span> <span class="n">seed</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="n">FLAG</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Ok, I trust you</span><span class="sh">"</span><span class="p">)</span>
    <span class="k">return</span>


<span class="k">def</span> <span class="nf">handler</span><span class="p">(</span><span class="n">signum</span><span class="p">,</span> <span class="n">frame</span><span class="p">):</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Time over!</span><span class="sh">"</span><span class="p">)</span>
    <span class="nf">exit</span><span class="p">()</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">"</span><span class="s">__main__</span><span class="sh">"</span><span class="p">:</span>
    <span class="n">signal</span><span class="p">.</span><span class="nf">signal</span><span class="p">(</span><span class="n">signal</span><span class="p">.</span><span class="n">SIGALRM</span><span class="p">,</span> <span class="n">handler</span><span class="p">)</span>
    <span class="n">signal</span><span class="p">.</span><span class="nf">alarm</span><span class="p">(</span><span class="mi">30000</span><span class="p">)</span>
    <span class="nf">main</span><span class="p">()</span>
</code></pre></div></div>]]></content><author><name>Oliver Kovacs</name></author><category term="writeup" /><summary type="html"><![CDATA[openECSC 2024 - Round 1]]></summary></entry></feed>