<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Thore Göbel</title><link>https://thore.io/posts/</link><description>Recent content in Posts on Thore Göbel</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>Thore Göbel</copyright><lastBuildDate>Fri, 27 Mar 2026 07:00:00 +0000</lastBuildDate><atom:link href="https://thore.io/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Link-Local File Transfer</title><link>https://thore.io/posts/2026/03/link-local-file-transfer/</link><pubDate>Fri, 27 Mar 2026 07:00:00 +0000</pubDate><guid>https://thore.io/posts/2026/03/link-local-file-transfer/</guid><description>&lt;p>Do you:&lt;/p>
&lt;ul>
&lt;li>Have two Linux machines sitting next to each other?&lt;/li>
&lt;li>Want to transfer some files?&lt;/li>
&lt;li>Not have a USB stick handy?&lt;/li>
&lt;li>Have an ethernet cable?&lt;/li>
&lt;/ul>
&lt;p>Then this simple &lt;del>hack&lt;/del> guide is for you!
You can connect the two computer directly with each other using an ethernet cable
and transfer a file using &lt;a href="https://en.wikipedia.org/wiki/Netcat">netcat&lt;/a>.
This will pipe the file in on one end of the cable, and it will come out the other end.&lt;/p></description><content type="html"><![CDATA[<p>Do you:</p>
<ul>
<li>Have two Linux machines sitting next to each other?</li>
<li>Want to transfer some files?</li>
<li>Not have a USB stick handy?</li>
<li>Have an ethernet cable?</li>
</ul>
<p>Then this simple <del>hack</del> guide is for you!
You can connect the two computer directly with each other using an ethernet cable
and transfer a file using <a href="https://en.wikipedia.org/wiki/Netcat">netcat</a>.
This will pipe the file in on one end of the cable, and it will come out the other end.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>On both machines, install <code>netcat-openbsd</code>.
By default, Debian comes with <code>netcat-traditional</code>, which does not support IPv6.</p>
<pre><code class="language-sh">sudo apt remove netcat-traditional
sudo apt install netcat-openbsd
</code></pre>
<h2 id="connect-the-computers">Connect the computers</h2>
<p>Directly connect the two computers using an ethernet cable (possibly using RJ45-to-USB-C adapters).</p>
<p>There is <strong>no switch</strong> or any other networking equipment inbetween! It is really a direct link.
On modern machines this should work with any ethernet cable,
because recent network cards support <a href="https://en.wikipedia.org/wiki/Medium-dependent_interface">Auto-MDI-X</a>.
On older hardware, you need to use a crossover cable (due to the absence of a switch).</p>
<h2 id="get-the-link-local-ipv6-address">Get the link-local IPv6 address</h2>
<p>On the <strong>target</strong> machine, list the IPv6 addresses of the interfaces:</p>
<pre><code class="language-shell">ip -6 a
</code></pre>
<p>Look for the <a href="https://en.wikipedia.org/wiki/Link-local_address">link-local</a> address, which starts with <code>fe80:</code>.
Note down this address.</p>
<p>If either of your computers has a network manager (which is very likely if it has a desktop environment),
you need to change the IPv4 and IPv6 address selection method from &ldquo;Automatic&rdquo; to &ldquo;Link-local&rdquo; for the wired interface.
Otherwise it will look for a DHCP server (to no avail).</p>
<p>On KDE Plasma, the network manager settings look like this:</p>


<img src="/img/link-local-network-manager.png"   class="center" />

<h2 id="check-connectivity">Check connectivity</h2>
<p>Check that the <strong>source</strong> machine can ping the <strong>target</strong> machine.
Run the following command on the source machine:</p>
<pre><code class="language-sh">ping fe80::1122:3344:5566:7788%eth0
</code></pre>
<p>This is the IPv6 address of the <strong>target</strong> machine followed by the interface name of the <strong>source</strong> machine.</p>
<p>In IPv6 you need to add the interface name at the end, separated by <code>%</code>.
This is because all interfaces share the same link-local subnet (<code>fe80::/10</code>),
so the network stack needs to know through which interface to send the traffic.</p>
<p>Your network interface is called something like <code>enp0s10</code> or <code>eth0</code>.
You can list the available interfaces with:</p>
<pre><code class="language-sh">ip link show
</code></pre>
<p>This also shows the state of the link (UP/DOWN).</p>
<h2 id="do-the-file-transfer">Do the file transfer</h2>
<p>On the <strong>target</strong> machine, start netcat:</p>
<pre><code class="language-sh">nc -vl6 9000 &gt; file.txt
</code></pre>
<p>This causes netcat to listen on port 9000 and to write any data that it receives to the named file.</p>
<p>On the <strong>source</strong> machine, send the data with netcat:</p>
<pre><code class="language-sh">nc -N fe80::1122:3344:5566:7788%eth0 9000 &lt; file.txt
</code></pre>
<p>This causes netcat to connect to the given IPv6 address and port, and then send the contents of the file.
Again, note the interface name at the end, separated by <code>%</code>.</p>
<p>The netcat instance on the target machine should receive the contents and write them to its file.</p>
<h2 id="security">Security</h2>
<p>This is a very basic transfer mechanism.
It&rsquo;s secure because (and only if) you physically control the entire, single network cable.
It&rsquo;s intended for quick-and-dirty on-desk setups.</p>
<p>Importantly, the netcat approach does not have any cryptographic confidentiality, integrity, or authenticity guarantees!
As a basic integrity check, you can compute the <code>sha256sum</code> of the file on both ends.</p>
<p>If you are doing this over a real network, you should use ssh combined with scp or rsync.
They require a bit more setup than netcat, but provide security against a network adversary.</p>
]]></content></item><item><title>Introduction to Arm Memory Tagging Extensions</title><link>https://thore.io/posts/2025/09/introduction-to-arm-memory-tagging-extensions/</link><pubDate>Tue, 16 Sep 2025 19:00:00 +0200</pubDate><guid>https://thore.io/posts/2025/09/introduction-to-arm-memory-tagging-extensions/</guid><description>&lt;p>This post is an introduction into Arm Memory Tagging Extensions (MTE),
a hardware-based defense against memory safety vulnerabilities.
Arm MTE is available in Google Pixel 8 devices (released 2023) and in iPhone 17 devices (released 2025).&lt;/p>
&lt;p>The focus of this post is on explaining the high-level ideas, why MTE is important,
and how developers can enable MTE in their Android and iOS apps.&lt;/p>
&lt;h2 id="background-memory-allocations">Background: memory allocations&lt;/h2>
&lt;p>Programs store data in memory either on the &lt;a href="https://en.wikipedia.org/wiki/Stack-based_memory_allocation">stack&lt;/a>
or on the &lt;a href="https://en.wikipedia.org/wiki/Memory_management">heap&lt;/a>.
Generally, the stack is used for data that is small and whose size is known when the program is compiled.
The heap is used for larger data and for data whose size is only known when the program executes
(for example, any data that the user inputs).&lt;/p></description><content type="html"><![CDATA[<p>This post is an introduction into Arm Memory Tagging Extensions (MTE),
a hardware-based defense against memory safety vulnerabilities.
Arm MTE is available in Google Pixel 8 devices (released 2023) and in iPhone 17 devices (released 2025).</p>
<p>The focus of this post is on explaining the high-level ideas, why MTE is important,
and how developers can enable MTE in their Android and iOS apps.</p>
<h2 id="background-memory-allocations">Background: memory allocations</h2>
<p>Programs store data in memory either on the <a href="https://en.wikipedia.org/wiki/Stack-based_memory_allocation">stack</a>
or on the <a href="https://en.wikipedia.org/wiki/Memory_management">heap</a>.
Generally, the stack is used for data that is small and whose size is known when the program is compiled.
The heap is used for larger data and for data whose size is only known when the program executes
(for example, any data that the user inputs).</p>
<p>Memory on the stack is &ldquo;automatically managed&rdquo; in the sense that the compiler inserts
instructions to automatically &ldquo;allocate&rdquo; and &ldquo;deallocate&rdquo; memory on the stack (by moving the stack pointer).
This is possible because the compiler already knows the size of the needed memory.</p>
<p>Memory on the heap is dynamically managed by the program when it executes.
The program calls <code>malloc(size)</code> to allocate some memory.
The memory allocator then reserves the requested memory size and gives the program a pointer to where this memory section is.
Once the program no longer needs this memory, it should call <code>free(pointer)</code> to tell the allocator that the memory can be reused.</p>
<p>This manual memory management (malloc+free) is common in C and C++.
In other languages, developers don&rsquo;t need to manually manage heap memory:
In Java and Go the <a href="https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29">garbage collector</a>
periodically frees unused memory.
In Rust, the compiler automatically inserts <code>free()</code> statements into the compiled code
(since Rust&rsquo;s ownership semantics allow the compiler to figure out when a value will become unused).
In Swift and in C++&rsquo;s smart pointers, <a href="https://en.wikipedia.org/wiki/Automatic_Reference_Counting">Automatic Reference Counting</a>
automatically frees memory once it is no longer referenced.</p>
<h2 id="background-memory-vulnerabilities">Background: memory vulnerabilities</h2>
<p>Manual memory management puts a burden on programmers using C/C++.
Programmers need to make sure to only access memory that is allocated,
to not forget to free the memory (causing memory leaks),
and to not access the memory again once it has been freed.
Unfortunately, as the last 30+ years have shown, C/C++ programmers repeatedly make these mistakes. A lot.</p>
<p>These mistakes in memory management are a common source of vulnerabilities:</p>
<ul>
<li><strong>Spatial safety (out-of-bounds access, buffer overflow):</strong>
The program accesses memory outside its allocated region.
(This can happen with stack memory, too.)</li>
<li><strong>Temporal safety (use-after-free, double free):</strong>
The program accesses memory after it has freed it.</li>
</ul>
<p>By maliciously crafting inputs, an attacker can exploit such memory issues to take over the program flow and execute custom code.</p>
<h2 id="defenses-against-memory-safety-vulnerabilities">Defenses against memory safety vulnerabilities</h2>
<p>Unfortunately, memory safety vulnerabilities are very common in C and C++,
and a LOT of code is written in those languages.
Therefore unsurprisingly, people have been looking into defenses for a long time.
Examples of such defenses are:</p>
<ul>
<li>Hardened memory allocators,
for example in <a href="https://en.wikipedia.org/wiki/Security_and_privacy_of_iOS#Hardened_memory_allocation">iOS</a>
and <a href="https://github.com/GrapheneOS/hardened_malloc">GrapheneOS</a>.</li>
<li>Pointer authentication (PAC),
for example in <a href="https://en.wikipedia.org/wiki/Return-oriented_programming#Pointer_Authentication_Codes_%28PAC%29">iOS</a>
and <a href="https://community.arm.com/arm-community-blogs/b/operating-systems-blog/posts/control-flow-integrity">Chromium for Android</a>.</li>
<li><a href="https://en.wikipedia.org/wiki/Control-flow_integrity">Control flow integrity (CFI)</a> such as PAC,
<a href="https://en.wikipedia.org/wiki/Indirect_branch_tracking">BTI</a>, shadow stacks, and stack canaries.
<ul>
<li>This prevents attackers from redirecting the control flow of a program to an unintended path.</li>
</ul>
</li>
<li>MTE
<ul>
<li>This prevents attackers from corrupting memory (possibly to redirect the control flow later).</li>
</ul>
</li>
</ul>
<p>Note that these approaches are complementary, and should be used together.</p>
<p>What these approaches and MTE have in common, is that they don&rsquo;t require changes
to existing code (except that some require re-compiling the program).
Additionally, they eliminate entire classes of attacks across the entire program.</p>
<p>Other approaches (like <a href="https://en.wikipedia.org/wiki/Smart_pointer">smart pointers</a>) also exist,
but they require developers to rewrite their code (and all of their dependencies!) to use modern, &ldquo;safe&rdquo; idioms/language features.
This is a lot of work &ndash; work that is arguably better spent on rewriting the code in a memory-safe language such as Rust.
Also, they only eliminate issues in the narrow sections of code where they are applied.</p>
<p>Sidenote: unsafe memory usage <a href="https://alexgaynor.net/2019/apr/21/modern-c&#43;&#43;-wont-save-us/">hides</a>
even in modern C++ idioms!</p>
<h2 id="how-mte-works">How MTE works</h2>
<p>Memory tagging works by assigning a unique, random <em>tag</em> to every memory location.
This tag changes every time a memory location is allocated with <code>malloc()</code> and every time it is <code>free()</code>d.</p>
<p><code>malloc()</code> returns a <em>pointer</em> to the start of the allocated memory region.
The tag for this memory region is embedded/encoded into the pointer.</p>
<p>Memory is accessed via pointers, possibly with an offset
(&ldquo;please read the value stored at the memory location this pointer points to&rdquo;).
An access can be a read or a write.
For each memory access, the hardware checks that the tag in the pointer matches the tag of the memory location.
If they mismatch, the access is denied. In practice, this causes the app to crash.</p>
<p>This scheme prevents invalid memory accesses, because invalid accesses will have non-matching tags:</p>
<ul>
<li>Spatial safety (out-of-bounds access, buffer overflow):
The memory location has a different tag than the pointer,
because the pointer came from the allocation of a different memory region.</li>
<li>Temporal safety (use-after-free):
The pointer and the memory location had matching tags in the past,
but when the memory was freed, the memory tag changed.</li>
</ul>
<p>To attack MTE, an attacker needs to guess the tag of the memory location they want to access,
and then modify the pointer to have the same tag.
For example, an attacker might leak the tag via a side-channel (see <a href="/posts/2025/09/introduction-to-arm-memory-tagging-extensions/#no-silver-bullet">below</a>).</p>
<p>For a more detailed explanation, see the links <a href="/posts/2025/09/introduction-to-arm-memory-tagging-extensions/#further-reading">at the bottom</a> of this post.</p>
<p>For a visual representation, see the figures below, taken from the
<a href="https://docs.google.com/presentation/d/10V_msbtEap9dNerKvTrRAzvfzYdrQFC8e2NYHCZYJDE/view">slides</a>
of <a href="https://www.youtube.com/watch?v=9wRT2hNwbkA">this talk</a> by Andrey Konovalov.
Tags are represented as colors.</p>
<p><figure><img src="/img/mte_oob.png"
    alt="Out-of-bounds with MTE"><figcaption>
      <p>Out-of-bounds with MTE</p>
    </figcaption>
</figure>

<figure><img src="/img/mte_uaf.png"
    alt="Use-after-free with MTE"><figcaption>
      <p>Use-after-free with MTE</p>
    </figcaption>
</figure>
</p>
<h2 id="mte-on-android">MTE on Android</h2>
<p>Among Android devices, Google Pixel 8 (and later) are the only known devices
with hardware support for MTE, thanks to Google&rsquo;s Tensor G3 chip.
They were <a href="https://googleprojectzero.blogspot.com/2023/11/first-handset-with-mte-on-market.html">released in October 2023</a>.</p>
<p>No other Android phones seem to have practical MTE.
A big reason is the lack of hardware support (see the <a href="/posts/2025/09/introduction-to-arm-memory-tagging-extensions/#appendix-hardware-support">appendix</a>).
However, even if the chip would support it, every phone vendor customizes Android,
and may not enable MTE in their operating system.</p>
<p>On Google Pixel&rsquo;s Android, MTE is NOT enabled for the kernel, but it is enabled for
critical userspace system processes such as Bluetooth, NFC, and SecureElement
(<a href="https://source.android.com/docs/security/test/memory-safety/mte-configuration">source</a>).
Additionally, <a href="https://support.google.com/android/answer/16339980?hl=en">Android Advanced Protection Mode</a> enables MTE.
(However, I haven&rsquo;t found an offical source that says for which parts MTE is additionally enabled by Advanced Protection.)</p>
<p>On <a href="https://grapheneos.org/">GrapheneOS</a> (a security-focussed Android-based operating system),
MTE is enabled for the kernel, for some of the system apps, and for user-installed apps that don&rsquo;t have native code
(<a href="https://grapheneos.social/@GrapheneOS/114721878120169404">source 1</a>,
<a href="https://grapheneos.social/@GrapheneOS/115177759496849433">source 2</a>).</p>
<p>To enable MTE for a given app, the app developer needs to explicitly opt-in by
<a href="https://source.android.com/docs/security/test/memory-safety/arm-mte#enable-mte-apps">setting</a>
<code>android:memtagMode=&quot;async&quot;</code> in the <code>AndroidManifest.xml</code> of their app.
Additionally, GrapheneOS provides a toggle allowing users to force MTE for specific apps.</p>
<h2 id="mte-on-ios">MTE on iOS</h2>
<p>Apple&rsquo;s marketing name for MTE is <a href="https://security.apple.com/blog/memory-integrity-enforcement/">Memory Integrity Enforcement (MIE)</a>.
MIE is supported on the A19 chip, included in iPhone 17 devices, launched in September 2025.
It is unclear if and when MIE is coming to M-series chips (for iPads and Macs).
MIE uses a newer version of Arm MTE; the concepts are the same.</p>
<p>On iOS, MIE <a href="https://security.apple.com/blog/memory-integrity-enforcement/">is enabled</a>
in the &ldquo;the kernel and over 70 userland processes&rdquo;.</p>
<p>To enable MIE for a given app, the app developer needs to explicitly opt-in by
<a href="https://developer.apple.com/documentation/xcode/enabling-enhanced-security-for-your-app">setting the appropriate entitlement</a>.</p>
<h2 id="why-is-mte-not-more-widely-deployed">Why is MTE not more widely deployed?</h2>
<p>Why has MTE not been deployed sooner?
Why is MTE not enabled for every app and every process on the phone, but only for some?</p>
<p>MTE has two &ldquo;problems&rdquo;:</p>
<ol>
<li><strong>Performance:</strong> Maintaining and checking the tags introduces a computational and memory overhead.</li>
<li><strong>Crashes:</strong> Invalid memory accesses cause crashes.
Without MTE, buggy apps that make invalid accesses (such as use-after-free) often silently work.
With MTE, these accesses are denied and the apps crash (by design).
(Note that MTE does not introduce new bugs, but it makes existing bugs very visible to the user.)</li>
</ol>
<p>Performance is one of the reasons why Google is hesitant to enable MTE for more parts of Android,
and why it is keeping MTE disabled for the kernel.
Apple has solved the performance problem by <a href="https://security.apple.com/blog/memory-integrity-enforcement/">deeply optimising</a> the hardware for MIE.
Its new A19 chip <a href="https://www.macrumors.com/2025/09/10/iphone-17-pro-iphone-air-a19-pro-benchmarks/">is much faster</a>, even with MIE enabled.</p>
<blockquote>
<p>Sidenote:
Product requirements driving chip design
<a href="https://creativestrategies.com/iphone-13-and-apple-silicon/">is a recurring pattern</a> at Apple.
Apple doesn&rsquo;t build a fast chip and then thinks about what it can do with it.
Instead, they start with a requirement (cinematic mode in iPhone 13, MIE in iPhone 17),
and then design the chip to support the desired feature (massive GPU performance in A15, MIE performance in A19).</p>
</blockquote>
<p>Crashes are the reason why both Apple and Google don&rsquo;t force-enable MTE for user-installed apps.
Instead, app developers need to opt-in to MTE on both Android and iOS.</p>
<p>It is not clear if Apple and Google force-enable MTE for user-installed apps
when Lockdown Mode/Advanced Protection are enabled.
Doing so would make sense because users with such high security requirements benefit the most from MTE,
while also being more likely to accept some app crashes (as the price of security).</p>
<p>To underline the point about app crashes:
Apple Music on Android regularly crashes on my Pixel 8a with GrapheneOS.
Here is an example of a stack trace:</p>
<pre><code class="language-log">type: crash
osVersion: google/akita/akita:16/BP2A.250805.005/2025091000:user/release-keys
package: com.apple.android.music:1472, targetSdk 35
sharedUid: com.apple.android
process: com.apple.android.music

signal 11 (SIGSEGV), code 9 (SEGV_MTESERR), fault addr 0x0d00c4378c1aecb8

backtrace:
      #00 pc 0000000000604c5c  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/lib/arm64/libandroidappmusic.so (BuildId: b52cdcc1f1daf9a96aaaa911f060d467d7b54552)
      #01 pc 0000000000601ae0  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/lib/arm64/libandroidappmusic.so (BuildId: b52cdcc1f1daf9a96aaaa911f060d467d7b54552)
      #02 pc 0000000000600c24  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/lib/arm64/libandroidappmusic.so (BuildId: b52cdcc1f1daf9a96aaaa911f060d467d7b54552)
      #03 pc 000000000033ae04  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/lib/arm64/libandroidappmusic.so (Java_com_apple_android_music_renderer_javanative_LevelComposer_compose+268) (BuildId: b52cdcc1f1daf9a96aaaa911f060d467d7b54552)
      #04 pc 0000000000049d7c  /system/framework/arm64/boot-core-libart.oat (art_jni_trampoline+140) (BuildId: e221ad2e1579dba8c552c66ad1435db15dd3b38c)
      #05 pc 00000000025b4a64  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/oat/arm64/base.odex (com.apple.android.music.playback.player.PlayerAudioFadeControl.setComposerTransition+1092)
      #06 pc 00000000025ae7d0  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/oat/arm64/base.odex (com.apple.android.music.playback.player.PlayerAudioFadeControl$computeTransitionJob$1.invokeSuspend+304)
      #07 pc 0000000003541ef8  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/oat/arm64/base.odex (Vb.a.resumeWith+152)
      #08 pc 000000000362b070  /data/app/~~qvCT42FscwNrFow1psc79g==/com.apple.android.music-SUeV4RIatUrpGVV1gt7VDg==/oat/arm64/base.odex (yd.T.run+1024)
      #09 pc 0000000000214c54  /system/framework/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+676) (BuildId: 5e31ba31fc4f779978b4ee5a158a82f8b97f6aad)
      #10 pc 0000000000218bf8  /system/framework/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+56) (BuildId: 5e31ba31fc4f779978b4ee5a158a82f8b97f6aad)
      #11 pc 00000000000a94f0  /system/framework/arm64/boot.oat (java.lang.Thread.run+64) (BuildId: 5e31ba31fc4f779978b4ee5a158a82f8b97f6aad)
      #12 pc 00000000002faf94  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: c3d2bff6e80fd46838179f7753be74fa)
      #13 pc 00000000002e59dc  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+220) (BuildId: c3d2bff6e80fd46838179f7753be74fa)
      #14 pc 000000000042b08c  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+940) (BuildId: c3d2bff6e80fd46838179f7753be74fa)
      #15 pc 000000000042accc  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallbackWithUffdGc(void*)+12) (BuildId: c3d2bff6e80fd46838179f7753be74fa)
      #16 pc 000000000008e254  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+180) (BuildId: e688446b48f00a577c82f6e36cac2c6e)
      #17 pc 000000000007f9f4  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: e688446b48f00a577c82f6e36cac2c6e)
</code></pre>
<p>The good news is that crashes are the exception.
I have MTE force-enabled for nearly all apps on my Pixel 8a with GrapheneOS,
and I have seen very few crashes in the past year.</p>
<h2 id="how-to-enable-mte-for-your-android-or-ios-app">How to enable MTE for your Android or iOS app</h2>
<p><strong>As a user,</strong> there is little you can do.
At the minimum, you need to buy a Pixel 8 or iPhone 17 (and later) to have the hardware support,
and rely on Google/Apple to enable MTE for the operating system.
On Android, you can also enable Advanced Protection or install GrapheneOS.
For manually installed apps, you are reliant on app developers enabling MTE for their apps (ask them about it!).</p>
<p><strong>As an app developer,</strong> you can opt-in your app into using MTE (by setting the manifest flag or the entitlement, see above).
Especially if you don&rsquo;t have native code (only Java/Kotlin), this should be easy and not cause any issues.
If you have custom native code, MTE may even detect some bugs that you were previously not aware of.</p>
<p>Important: before you ship a release with MTE enabled, thoroughly test your app
on a supported device (Pixel 8 and iPhone 17), and fix any crashes that you find.</p>
<h2 id="should-you-enable-mte-for-your-app">Should you enable MTE for your app?</h2>
<p>Yes!</p>
<p>It is easy to do, and should not impact your app much.
You likely won&rsquo;t notice the performance impact (especially on iPhone),
and crashes are few (in my experience on GrapheneOS).</p>
<p>MTE crashes only surface existing bugs that you didn&rsquo;t know about and should fix anyway.
So MTE is also a useful bug finding tool.</p>
<p>In Java, when you try to access data outside of an array, you get an <code>ArrayIndexOutOfBoundsException</code>.
In C, writing data outside of a buffer may sometimes work, but it silently corrupts memory.
This corruption can lead to crashes much later, which are very difficult to debug!
With MTE, your C code instead crashes immediately<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, just like an <code>ArrayIndexOutOfBoundsException</code> would crash your app.
The crash is not really the fault of MTE, you need to fix your code.
So don&rsquo;t be &ldquo;scared&rdquo; of MTE, just test your app properly on MTE-enabled hardware.</p>
<p>Interestingly, even if your Android app is written in Java/Kotlin and has no native bundled into the APK file,
at runtime your app&rsquo;s process may call Android framework functions that use native code,
which can have memory vulnerabilities.
Therefore, even if you don&rsquo;t explicitly use native code, MTE can still protect your app.
For a real-world example, see <a href="https://web.archive.org/web/20250711021912/https://dustri.org/b/grapheneoss-mte-caught-a-crash-in-signal.html">this bug</a>
in the Signal messenger that was detected by MTE.</p>
<p>Especially <strong>apps that handle input that can be controlled by a remote attacker over the network</strong> should enable MTE.
Among others, this includes web browsers, messenger apps, e-mail clients, social media,
file sharing and cloud storage apps, and media streaming (video, music, podcasts).
These apps allow attackers to remotely and relatively easily cause your phone to load malicious content
(by sending a message, sharing a file, tricking you into opening a website or watching a video).
And unfortunately, media parsers are a common source of vulnerabilities,
because image/audio/video formats are very complex.
For example, see the <a href="https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html">2021 FORCEDENTRY</a>
and the <a href="https://googleprojectzero.blogspot.com/2025/03/blasting-past-webp.html">2023 BLASTPASS</a> exploits.</p>
<h2 id="no-silver-bullet">No silver bullet</h2>
<p>None of the discussed defenses are magical solutions:</p>
<ul>
<li>Both Pointer Authentication (<a href="https://en.wikipedia.org/wiki/Pacman_%28security_vulnerability%29">PACMAN</a>)
and MTE (<a href="https://www.vusec.net/projects/stickytags/">StickyTags</a>, <a href="https://arxiv.org/abs/2406.08719">TikTag</a>)
have been vulnerable to side-channel attacks.</li>
<li>MTE only applies to main memory.
GitHub researchers <a href="https://github.blog/security/vulnerability-research/gaining-kernel-code-execution-on-an-mte-enabled-pixel-8/">demonstrated an attack</a>
that (ab)uses GPU memory.</li>
</ul>
<p>Nevertheless, these defenses raise the bar and eliminiate entire classes of attacks.
This forces attackers to come up with more complicated exploitation techniques.
MTE raises the cost of attacks.</p>
<h2 id="conclusion">Conclusion</h2>
<p>This post gave a high-level introduction into Arm MTE.
MTE is a strong defense against memory vulnerabilities.
Hardware support is still limited to a few devices, but will hopefully grow.
MTE already protects parts of the operating system and system apps.
To protect user-installed apps, app developers need to manually enable MTE and test their apps with it.</p>
<p>Here is what you can do next:</p>
<ul>
<li>If you want to dive deeper into the technical details, continue reading with the resources linked below.</li>
<li>If you are a security-conscious user, consider buying a device with hardware support for MTE,
such as a Google Pixel 8 (and later) or an iPhone 17 (or another Apple device with an A19 chip).</li>
<li><strong>If you are a mobile app developer, opt-in to MTE now!</strong></li>
</ul>
<p>Additionally, if you have more information about the unclear-to-me points mentioned in this post, please let me know!
In particular:</p>
<ol>
<li>For which parts does Android Advanced Protection enable MTE
(additionally to what is already enabled anyway)? The kernel? What else?</li>
<li>Do Advanced Protection mode and Lockdown mode force-enable MTE for user-installed apps?</li>
<li>What is the state of MTE on other Android phones? Are other OEMs considering it?</li>
<li>What is the state of MTE on Apple Silicon M-series chips? Is it coming?</li>
</ol>
<h2 id="further-reading">Further reading</h2>
<p>For a deeper technical dive into MTE, I recommend the following resources
(accessible at the time of writing, 2025-09-16):</p>
<ul>
<li>General:
<ul>
<li><a href="https://www.usenix.org/system/files/login/articles/login_summer19_03_serebryany.pdf">https://www.usenix.org/system/files/login/articles/login_summer19_03_serebryany.pdf</a></li>
<li><a href="https://www.youtube.com/watch?v=9wRT2hNwbkA">https://www.youtube.com/watch?v=9wRT2hNwbkA</a></li>
<li><a href="https://www.youtube.com/watch?v=KmFVPyHyfqQ">https://www.youtube.com/watch?v=KmFVPyHyfqQ</a></li>
</ul>
</li>
<li>Android:
<ul>
<li><a href="https://source.android.com/docs/security/test/memory-safety/arm-mte">https://source.android.com/docs/security/test/memory-safety/arm-mte</a></li>
<li><a href="https://developer.android.com/ndk/guides/arm-mte">https://developer.android.com/ndk/guides/arm-mte</a></li>
<li><a href="https://cs.android.com/android/platform/superproject/main/&#43;/main:bionic/docs/mte.md">https://cs.android.com/android/platform/superproject/main/+/main:bionic/docs/mte.md</a></li>
<li><a href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html">https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html</a></li>
</ul>
</li>
<li>iOS:
<ul>
<li><a href="https://security.apple.com/blog/memory-integrity-enforcement/">https://security.apple.com/blog/memory-integrity-enforcement/</a></li>
<li><a href="https://developer.apple.com/documentation/xcode/enabling-enhanced-security-for-your-app">https://developer.apple.com/documentation/xcode/enabling-enhanced-security-for-your-app</a></li>
</ul>
</li>
<li>Linux:
<ul>
<li><a href="https://www.kernel.org/doc/html/v6.12/arch/arm64/memory-tagging-extension.html">https://www.kernel.org/doc/html/v6.12/arch/arm64/memory-tagging-extension.html</a></li>
<li><a href="https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/mte/mte/">https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/mte/mte/</a></li>
</ul>
</li>
<li>Arm:
<ul>
<li><a href="https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Arm_Memory_Tagging_Extension_Whitepaper.pdf">https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Arm_Memory_Tagging_Extension_Whitepaper.pdf</a></li>
</ul>
</li>
</ul>
<h2 id="appendix-hardware-support">Appendix: hardware support</h2>
<p>In this section, I will try to briefly summarise my understanding of the hardware support for MTE.</p>
<h3 id="instruction-set-architecture-isa">Instruction set architecture (ISA)</h3>
<p>MTE was first introduced to the <a href="https://en.wikipedia.org/wiki/Instruction_set_architecture">instruction set architecture (ISA)</a>
in <a href="https://developer.arm.com/documentation/109697/2025_06/Feature-descriptions/The-Armv8-5-architecture-extension?lang=en#md450-the-armv85-architecture-extension__feat_FEAT_MTE">Armv8.5</a>.
In <a href="https://developer.arm.com/documentation/109697/2025_06/Feature-descriptions/The-Armv8-7-architecture-extension?lang=en#md452-the-armv87-architecture-extension__feat_FEAT_MTE3">Armv8.7</a>
and <a href="https://developer.arm.com/documentation/109697/2025_06/Feature-descriptions/The-Armv8-9-architecture-extension?lang=en#md454-the-armv89-architecture-extension__feat_FEAT_MTE4">Armv8.9</a>,
MTE was extended with additional features.
(Apple&rsquo;s MIE is based on FEAT_MTE4 in Armv8.9)
<a href="https://developer.arm.com/documentation/109697/2025_06/Feature-descriptions/The-Armv9-0-architecture-extension?lang=en">Armv9</a>
contains no changes to MTE.</p>
<p>Notably, MTE is <strong>optional</strong> in all of these ISA versions.
This means that chip vendors can produce a chip that is Armv9-compliant, but does not contain MTE!</p>
<h3 id="chips">Chips</h3>
<p>Arm&rsquo;s own Cortex CPU design <a href="https://newsroom.arm.com/blog/memory-safety-arm-memory-tagging-extension">has MTE</a>
starting from the first Armv9-compliant Cortex CPUs.</p>
<p>However, Arm does not actually produce these CPUs!
Instead, <a href="https://en.wikipedia.org/wiki/List_of_Arm_processors">other vendors</a> license the CPU design
and build their own <a href="https://en.wikipedia.org/wiki/System_on_a_chip">system-on-a-chip (SoC)</a> with it.
Prominent examples are Google Tensor, Qualcomm Snapdragon, Samsung Exynos, and Apple Silicon.
Some of these are based on Cortex (with varying degrees of modification)
while others (like Apple Silicon) are independent.</p>
<p>This breadth of different chips is why so far no Android phones except the Google Pixel have support for MTE.
<a href="https://grapheneos.social/@GrapheneOS/114721906692172623">According to GrapheneOS</a>,
some high-end Samsung Exynos and MediaTek chips have MTE support, and Qualcomm Snapdragon is planning it.
On the server side, Ampere <a href="https://amperecomputing.com/blogs/empowering-developers-and-fueling-ai-adoption-with-ampereone">has recently added</a>
MTE support.
See also <a href="https://gpages.juszkiewicz.com.pl/arm-socs-table/arm-socs.html">this overview table</a>
maintained by a RedHat engineer.</p>
<p>Therefore, the difference between what features the ISA describes and what the physical chip implements is important.</p>
<p>There is some confusion online about when MTE was &ldquo;introduced&rdquo;.
For example, the <a href="https://docs.kernel.org/arch/arm64/memory-tagging-extension.html">Linux kernel docs</a> say Armv8.5,
while the <a href="https://developer.android.com/ndk/guides/arm-mte">Android NDK docs</a> say Armv9.
This confusion comes from the ISA&ndash;chip mismatch.
Even though Armv8.5 defined MTE, there were no chips that supported it.
The first Cortex designs with MTE support happened to already support the Armv9 ISA.</p>
<p>The most reliable way to check if your chip supports MTE is to query it:</p>
<pre><code class="language-sh">adb shell grep mte /proc/cpuinfo
</code></pre>
<p>My Google Pixel 8a reports to support <code>mte mte3</code>.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>MTE is checked immediately in <code>sync</code> mode.
In <code>async</code> mode, it crashes on the next context switch to the kernel.
The <code>asymm</code> mode is a combination: <code>sync</code> for reads and <code>async</code> for writes.
On Android, the OS is <a href="https://source.android.com/docs/security/test/memory-safety/arm-mte#asymmetric-mode">usually configured</a>
to use <code>asymm</code> whenever <code>async</code> is requested.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>In the News</title><link>https://thore.io/posts/2025/06/in-the-news/</link><pubDate>Thu, 19 Jun 2025 07:00:00 +0200</pubDate><guid>https://thore.io/posts/2025/06/in-the-news/</guid><description>&lt;p>I&amp;rsquo;m in the newspaper!
&lt;a href="https://www.dorianzgraggen.com/">Dorian Zraggen&lt;/a> wrote an article about digital gatekeepers,
and I am one of the three people he interviewed:
me about &lt;a href="https://f-droid.org/">F-Droid&lt;/a>,
&lt;a href="https://carlschwan.eu/">Carl Schwan&lt;/a> about &lt;a href="https://kde.org/">KDE&lt;/a>,
and Hannah Ward about the &lt;a href="https://joinmastodon.org/">fediverse&lt;/a>.&lt;/p>
&lt;p>The article: &lt;a href="https://www.woz.ch/2525/digitale-oekonomie/die-gatekeeper-umgehen/!M44FC5J9CXJP">https://www.woz.ch/2525/digitale-oekonomie/die-gatekeeper-umgehen/!M44FC5J9CXJP&lt;/a>&lt;/p>
&lt;p>I have been using F-Droid for the past ~8 years.
Over time, I increasingly contributed to it: from small app metadata fixes, to website edits,
to a &lt;a href="https://gitlab.com/thgoebel/fdroid-metrics">tool visualizing app download statistics&lt;/a>
(see the &lt;a href="https://divested.dev/pages/fdroid_stats">graphs&lt;/a> assembled by Tavi).&lt;/p>
&lt;p>In the current &lt;a href="https://gitlab.com/fdroid/fdroidclient/-/blob/master/CHANGELOG.md#1230-2025-05-22">1.23 release&lt;/a>
of the F-Droid Android client, I rewrote the repository details screen in &lt;a href="https://developer.android.com/compose">Jetpack Compose&lt;/a>.
Not only does it look more modern and more integrated with the rest of the app (compare it to the app details screen),
but also mirror management has become a lot easier.
Previously, the mirror list was a fixed-height nested scroll view&amp;hellip;&lt;/p></description><content type="html"><![CDATA[<p>I&rsquo;m in the newspaper!
<a href="https://www.dorianzgraggen.com/">Dorian Zraggen</a> wrote an article about digital gatekeepers,
and I am one of the three people he interviewed:
me about <a href="https://f-droid.org/">F-Droid</a>,
<a href="https://carlschwan.eu/">Carl Schwan</a> about <a href="https://kde.org/">KDE</a>,
and Hannah Ward about the <a href="https://joinmastodon.org/">fediverse</a>.</p>
<p>The article: <a href="https://www.woz.ch/2525/digitale-oekonomie/die-gatekeeper-umgehen/!M44FC5J9CXJP">https://www.woz.ch/2525/digitale-oekonomie/die-gatekeeper-umgehen/!M44FC5J9CXJP</a></p>
<p>I have been using F-Droid for the past ~8 years.
Over time, I increasingly contributed to it: from small app metadata fixes, to website edits,
to a <a href="https://gitlab.com/thgoebel/fdroid-metrics">tool visualizing app download statistics</a>
(see the <a href="https://divested.dev/pages/fdroid_stats">graphs</a> assembled by Tavi).</p>
<p>In the current <a href="https://gitlab.com/fdroid/fdroidclient/-/blob/master/CHANGELOG.md#1230-2025-05-22">1.23 release</a>
of the F-Droid Android client, I rewrote the repository details screen in <a href="https://developer.android.com/compose">Jetpack Compose</a>.
Not only does it look more modern and more integrated with the rest of the app (compare it to the app details screen),
but also mirror management has become a lot easier.
Previously, the mirror list was a fixed-height nested scroll view&hellip;</p>
<p>And as it happens, if you get the WOZ app from F-Droid you will use my new repository details screen!
Since the WOZ app is not in the <a href="https://search.f-droid.org/">main repo</a> but in a <a href="https://fdroid.woz.ch/">custom repo</a>.</p>
<h2 id="repository-details-before-and-after">Repository details before and after</h2>
<p>Before:</p>


<img src="/img/in-the-news/old.png"   width="350"  class="center" />

<p>After (collapsed):</p>


<img src="/img/in-the-news/new-short.png"   width="350"  class="center" />

<p>After (expanded):</p>


<img src="/img/in-the-news/new.png"   width="350"  class="center" />

]]></content></item><item><title>Fiber Home Internet Prices</title><link>https://thore.io/posts/2025/05/fiber-home-internet-prices/</link><pubDate>Fri, 09 May 2025 17:00:00 +0200</pubDate><guid>https://thore.io/posts/2025/05/fiber-home-internet-prices/</guid><description>&lt;p>I plotted the development of fiber home internet prices in Switzerland:&lt;/p>
&lt;img src="https://thore.io/img/internet-prices.png" class="center" />
&lt;p>You can find an interactive version &lt;a href="https://thore.io/img/internet-prices.html">here&lt;/a>.&lt;/p>
&lt;p>The source code is available &lt;a href="https://github.com/thgoebel/internet-prices">on Github&lt;/a>.&lt;/p>
&lt;p>For each speed, only the &lt;em>lowest known base price&lt;/em> (at that point in time) is included.
Reductions from the base price are not considered (temporary promotions, combining home internet with a mobile subscription, &amp;hellip;).
There are too many possible combinations, they change too often,
and they are too intransparent to track without a lot of effort.&lt;/p></description><content type="html"><![CDATA[<p>I plotted the development of fiber home internet prices in Switzerland:</p>


<img src="/img/internet-prices.png"   class="center" />

<p>You can find an interactive version <a href="/img/internet-prices.html">here</a>.</p>
<p>The source code is available <a href="https://github.com/thgoebel/internet-prices">on Github</a>.</p>
<p>For each speed, only the <em>lowest known base price</em> (at that point in time) is included.
Reductions from the base price are not considered (temporary promotions, combining home internet with a mobile subscription, &hellip;).
There are too many possible combinations, they change too often,
and they are too intransparent to track without a lot of effort.</p>
<p>Note that price is only one factor when choosing your internet.
E.g., you may want to consider:
the physical architecture (P2P/AON vs. P2MP/PON),
the backhaul capacity of the POP you are connected to,
the connectivity of the ISP towards other ASes (good peering and internet exchange capacity),
or the quality of customer support.</p>
<p>Please let me know if there is any base price data that I missed!</p>
<h2 id="paying-for-the-physical-fiber">Paying for the physical fiber</h2>
<p>ISPs don&rsquo;t build their own fiber to each house.
That would be insanely expensive and simply redundant.
It would also require a huge amount of capital for a new ISP to enter the market.
<em>Fiber should be a public utility, just like water and electricity.</em>
Politicians and the resulting regulations don&rsquo;t always see it that way, though&hellip;</p>
<p>ISPs rent fiber access from Swisscom.
Swisscom (through their subsidiary <a href="https://www.cablex.ch">Cablex</a>) builds and operates the fiber,
often in cooperation with the local municipial utility company (Stadtwerke),
e.g. see <a href="https://www.ewz.ch/de/private/glasfaser/anschluss/liegenschaft-anschliessen.html">Zürich</a>.
They do this until the building entrypoint.
The cabling inside the building is also done by local electricians.</p>
<p>Swisscom&rsquo;s product for renting fiber access is called
<a href="https://web.archive.org/web/20250512065853/https://www.swisscom.ch/de/business/wholesale/angebot/anschluesse/access-line-optical.html">Access Line Optical (ALO)</a>.
The <a href="https://web.archive.org/web/20240814115723/https://www.swisscom.ch/content/dam/swisscom/de/ws/documents/D_ALO-Dokumente/d_-alo_handbuch-preisev2-6--gueltig-ab-01-02-2024-.pdf.dl.res/d_-alo_handbuch-preisev2-6--gueltig-ab-01-02-2024-.pdf">prices for ALO</a>
are the following:</p>
<ul>
<li>24 Fr. per month recurring fee</li>
<li>107 Fr. one-time fee for setting up a new connection</li>
</ul>
<p>For a new connection, a Swisscom (!) employee has to physically go to the switchboard building in your town
or neighbourhood and plug the fiber coming from your home into the equipment of your ISP.</p>
<p>So even if your ISP is not Swisscom, 24 Fr. of what you pay every month still goes to Swisscom for operating <a href="https://en.wikipedia.org/wiki/OSI_model">Layer 1</a>.</p>
<h2 id="cost-of-running-a-pop-as-an-isp">Cost of running a PoP as an ISP</h2>
<p>init7 has a <a href="https://blog.init7.net/de/rentabilitatsrechnung/">blog post</a> where they break down
what it costs them as an ISP to build and operate the equipment for a point-of-presence (PoP).</p>
]]></content></item><item><title>Open Source your Docs</title><link>https://thore.io/posts/2025/05/open-source-your-docs/</link><pubDate>Wed, 07 May 2025 15:00:00 +0200</pubDate><guid>https://thore.io/posts/2025/05/open-source-your-docs/</guid><description>&lt;p>If you have publicly available documentation for your product, open source it!&lt;/p>
&lt;p>Even if all of your other software is proprietary, your documentation is a great candidate to be open sourced.
For several reasons:&lt;/p>
&lt;h3 id="1-everything-is-already-public">1. Everything is already public&lt;/h3>
&lt;p>Most docs today are some flavour of Markdown that is compiled with a static site generator to a static website.
Unless you wrote &lt;a href="https://fasterthanli.me/articles/open-sourcing-the-home-cms">a custom static site generator&lt;/a>,
there is nothing novel about your docs site.
The content is public, and the site generator is probably FOSS anyway, so the git repository can be public, too.&lt;/p></description><content type="html"><![CDATA[<p>If you have publicly available documentation for your product, open source it!</p>
<p>Even if all of your other software is proprietary, your documentation is a great candidate to be open sourced.
For several reasons:</p>
<h3 id="1-everything-is-already-public">1. Everything is already public</h3>
<p>Most docs today are some flavour of Markdown that is compiled with a static site generator to a static website.
Unless you wrote <a href="https://fasterthanli.me/articles/open-sourcing-the-home-cms">a custom static site generator</a>,
there is nothing novel about your docs site.
The content is public, and the site generator is probably FOSS anyway, so the git repository can be public, too.</p>
<h3 id="2-docs-are-easy-to-contribute-to">2. Docs are easy to contribute to</h3>
<p><em>Fixing a software bug</em> requires writing code.
Contributors need to set up a build environment, which is often time-consuming.
Personally, I mostly contribute bug fixes to Android projects, because I already have the Android toolchain installed on my laptop.
For other software (iOS, desktop, NodeJS, Ruby, etc.) I only open issues.</p>
<p>By contrast, <em>fixing a typo in the docs</em> requires editing a Markdown file.
All I need is GitHub/GitLab.
I can do everything via the web GUI: fork your repo, create a branch, edit the file, create a pull request.
I can even preview the rendered Markdown directly in GitHub/GitLab.</p>
<p>This makes documentation a natural candidate for getting started in open source.
For new contributors, but also for your company (if it is new to doing open source).</p>
<h3 id="3-the-git-based-workflow-is-more-time-efficient-for-you-and-me">3. The git-based workflow is more time-efficient (for you and me)</h3>
<p>Documentation fixes are often small,
from a simple typo to a few lines of text.</p>
<p><em>For me</em>, it takes roughly the same amount of time to &ldquo;fork, edit, make PR&rdquo;
as it takes me to &ldquo;write e-mail to support, explain to them where in the text the issue is,
what the correct text should be, and convince them that
&rsquo;no, I don&rsquo;t actually have a question, I just want to report an issue&rsquo;.&rdquo;
Both approaches take the same amount of time, but git is much less stressful for me.
It is more precise, less verbose, and less back-and-forth.</p>
<p><em>For your team</em>, git saves A LOT of time.
Reviewing my PR with a few lines of English text in Markdown is trivial.
Review, press merge, your CI deploys. 5 minutes of effort.
On the other hand, consider this: having your support staff answer my e-mail,
forwarding the information to your technical writing team, creating a ticket,
having them do the work of making the edits, committing them, creating a PR,
moving the ticket to done.
That is a lot more work. Work that you can <del>outsource to me</del> save by simply open sourcing your docs.</p>
<h2 id="when-not-to-open-source-docs">When not to open source docs</h2>
<p>There are some situations where you may not want to open source your docs, at least not directly:</p>
<h3 id="a-keeping-unpublished-drafts-private">a. Keeping unpublished drafts private</h3>
<p>This blog is currently not open source.
This is because I often write posts to get them out of my brain, but later decide not to publish them.
I like keeping them around and tracked in git for my own reference, but I don&rsquo;t want the world to read my half-finished thoughts.</p>
<p>In technical writing, too, you can encounter the need to keep documentation private:
e.g., while preparing documentation for an upcoming, not-yet-announced feature.</p>
<p>And in software development this also happens:
e.g., the fixing of <a href="https://www.redhat.com/en/blog/security-embargoes-red-hat">embargoed security issues</a>
often happens on a private fork.</p>
<p>Your choice depends on how often you find yourself in such situations:
are they one-off or regular?
Therefore, do you keep all docs closed, or do you set up a private repo when the need arises?</p>
<h2 id="conclusion">Conclusion</h2>
<p>Note that open source != FOSS.
You can publish your docs under whatever license you like,
and optionally have contributors sign a <a href="https://en.wikipedia.org/wiki/Contributor_License_Agreement">CLA</a>.</p>
<p>Additionally, you can keep your existing processes of getting feedback from non-git-savy customers
via your support portal and your feedback forms, and manually feed that back into your docs.
Handling PRs just complements these methods.</p>
<p>As a developer/sysadmin/engineer/etc, I use publicly available docs every day.
Whenever I stumble over an issue, I like to see it fixed, so that the next person doesn&rsquo;t have to suffer the same confusion.
I have made PRs with doc fixes to projects as big as <a href="https://gitlab.com/gitlab-org/gitlab/-/merge_requests/190415">GitLab</a>
and <a href="https://github.com/flutter/engine/pull/21208">Google&rsquo;s Flutter</a>,
but also smaller to ones like <a href="https://github.com/opnsense/docs/commits?author=thgoebel">OPNsense</a>.
This would not have been as smooth and pleasant for both me and their product/dev teams had the docs not been open source.</p>
<p>So please make it easy for drive-by contributors to fix your docs &ndash; open source them!</p>
]]></content></item><item><title>Why ‘john.doe+shopping’ Shouldn’t Break Your App (But Does)</title><link>https://thore.io/posts/2025/04/why-john.doe-shopping-shouldnt-break-your-app-but-does/</link><pubDate>Sat, 19 Apr 2025 10:30:00 +0200</pubDate><guid>https://thore.io/posts/2025/04/why-john.doe-shopping-shouldnt-break-your-app-but-does/</guid><description>&lt;p>A rant about internet standards, e-mail, plus-aliases, and why reading the RFCs matters.&lt;/p>
&lt;h2 id="the-internet-is-a-mess">The Internet is a mess&lt;/h2>
&lt;p>E-Mail is a mess.
It has been around since the 80s and has been implemented hundreds, if not thousands, of times
by different people, in different ways, with different levels of compatibility.&lt;/p>
&lt;p>But: everything in the internet that has to be interoperable and that is older than 1 year is a mess.
As humans, we never get a design right on the first try.
People want new features. Security issues are found.
So a new scheme is designed.
But because not everyone will upgrade to the new scheme (because of cost, unawareness, loss of skilled staff, or just not caring),
the updated scheme has to be backwards compatible with the old scheme.
And what is worse, many did not even implement the old scheme correctly.&lt;/p></description><content type="html"><![CDATA[<p>A rant about internet standards, e-mail, plus-aliases, and why reading the RFCs matters.</p>
<h2 id="the-internet-is-a-mess">The Internet is a mess</h2>
<p>E-Mail is a mess.
It has been around since the 80s and has been implemented hundreds, if not thousands, of times
by different people, in different ways, with different levels of compatibility.</p>
<p>But: everything in the internet that has to be interoperable and that is older than 1 year is a mess.
As humans, we never get a design right on the first try.
People want new features. Security issues are found.
So a new scheme is designed.
But because not everyone will upgrade to the new scheme (because of cost, unawareness, loss of skilled staff, or just not caring),
the updated scheme has to be backwards compatible with the old scheme.
And what is worse, many did not even implement the old scheme correctly.</p>
<p>Thus over time, as new requirements come in, the whole thing inevitably evolves into a huge pile of patches.</p>
<p>E-Mail is not alone here, you can find this pattern in most, if not all, (internet) protocols.
Just look at <em>the</em> Internet Protocol (IP) and <a href="https://en.wikipedia.org/wiki/Network_address_translation">NAT</a>:
even 25+ years later, many big organisations are still not migrating to IPv6 &ndash; not successfully, or not at all.
(I have studied and worked at such organisations. In 2025, there are still IPv4-only mobile carriers in Switzerland.)
So instead of IPv6, we got NAT. And because of NAT, we got STUN, TURN, and ICE.
(To learn more about NAT, I highly recommend Eric Rescorla&rsquo;s <a href="https://educatedguesswork.org/posts/nat-part-1">four-part series</a>.)</p>
<p>In fact, we are moving towards a new <a href="https://book.systemsapproach.org/e2e/trend.html">narrow waist</a> of the OSI model.</p>
<p>NAT is an example where it was made to work:
<a href="https://en.wikipedia.org/wiki/Webrtc">WebRTC</a> works, your Jitsi/Zoom/Teams/Signal/WhatsApp calls work.
Even though under the hood, there is a pile of protocol patches trying to find a way through
your home network&rsquo;s NAT sitting behind a CGNAT, because your ISP could not be bothered.</p>
<p>It is easy to say &ldquo;let&rsquo;s abandon e-mail and build something better and more modern&rdquo;.
If your new thing <a href="https://signal.org/blog/the-ecosystem-is-moving/">is centralised</a>: great, that will work for you.
But if your goal is to build something that is interoperable (&ldquo;federated&rdquo;) across different entities,
then your system will, over time, evolve into a similar mess as all the other protocols before.</p>
<h2 id="plus-aliases">Plus-aliases</h2>
<p>Back to e-mail: one of my pet peeves is the so-called &ldquo;plus-alias&rdquo;.</p>
<p>If my main email address is &ldquo;<a href="mailto:john.doe@example.com">john.doe@example.com</a>&rdquo;, then &ldquo;<a href="mailto:john.doe&#43;shopping@example.com">john.doe+shopping@example.com</a>&rdquo;
and &ldquo;<a href="mailto:john.doe&#43;banking@example.com">john.doe+banking@example.com</a>&rdquo; are two plus-aliases.
You can suffix your username (the local-part) with &ldquo;+&rdquo; and some label.
These new emails will be delivered to your normal inbox.</p>
<p>This is NOT supported by all email providers.
<a href="https://gmail.googleblog.com/2008/03/2-hidden-ways-to-get-more-from-your.html">GMail</a>
and <a href="https://proton.me/support/creating-aliases#&#43;Aliases">Proton Mail</a> support this,
but your university or work email might not.</p>
<p>This is where internet standards<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> come in:</p>
<ol>
<li>The &ldquo;+&rdquo; character is allowed in the local-part.
In fact, like it or not, all of these characters are allowed in the local-part:</li>
</ol>
<pre><code>! # $ % &amp; ' * + - / = ? ^ _ ` { | } ~
</code></pre>
<p>So as far as the IETF standards are concerned, <code>john!#$doe%&amp;'=?{shopping+bank}@example.com</code> is a valid e-mail address.</p>
<ol start="2">
<li>The local-part is locally interpreted.
&ldquo;[&hellip;] it is simply interpreted on the particular host as a name of a particular mailbox&rdquo;
(<a href="https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1">RFC 5322</a>).
So if GMail decides to interpret the &ldquo;+&rdquo; as an alias, and another mailserver interprets
it as separate mailboxes, this is completely up to them.
It is NOT up to the sender to make any decision about this.</li>
</ol>
<p>All of this is defined in <a href="https://datatracker.ietf.org/doc/html/rfc5322#section-3.4">RFC 5322</a>,
which defines the format of Internet Messages.
It superceded RFC 2822, which in turn superceded the original
<a href="https://datatracker.ietf.org/doc/html/rfc822">RFC 822</a>, written for the ARPANET in 1982.</p>
<h2 id="people-ignore-standards">People ignore standards</h2>
<p>Unfortunately &ndash; and this part is my pet peeve &ndash; there is a lot of software that thinks that &ldquo;+&rdquo;
is not a valid character in the local-part.</p>
<p>I have seen this fail in so many wonderful ways:</p>
<ul>
<li>In the best case, the input form (wrongly) claims &ldquo;this is not a valid e-mail&rdquo;.</li>
<li>Some sites will let me <em>register</em> an account with a plus-alias e-mail, but then won&rsquo;t let me <em>log in</em> with it.</li>
<li>Some sites silently strip the &ldquo;+&rdquo; (&ldquo;<a href="mailto:john.doeshopping@example.com">john.doeshopping@example.com</a>&rdquo;).
This is obviously a different address, so the mailhost will interpret it differently.
I had to register a new e-mail account once in order to regain access to my
domain registrar after their internal migration stripped my &ldquo;+&rdquo;.</li>
<li>Putting the email address in an URL, but <a href="https://www.linkedin.com/posts/activity-7168581979888693249-nBoZ">not URL-encoding the address</a>,
(<code>+</code> would need to be encoded as <code>%2B</code>).
This often happens in links such as &ldquo;click here to confirm your e-mail address for this account&rdquo;.
And it breaks those links.</li>
</ul>
<p>Companies have lost business over not supporting plus-aliases.
I have turned to alternatives or have lost interest completely when a site didn&rsquo;t let me register with a plus-alias.</p>
<h2 id="why-bother">Why bother?</h2>
<p>The easy way would be to just stop using plus-aliasses.
However, while it is annoying to recover from these bugs,
<em>I find it a very useful first indicator of how well (or badly) written the software is.</em></p>
<p>When they implemented e-mail handling, the people writing those softwares:</p>
<ul>
<li>Either never read the standards about e-mail.
After all, &ldquo;+&rdquo; has been an allowed character ever since e-mail was designed <strong>in 1982</strong>.</li>
<li>Are not e-mail power users, otherwise they would have been aware that <a href="https://gmail.googleblog.com/2008/03/2-hidden-ways-to-get-more-from-your.html">GMail supports plus-aliases</a> since at least 2008, i.e., <strong>17 years ago</strong>.</li>
<li>Or they knew, but had some technical reason or constraint to deny &ldquo;+&rdquo; anyway.</li>
</ul>
<p>While I see some reason to ignore some characters (like <code>/ ` { | }</code>), plus is not one of them.
Plus-aliases are widely used:</p>
<ul>
<li>By &ldquo;power users&rdquo; &ndash; GMail has supported them for 17 years.</li>
<li>By mailing list software. Look for headers like <code>List-Unsubscribe: &lt;mailto:listname+unsubscribe@example.org&gt;</code></li>
<li>By ticketing software. Look for headers like <code>Reply-To: Acme Corp &lt;support+id123456@acmecorp.zendesk.com&gt;</code></li>
</ul>
<p>So your software, too, ought to allow &ldquo;+&rdquo; in e-mail addresses.
If only for compatibility with, you know, GMail.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Interoperable things, like e-mail, will grow to a bunch of patches over time.
You can contribute to ameliorate the situation by <em>reading the existing standards</em> and actually implementing them.
If you do that, you will make your customers happier.
If everyone did that, it would make the work of
<a href="https://datatracker.ietf.org/doc/html/draft-ietf-lamps-header-protection-25#name-acknowledgments">the people</a>
who have to put patches on top of the existing pile a tiny bit easier.
Thank you!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I am deliberately glossing over the differences made by the IETF between
Draft Standard, Proposed Standard, Internet Standard in this post.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Getting the Download Count of Github Release Assets</title><link>https://thore.io/posts/2025/04/getting-the-download-count-of-github-release-assets/</link><pubDate>Fri, 11 Apr 2025 20:00:00 +0200</pubDate><guid>https://thore.io/posts/2025/04/getting-the-download-count-of-github-release-assets/</guid><description>&lt;p>In git, it is customary to tag software releases with &lt;code>git tag&lt;/code>.
Git repository hosting platforms such as GitHub and GitLab have a &amp;ldquo;Releases&amp;rdquo; section.
Not every git tag must be a &amp;ldquo;release&amp;rdquo;, but a release must be assigned a git tag.
Project maintainers can then add additional information to the release, such as a changelog and release assets.
This gives maintainers a platform to attach more information to a git tag, which in itself is just a pointer to a certain git commit.&lt;/p></description><content type="html"><![CDATA[<p>In git, it is customary to tag software releases with <code>git tag</code>.
Git repository hosting platforms such as GitHub and GitLab have a &ldquo;Releases&rdquo; section.
Not every git tag must be a &ldquo;release&rdquo;, but a release must be assigned a git tag.
Project maintainers can then add additional information to the release, such as a changelog and release assets.
This gives maintainers a platform to attach more information to a git tag, which in itself is just a pointer to a certain git commit.</p>
<p>Often, maintainers upload precompiled assets for each release.
Depending on the project, this can be *.msi, *.deb, *.rpm, or *.apk files.
Sometimes maintainers also upload *.sha256 or even *.gpg files to accompany these assets.
In addition, GitHub automatically adds both a *.zip and a *.tar.gz archive of the source code at the corresponding git tag to each releases&rsquo; assets.</p>
<p>Today, I am interested in getting the <em>download count</em> of these release assets.
GitHub does not show this in the UI, but they do expose it
<a href="https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#get-a-release-by-tag-name">in their API</a>:</p>
<pre><code class="language-bash">curl -L \
  -H &quot;Accept: application/vnd.github+json&quot; \
  -H &quot;X-GitHub-Api-Version: 2022-11-28&quot; \
  https://api.github.com/repos/OWNER/REPO/releases/tags/TAG
</code></pre>
<p>This way, we can e.g. learn that at the time of writing, ~4100 people have downloaded
the *.apk for <a href="https://github.com/signalapp/Signal-Android/releases/tag/v7.40.0">Signal&rsquo;s Android app v7.40.0</a>.</p>
<p>Of course, not all of these downloads will be real people (and the data is easy to maliciously increase, if that&rsquo;s what you want to do).
But mostly, the order of magnitude is correct.</p>
<p>If you have too much time, you can pipe this data into <code>jq</code> for further processing,
build a pretty web page with graphs around it, and whatever else you may do with this data.
For my curiousity &ndash; which is getting a quick insight into the scale of things &ndash; a <code>| grep download_count</code> also does the job.</p>
<p>And if you don&rsquo;t have <code>curl</code> handy (don&rsquo;t you have a
<a href="https://www.androidauthority.com/android-16-linux-terminal-doom-3521804/">Linux VM on your phone</a>?),
you can get the same data via a shields.io badge, directly from your browser:
<a href="https://img.shields.io/github/downloads/signalapp/signal-android/v7.40.0/total">https://img.shields.io/github/downloads/signalapp/signal-android/v7.40.0/total</a></p>
]]></content></item><item><title>Yet another 25G home router build</title><link>https://thore.io/posts/2024/02/yet-another-25g-home-router-build/</link><pubDate>Sat, 03 Feb 2024 20:00:00 +0100</pubDate><guid>https://thore.io/posts/2024/02/yet-another-25g-home-router-build/</guid><description>&lt;p>I recently moved out of my shared student flat &amp;ndash; where internet was centrally provided &amp;ndash; and into my own flat.
Finally I get to choose my internet setup!
The obvious choice is init7&amp;rsquo;s &lt;a href="https://www.init7.net/en/internet/fiber7/">Fiber7&lt;/a> offering:
unthrottled, symmetric, open peering, a static /48 IPv6, peer-to-peer (no &lt;a href="https://en.wikipedia.org/wiki/Passive_optical_network">PON&lt;/a>), no fuss.
An internet speed limited only by hardware, not by economics trying to carve out
pricing levels for every pocket (100 Mbit/s on fiber, seriously?).&lt;/p></description><content type="html"><![CDATA[<p>I recently moved out of my shared student flat &ndash; where internet was centrally provided &ndash; and into my own flat.
Finally I get to choose my internet setup!
The obvious choice is init7&rsquo;s <a href="https://www.init7.net/en/internet/fiber7/">Fiber7</a> offering:
unthrottled, symmetric, open peering, a static /48 IPv6, peer-to-peer (no <a href="https://en.wikipedia.org/wiki/Passive_optical_network">PON</a>), no fuss.
An internet speed limited only by hardware, not by economics trying to carve out
pricing levels for every pocket (100 Mbit/s on fiber, seriously?).</p>
<p><code>&lt;rant&gt;</code></p>
<p>Fiber7 costs 65 CHF/month, which is a medium market price in Switzerland.
10G and 25G have the same monthly price, only the setup fee differs, because the hardware cost differs.
65 CHF is not too expensive (there are more expensive offerings),
but also not the cheapest (there are cheaper offerings, but at worse service quality).</p>
<p>Especially when you look beyond the Swiss border and into Germany,
and you see Deutsche Telekom offering
<a href="https://web.archive.org/web/20240202184113/https://www.telekom.com/de/medien/medieninformationen/detail/magentazuhause-2000-1055094">Magenta 2000</a>:
2G down, 1G up for 140 €/month.
Twice the price for 1/10th of the speed.</p>
<p>What is more, this speed smells a lot like
<a href="https://ripe84.ripe.net/wp-content/uploads/presentations/73-RIPE84_20220518_25G_OneYear.pdf#page=10">GPON</a>.
But on <a href="https://web.archive.org/web/20240202184113/https://www.telekom.com/de/medien/medieninformationen/detail/magentazuhause-2000-1055094">the announcement</a>
Telekom says that they have XGSPON equipment on their end and that you need a XGSPON-capable router.
But XGSPON can carry symmetric 10G!
So is Telekom throttling XGSPON to GPON? Maybe.
Ein Schelm, wer Böses denkt.
Telekom is clearly leaving itself room to give customers an artifical
speed upgrade in the future (or even to sell the upgrade at a premium).</p>
<p><code>&lt;/rant&gt;</code></p>
<p>All of this is to say: I am very happy init7 exists and provides this great service.
Now I just need to get a router.</p>
<p>A number of other people have also written about their home router builds for their init7 connection:</p>
<ul>
<li><a href="https://michael.stapelberg.ch/posts/tags/fiber/">Michael Stapelberg</a></li>
<li><a href="https://medium.com/@sdier/new-internet-service-calls-for-a-new-router-4dbebbdc6dbd">Scott Dier</a></li>
<li><a href="https://q.vtable.org/25gbps-internet-speedtest-net-server/">James Kavakopoulos</a></li>
</ul>
<p>Check them out! I got inspired by their blog posts, too.
This post is just yet another home router build.</p>
<p>A small note on hardware before we start:
There are two form factors for network cables. RJ45 (the classic) and SFP (and its variants).
At 10G, people tend to use both SFP+ (data center) and RJ45 (home lab) connectors.
At 25G, however, SFP28 is the go-to option (but Cat8 <a href="https://community.fs.com/article/cat8-cable-for-25gbase-t-and-40gbase-t.html">would work</a>, too).
Wikipedia has a full <a href="https://en.wikipedia.org/wiki/Small_Form-factor_Pluggable#SFP_types">table</a>
showing all the different SFP types.
Here is an extract:</p>
<table>
  <thead>
      <tr>
          <th>Port</th>
          <th>Speed</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>SFP</td>
          <td>1G</td>
      </tr>
      <tr>
          <td>SFP+</td>
          <td>10G</td>
      </tr>
      <tr>
          <td>SFP28</td>
          <td>25G</td>
      </tr>
  </tbody>
</table>
<h2 id="initial-reconnaissance">Initial reconnaissance</h2>
<p>My original plan was to simply go for 10G and buy an off-the-shelf appliance as a router:
the <a href="https://shop.opnsense.com/product/dec740-opnsense-desktop-security-appliance/">DEC740</a>
from Deciso, the makers of OPNsense, the router and firewall I wanted to use.
It is fanless, quiet, and has a low power consumption of ~15W, and costs 750 €.
The simple router boxes other ISPs give their customers are also in the 10-15W range.</p>
<p>But I needed to buy a network card anyway to connect my existing NAS to the router.
So I started shopping. Initially, I was searching for 10G cards.
Most 10G cards cost around 200&ndash;250 CHF.
SFP28 cards tend to cost 300&ndash;350 CHF.
(As of December 2023, YMMV.)</p>
<p>Eventually, I came across the Mellanox ConnectX-4 Lx on Digitec:</p>


<img src="/img/router-build/nic-1.png"   class="center" />

<p>Or rather, I took this screenshot too late.
I actually came across it a few days earlier when it was available not for 145 CHF but for 115 CHF!
(This likely was some temporary deal from supplier jacob.de.)</p>


<img src="/img/router-build/nic-2.png"   class="center" />

<p>The Mellanox ConnectX-4 Lx has two SFP28 ports, not SFP+ ports.
I was hooked. If this 25G card is cheaper than the 10G cards (115 &lt; 200), then let&rsquo;s buy this one!
And if my NAS has a 25G networking card, it would be a shame if my router only had 10G, right?
Sure, SFP28 is backwards compatible with SFP+, but still.</p>
<p>Thus, I gave up on my &ldquo;buy an off-the-shelf appliance and be done with it&rdquo; plans
and started researching a custom router build.
Spoiler: at the end, it was way more expensive than the DEC740.
But I learnt a lot about the hardware, and it was enormous fun doing the <del>shopping</del> research for parts and finally the assembly!</p>
<h2 id="settling-on-a-nuc">Settling on a NUC</h2>
<p>My first idea was to build a tower-sized computer.
<a href="https://michael.stapelberg.ch/posts/2021-07-10-linux-25gbit-internet-router-pc-build/#cpu-and-chipset">Michael Stapelberg&rsquo;s blog post</a>
drew my attention to the AMD Ryzen 7 Pro 5750GE, with only 35W TDP!
Unfortunately, it was out-of-stock wherever I looked.</p>
<p>Later, <a href="https://medium.com/@sdier/new-internet-service-calls-for-a-new-router-4dbebbdc6dbd">Scott Diers&rsquo;s build</a>
with the Intel NUC 9 Pro inspired me to take a look at NUCs instead of a full tower.
I liked the smaller form factor.
Before reading Scott&rsquo;s post, I simply wasn&rsquo;t aware that there exist NUCs that have PCIe slots
(and you need a PCIe slot for the network card).</p>
<blockquote>
<p>The reason that these NUCs have a PCIe slot is that they are designed for gamers.
We can (ab)use that: instead of putting in a graphics card, we can put in a networking card!</p>
</blockquote>
<p>Sadly, the &ldquo;Pro&rdquo; series that Scott used does not come with a PCIe slot anymore (for the 11, 12, 13 versions).
Therefore, I had to go for the more expensive &ldquo;Extreme&rdquo; series.
The Pros cost around 500 CHF while the Extremes cost around 1000 CHF&hellip;</p>
<p>So let&rsquo;s compare the two most relevant NUC Extremes.
The i9 variant of the
<a href="https://web.archive.org/web/20240202190149/https://download.intel.com/newsroom/2022/client-computing/intel-nuc-12-extreme-dcm-i9i7-kit-product-brief.pdf">NUC 12 Extreme</a>
and the
<a href="https://web.archive.org/web/20240202190157/https://download.intel.com/newsroom/2022/client-computing/newsroom-nuc-13-extreme-tech-specs.pdf">NUC 13 Extreme</a>
compare as follows (an i7 variant also exists):</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>NUC 12 Extreme</th>
          <th>NUC 13 Extreme</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Launch</td>
          <td><a href="https://www.intel.com/content/www/us/en/newsroom/news/12th-gen-nuc.html">February 2022</a></td>
          <td><a href="https://www.intel.com/content/www/us/en/newsroom/news/intel-nuc-13-extreme-new-standard-mini-pc-gaming-performance.html">November 2022</a></td>
      </tr>
      <tr>
          <td>CPU</td>
          <td>12th Gen i9-12900</td>
          <td>13th Gen  i9-13900K</td>
      </tr>
      <tr>
          <td>Core count</td>
          <td>16 cores (8P+8E), 24 threads</td>
          <td>24 cores (8P+16E), 32 threads</td>
      </tr>
      <tr>
          <td>TDP</td>
          <td>65 W</td>
          <td>125 W</td>
      </tr>
  </tbody>
</table>
<p>In all other regards (that are relevant to me) they are similar:
1 PCIe x16 Gen5 slot, 2 Thunderbolt 4 ports, lots of USB-A ports, up to 64 GB RAM (though 12 is DDR4, 13 is DDR5),
3 M.2 slots, two RJ45 ports (2.5 Gbit/s and 10 Gbit/s).</p>
<p>The only difference between the i9 variant and the i7 variant (other than the CPU)
is the 10 Gbit/s port, which is only present on the i9 variant.
I chose the i9 variant because I wanted the additional RJ45 port.</p>
<p>In the end, I chose the NUC 12 Extreme simply because the NUC 13 Extreme was not available
in a reasonable timeframe from any online store.
Note that the TDP is lower, but the TDP doesn&rsquo;t say much about the idle power consumption.</p>
<p>Having a 16-core home router is a waste.
Let&rsquo;s use it for other computing tasks as well!
I decided to not build a router anymore, but instead build a server that happens to be a router.
In practice, this means that the bare metal is running Proxmox as a hypervisor,
and one of the VMs is running OPNsense as the router and firewall.</p>
<p>In total the server will feature: 16 cores, 64 GB RAM, 8 TB SSDs (but as RAID-1, so only 4 TB usable).
A compute-heavy complement to my existing storage-heavy NAS (which I built a few years ago).</p>
<p>(Granted, it is still a desktop CPU not a server CPU.
It has &ldquo;only&rdquo; 8 performance cores, the other 8 are energy-efficient cores.
An Intel Xeon or AMD Epyc CPU is a very different beast.)</p>
<h2 id="the-final-build">The final build</h2>
<p>Fast forward, I ended up with the following parts for the <del>router</del> server:</p>
<table>
  <thead>
      <tr>
          <th>Part</th>
          <th>Prize</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Intel NUC 12 Extreme Kit</td>
          <td>963 CHF</td>
      </tr>
      <tr>
          <td>2x Samsung 990 Pro SSD 4TB</td>
          <td>2x (265 € ~ 250 CHF)</td>
      </tr>
      <tr>
          <td>Corsair Vengeance RAM 2x 32 GB</td>
          <td>117 CHF</td>
      </tr>
      <tr>
          <td>Mellanox ConnectX-4 Lx</td>
          <td>115 CHF</td>
      </tr>
      <tr>
          <td>Σ</td>
          <td>1695 CHF</td>
      </tr>
  </tbody>
</table>
<p>To connect the router to the optical termination outlet (OTO) of my flat,
and to upgrade my NAS to 25G and connect it to the router,
I also bought the following parts:</p>
<table>
  <thead>
      <tr>
          <th>Part</th>
          <th>Prize</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>LC UPC to LC APC, simplex, single mode, 2m patch cable</td>
          <td>3.30 € ~ 3 CHF</td>
      </tr>
      <tr>
          <td>SFP28 optical transceiver</td>
          <td>106 € ~ 99 CHF</td>
      </tr>
      <tr>
          <td>SFP28 DAC Cable, 2m</td>
          <td>37 € ~ 35 CHF</td>
      </tr>
      <tr>
          <td>Mellanox ConnectX-4 Lx</td>
          <td>115 CHF</td>
      </tr>
      <tr>
          <td>Σ</td>
          <td>252 CHF</td>
      </tr>
  </tbody>
</table>
<p>I bought all of the above parts on digitec.ch, amazon.de, and fs.com.</p>
<p>You can also get the fiber patch cable and the transceiver directly from init7,
for 77 CHF (10G) or for 222 CHF (25G) (because SFP28 transceivers are most expensive).
With a referral code, you get 111 CHF off the hardware.</p>
<p>If you (like me) buy the parts yourself, you need to do your research to make sure you buy the right cable and transceiver.
The wall outlets (OTO) in Switzerland are generally LC APC.
SFP transceivers are almost always UPC (aka. PC), but can be either SC or LC.
APC is green, UPC is blue.
<a href="https://community.fs.com/blog/">fs.com&rsquo;s blog</a> is a great resource to learn about the various types of cables and connectors.
For the transceiver, follow the specs provided by init7 <a href="https://www.init7.net/en/support/router-information/">here</a>
and <a href="https://www.init7.net/en/internet/hardware/">here</a>.
People seem to buy fiber equipment either on fs.com or on flexoptics.net.</p>
<h2 id="assembling-it">Assembling it</h2>
<p>Here are a few photos from assembling the server.</p>
<p>The inside:
You can see the two SSDs on the left, the big silver heat sink that hides the CPU behind it,
and the two pieces of RAM on the right.
The box on the very right (facing the front of the NUC) is the power supply.
Lying at the front, you can see the box with the fan that goes on top of the CPU/SSD/RAM.
The two grey bars will go on top of the SSDs, meaning that you don&rsquo;t need dedicated heatsinks for the SSDs (also, they wouldn&rsquo;t fit).</p>


<img src="/img/router-build/build-1.jpg"   class="center" />

<p>Installing the Mellanox card in the blue PCIe slot:</p>


<img src="/img/router-build/build-2.jpg"   class="center" />

<p>The view of the back:
The top RJ45 port is 10 Gbit/s, the bottom one is 2.5 Gbit/s.
On the right, the two SFP28 ports of the Mellanox card.
Matchstick for scale.</p>


<img src="/img/router-build/build-3.jpg"   class="center" />

<h2 id="installing-it">Installing it</h2>
<p>This is what the NUC looks like with everything installed:</p>


<img src="/img/router-build/router-1.jpg"   class="center" />

<p>And the back:
The yellow fiber cable goes into the wall and out to init7.
The black Direct Attach Cable (DAC) below goes into my NAS.
The blue copper cables go into switches.</p>


<img src="/img/router-build/router-3.jpg"   class="center" />

<p>Because the NUC Extreme is designed for gamers, it has LEDs (of course it does):</p>


<img src="/img/router-build/router-2.jpg"   class="center" />

<p>Luckily, there is a physical button on the bottom of the NUC allowing you to turn the LEDs on and off.
No need to install any drivers.</p>
<p>As you can see e.g. on its <a href="https://www.digitec.ch/en/s1/product/intel-nuc-12-extreme-kit-nuc12dcmi9-intel-core-i9-12900-barebones-21616859?shid=1249618">Digitec page</a>,
the front of the NUC usually features a skull.
Weird taste, probably reaching only a subset of gamers, and an even smaller subset of the general population, but okay.
Luckily, the skull is just a small semi-transparent mask.
You can unscrew the front of the panel and take the skull mask out,
leaving you with the full, square LED front (as seen in my picture).
(I learnt this from <a href="https://williamlam.com/2021/07/esxi-on-intel-nuc-11-extreme-beast-canyon.html">this review</a>
of the Intel NUC 11 Extreme.)
Optionally, you can cut your own thin sheet to mask the light to another shape.
I haven&rsquo;t tried this yet since I leave the LEDs off anyway.</p>
<h2 id="speedtest">Speedtest</h2>
<p>So does it work? Does it make the internet go swoosh?</p>
<p>First, an iPad Pro, with a 2.5 Gbit/s <a href="https://www.digitec.ch/en/s1/product/belkin-usb-4-to-rj-45-usb-c-rj45-network-adapters-24043669">USB-C to RJ45 adapter</a>:</p>


<img src="/img/router-build/speedtest-ipad.png"   class="center" />

<p>(Note that unlike Android, iPadOS doesn&rsquo;t have a dedicated status icon in the top right for Ethernet (like for WiFi).)</p>
<p>Next, the system monitor on my laptop when connected with the 2.5 Gbit/s adapter (290 MiB/s = 2430 Mbit/s):</p>


<img src="/img/router-build/speedtest-laptop.png"   class="center" />

<p>The first half shows an iperf3 test to speedtest.init7.net.
The second half shows a speedtest.net test in Firefox.
Clearly my CPU (a 2 core, 4 threads i5 7th gen) is the bottleneck.
Speedtest.net, Firefox, the Snap sandbox, the network stack, or something else somewhere,
makes the CPU go more spinny than iperf3 in a terminal does.
Either I can buy a new latptop, or someone can fix the software.</p>
<p>Apropos iperf3 in a terminal. Here is iperf3 running on the shiny new router:</p>


<img src="/img/router-build/speedtest-router.png"   class="center" />

<p>A mere 15&ndash;16 Gbit/s. Far from the 25 Gbit/s we were hoping for.
But at least more than 10 Gbit/s, so not a complete waste, I guess?</p>
<p>Doing an iperf3 between the new router and the old NAS,
both with their SFP28 cards and the SFP28 DAC cable, I also only get ~15 Gbit/s.
So the bottleneck is not init7, but somewhere on my setup.
I just need to find the time to track it down.
Using PCI passthrough for the NIC (since OPNsense is running in a VM) already improved
the performance by ~1 Gbit/s compared to using Proxmox&rsquo; virtual bridge.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this post I described my journey to building a home router.
Compute-wise, the new server is more powerful than originally envisioned.
That&rsquo;s fine, I will use it to run VMs, e.g. a remote desktop to extend the lifetime of my old laptop.
Speed-wise, the router is practically capable of 15 Gbit/s,
and theoretically capable of 25 Gbit/s (once I managed to tune it).</p>
<p>Do I need 15 Gbit/s? No.
Working, reliable 2.5 Gbit/s would be nice though.</p>
<p>In practice, the download performance for many things is still at most 1 Gbit/s, and 1.5 Gbit/s if you are lucky.
I briefly tested this by downloading various installation images (Debian, Ubuntu, LineageOS, GrapheneOS).</p>
<p>It is a chicken-and-egg problem.
If no one has fast internet at home, no one will provide fast servers,
and no one will optimise the software stacks and transport protocols to &ldquo;just work&rdquo;.
By having the hardware for 25 Gbit/s, we have eliminated the first bottleneck.
Next, we need to eliminate the software and configuration bottlenecks.</p>
<p>Hopefully, as more and more people have faster internet,
more developers will optimise for it,
and those speeds will become usable out-of-the-box.
I am looking forward to the day when I can download the 10 GB folder of photos
my friend shared with me from our holiday trip at 2.5 Gbit/s in 30 seconds,
and not in 2 minutes at the currently realistic 0.7 Gbit/s.</p>
<p>And maybe even in 8 seconds at 10 Gbit/s, if I decide to spent way too much money on a
<a href="https://www.digitec.ch/en/s1/product/sonnet-solo-10g-ethernet-rj45-sfp-network-adapters-15827198">Thunderbolt-to-SFP+ adapter</a>
for my laptop.</p>
]]></content></item><item><title>How Certificates are Born (Data Structure Edition)</title><link>https://thore.io/posts/2023/07/how-certificates-are-born-data-structure-edition/</link><pubDate>Fri, 28 Jul 2023 13:00:00 +0000</pubDate><guid>https://thore.io/posts/2023/07/how-certificates-are-born-data-structure-edition/</guid><description>&lt;p>Authentic key distribution is a fundamental problem of public key cryptography:
how do you know that a public key &lt;em>really&lt;/em> belongs an entity (the &amp;ldquo;subject&amp;rdquo;)?
A MITM attacker could have intercepted and changed the public key!
In other words, we need an authentic public-key-to-identity binding.&lt;/p>
&lt;p>One solution is to meet up in person and verify their public key directly.
This is what Signal and WhatsApp do with their Safety Numbers.&lt;/p></description><content type="html"><![CDATA[<p>Authentic key distribution is a fundamental problem of public key cryptography:
how do you know that a public key <em>really</em> belongs an entity (the &ldquo;subject&rdquo;)?
A MITM attacker could have intercepted and changed the public key!
In other words, we need an authentic public-key-to-identity binding.</p>
<p>One solution is to meet up in person and verify their public key directly.
This is what Signal and WhatsApp do with their Safety Numbers.</p>
<p>But this doesn&rsquo;t scale. How would you meet up with Google to verify their website&rsquo;s public key?
This is where certificates come in.</p>
<p>A Certificate Authority (CA) verifies the identity (&ldquo;thore.io&rdquo;) and that this identity controls a keypair (pk, sk).
The CA then <em>signs</em> a certificate that basically states
&ldquo;I, the CA, certify that the secret key belonging to the public key pk is controlled by the entity thore.io&rdquo;.
Now anybody who trusts that the CA is honest and
that it correctly verifies identifies before issuing certificates
can also trust that this public-key-to-identity binding is correct.</p>
<p>But what is the flow of creating certificates?
What are the data structures?</p>
<p>Certificates are often seen as this big complex beast. And correctly so!
The many extensions and options mean that it gets complicated fast.
But the core data structures are not <em>that</em> complicated.</p>
<p>This post tries to break down these data structures.
Using the data structures to guide us,
we step through the process of creating a certificate.</p>
<h2 id="step-1-certificate-request">Step 1: Certificate Request</h2>
<p>It starts with what is colloquially known as &ldquo;Certificate Signing Request&rdquo;.
It usually uses the following PKCS#10 data structures (defined in <a href="https://datatracker.ietf.org/doc/html/rfc2986.html">RFC 2986</a>).</p>
<p>PKCS#10 looks like this:</p>
<pre><code class="language-asn1">CertificationRequestInfo ::= SEQUENCE {
    version       INTEGER { v1(0) } (v1,...),
    subject       Name,
    subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
    attributes    [0] Attributes{{ CRIAttributes }}
}

CertificationRequest ::= SEQUENCE {
    certificationRequestInfo CertificationRequestInfo,
    signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
    signature          BIT STRING
}
</code></pre>
<p>If subject S has a keypair and wants to obtain a certificate,
it first creates a <code>CertificationRequestInfo</code> and fills out
the subject name (&ldquo;thore.io&rdquo;) and the details of their public key.
Then S signs the <code>CertificationRequestInfo</code> and together with the signature
puts it into a <code>CertificationRequest</code>.</p>
<h2 id="step-2-x509-certificate">Step 2: X.509 Certificate</h2>
<p>S then sends the <code>CertificationRequest</code> to a CA of their choice.</p>
<p>Now the CA needs to verify that the subject S really controls the public key
S wants to bind to its identity.
It can e.g. do this using ACME (defined in <a href="https://datatracker.ietf.org/doc/html/rfc8555.html">RFC 8555</a>).</p>
<p>When the CA is satisfied it issues the certificate.
Certificates generally use the X.509 format (defined in <a href="https://datatracker.ietf.org/doc/html/rfc5280.html">RFC 5280</a>).</p>
<p>X.509 certificates look like this:</p>
<pre><code class="language-asn1">TBSCertificate  ::=  SEQUENCE  {
    version         [0]  EXPLICIT Version DEFAULT v1,
    serialNumber         CertificateSerialNumber,
    signature            AlgorithmIdentifier,
    issuer               Name,
    validity             Validity,
    subject              Name,
    subjectPublicKeyInfo SubjectPublicKeyInfo,
    issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
    subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
    extensions      [3]  EXPLICIT Extensions OPTIONAL
}

Certificate  ::=  SEQUENCE  {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING
}
</code></pre>
<p>The CA first fills out the <code>TBSCertificate</code> (&ldquo;to-be-signed&rdquo; certificate).
It copies over the values from the <code>CertificationRequest</code>,
assigns a new serial number, chooses a validity period,
and adds any extensions that it wants.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>The CA then signs the <code>TBSCertificate</code> and puts everything together into the <code>Certificate</code>.
We now have an X.509 certificate!</p>
<h2 id="step-3-signed-certificate-timestamp">Step 3: Signed Certificate Timestamp</h2>
<p>Back in the day, we would now be done.
The CA returns the X.509 certificate to the requester subject S
who can use it to prove their identity (e.g. in a TLS handshake).</p>
<p>However, after a series of CAs misbehaving and wrongly issuing certificates
Google introduced <a href="https://certificate.transparency.dev/howctworks/">Certificate Transparency (CT)</a>.
With CT the CAs need to insert every certificate that they issue into a public append-only log.
For efficiency, this log is a Merkle Tree with the leaves being the log entries.</p>
<p>CT is defined in <a href="https://datatracker.ietf.org/doc/html/rfc9162.html">RFC 9162</a>.
The relevant data structures are:</p>
<pre><code class="language-c">struct {
    VersionedTransType versioned_type;
    select (versioned_type) {
        case x509_entry_v2: TimestampedCertificateEntryDataV2;
        case precert_entry_v2: TimestampedCertificateEntryDataV2;
        case x509_sct_v2: SignedCertificateTimestampDataV2;
        case precert_sct_v2: SignedCertificateTimestampDataV2;
        case signed_tree_head_v2: SignedTreeHeadDataV2;
        case consistency_proof_v2: ConsistencyProofDataV2;
        case inclusion_proof_v2: InclusionProofDataV2;
    } data;
} TransItem;

opaque TBSCertificate&lt;1..2^24-1&gt;;

struct {
    uint64 timestamp;
    opaque issuer_key_hash&lt;32..2^8-1&gt;;
    TBSCertificate tbs_certificate;
    Extension sct_extensions&lt;0..2^16-1&gt;;
} TimestampedCertificateEntryDataV2;

struct {
    LogID log_id;
    uint64 timestamp;
    Extension sct_extensions&lt;0..2^16-1&gt;;
    opaque signature&lt;1..2^16-1&gt;;
} SignedCertificateTimestampDataV2;
</code></pre>
<p>First the CA sends the X.509 certificate to a CT log operator.
(Alternatively the CA can also send a &ldquo;precertificate&rdquo;.
This signals the CA&rsquo;s binding intent to later issue a certificate.)</p>
<p>The log operator extracts the <code>TBSCertificate</code> from the X.509 certificate (after verifying the signature).
The log operator then builds the <code>TimestampedCertificateEntryDataV2</code> and puts it into a <code>TransItem</code> of type <code>x509_entry_v2</code>.
This <code>TransItem</code> will eventually be inserted into the log (as one of the Merkle Tree leaves).</p>
<p>The log operator the creates a &ldquo;Signed Certificate Timestamp (SCT)&rdquo;:
It signs the <code>TransItem</code> and puts the signature into the <code>SignedCertificateTimestampDataV2</code>.
The <code>timestamp</code> and the <code>sct_extensions</code> are copied over from the <code>TimestampedCertificateEntryDataV2</code>.
With this signature a log operator promises to include the corresponding <code>TimestampedCertificateEntryDataV2</code> in the log.</p>
<p>Note that the SCT does <em>not</em> contain the certificate.
Thus the SCT is only useful in combination with a certificate.
Also, the SCT is <em>not</em> included in the log, only the certificate.</p>
<p>The log operator then returns the SCT to the CA.</p>
<h2 id="step-4-x509-certificate-again">Step 4: X.509 Certificate again</h2>
<p><a href="https://googlechrome.github.io/CertificateTransparency/ct_policy.html">Chrome</a>
and <a href="https://support.apple.com/en-us/HT205280">Safari</a> require CT and will only accept TLS connections with certificates
that are included in two or more CT logs.
<a href="https://developer.mozilla.org/en-US/docs/Web/Security/Certificate_Transparency#browser_requirements">Firefox</a> does not enforce CT
(at the time of writing in July 2023).</p>
<p>The browsers enforce this by verifying the &gt;= 2 SCTs together with the certificate.
There are three ways for the webserver to send the SCT to the browser:
include the SCT directly in the certificate, or serve the SCT over OCSP,
or as a TLS extension (see Section 6 of <a href="https://datatracker.ietf.org/doc/html/rfc9162.html">RFC 9162</a>).</p>
<p>If the SCT is directly embedded into the certificate, the flow is slightly different:
the CA does not submit a X.509 certificate to the log but instead it submits a precertificate.
When the CA gets the SCT from the log operator,
includes the SCT in the <code>extensions</code> field of the X.509 certificate.
Only then the CA signs and issues the X.509 certificate.</p>
<p>Finally, the CA returns the X.509 certificate and the SCT to the subject.</p>
<h2 id="conclusion">Conclusion</h2>
<p>This post gave a brief overview of the process of creating certificates
and the data structures that the certificate data flows through.</p>
<p>We started with a Certificate Request, then issued an X.509 certificate, and then also obtained an SCT.</p>
<p>If you want to dive deeper read the linked RFCs.</p>
<p>If you want to inspect PEM/DER-encoded ASN.1 objects (e.g. a CSR) you can use <code>openssl asn1parse</code>.
Alternatively <code>der2ascii</code> (<a href="https://github.com/google/der-ascii">Github</a>) provides a nice hierarchical view.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>The <code>TBSCertificate.signature</code> field <a href="https://security.stackexchange.com/questions/24788/signaturealgorithm-vs-tbscertificate-signature">is redundant</a>.
Also yes, it should really be called <code>TBSCertificate.signatureAlgorithm</code>&hellip;&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Please Don't Write Passwords to Android Logs</title><link>https://thore.io/posts/2023/05/please-dont-write-passwords-to-android-logs/</link><pubDate>Wed, 10 May 2023 08:00:00 +0200</pubDate><guid>https://thore.io/posts/2023/05/please-dont-write-passwords-to-android-logs/</guid><description>&lt;blockquote>
&lt;p>TLDR: Don&amp;rsquo;t log sensitive information. Not on Android, and not anywhere else.
Still, in 2022 I found two Android apps that do exactly that.&lt;/p>
&lt;/blockquote>
&lt;p>This post starts with an introduction to logging on Android.
I describe common pitfalls that lead to sensitive information being leaked to Android logs.
I describe why this is bad and what impact it can have.
Finally, I show two real-world apps that were/are leaking sensitive information in this way.&lt;/p></description><content type="html"><![CDATA[<blockquote>
<p>TLDR: Don&rsquo;t log sensitive information. Not on Android, and not anywhere else.
Still, in 2022 I found two Android apps that do exactly that.</p>
</blockquote>
<p>This post starts with an introduction to logging on Android.
I describe common pitfalls that lead to sensitive information being leaked to Android logs.
I describe why this is bad and what impact it can have.
Finally, I show two real-world apps that were/are leaking sensitive information in this way.</p>
<h2 id="logs-on-android">Logs on Android</h2>
<p>Logs are useful because they allow developers to trace application behaviour.
It allows developers to understand what happened to an application, what state it was in, what events occurred.
This is useful when troubleshooting.</p>
<p>Apps on Android usually write logs by calling one of the methods of the
<code>android.util.Log</code> <a href="https://developer.android.com/reference/android/util/Log.html">class</a>:</p>
<pre><code class="language-java">Log.v(&quot;MY_TAG&quot;, &quot;Something happened&quot;);
</code></pre>
<p>These print statements are collected into a log stream.
It&rsquo;s like printing to stdout, but separate.</p>
<p>There are different log levels: verbose, debug, info, warning, error.</p>
<p>Normally, apps can only read their own logs, but not other apps&rsquo; logs.
However, certain (system) apps can read all logs if they have the READ_LOGS permission (see below).</p>
<p>If debugging is enabled in the phone&rsquo;s developer settings, you can view all logs on a computer using
the <a href="https://developer.android.com/tools/logcat">ADB command</a> <code>adb logcat</code>
or in the logcat tab in <a href="https://developer.android.com/studio/debug/logcat">Android Studio</a>.
Logcat can filter logs by tag and by log level.</p>
<h3 id="common-pitfalls">Common Pitfalls</h3>
<p>There are two common pitfalls that I have seen Android developers fall into:</p>
<p><strong>Pitfall 1:</strong>
The log level <code>DEBUG</code> is only another tag to filter the stream when viewing logs.</p>
<p>Logs written with <code>Log.d</code> are included in builds with <a href="https://developer.android.com/build/build-variants#build-types">build type</a> &ldquo;release&rdquo;.
Even when <code>BuildConfig.DEBUG == False</code> these log statements are included and will be printed!</p>
<p>Developers, you need to manually wrap these <code>Log.d</code> statements in an <code>if (BuildConfig.DEBUG) { ... }</code>.
Or better, you should strip them completely from the release apk/dexfile (which is non-trivial).</p>
<p>Google could make this more clear, or make it easier for developers to strip DEBUG level statements.</p>
<p><strong>Pitfall 2:</strong> Including network logging in release builds.</p>
<p>Logging network requests is useful during development, since you don&rsquo;t need to setup a proxy and break open TLS.
And with OkHttp&rsquo;s
<a href="https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor">HttpLoggingInterceptor</a>
it is as easy as adding three lines of code:</p>
<pre><code class="language-java">HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); // add this
OkHttpClient client = new OkHttpClient.Builder()
  .addInterceptor(logging) // add this
  .build();

// add this to the build.gradle
implementation(&quot;com.squareup.okhttp3:logging-interceptor:1.0.0&quot;)

// and - bam! - all network requests are logged and viewable in logcat
</code></pre>
<p>Developers, you should only add the HttpLoggingInterceptor temporarily while debugging a specific issue.
There is no real need to even commit the HttpLoggingInterceptor to git.
And if you do, at least wrap it in <code>if (BuildConfig.DEBUG) { ... }</code>
and add the dependency only to debug builds (with <code>flavourDebugImplementation(...)</code>,
see the <a href="https://developer.android.com/build/dependencies#dependency_configurations">docs</a>).</p>
<h2 id="impact-of-logging-sensitive-information">Impact of Logging Sensitive Information</h2>
<p>Logging sensitive data can result in data exposure to third parties.</p>
<p>On Android specifically, logging crosses the <em>trust boundary</em> between the app sandbox and the logging system.</p>
<p>For example, an app that uses an access token for network requests can store the token in its &ldquo;shared preferences&rdquo;.
Despite the name, shared preferences are sandboxed and cannot be accessed by other apps.
But when the access token is written to logcat it leaks outside the sandbox.
Other apps can read these logs (with the appropriate permission, see below) and can now access the token!</p>
<p>The corresponding CWE is <a href="https://cwe.mitre.org/data/definitions/532.html">CWE-532</a> (Insertion of Sensitive Information into Log File).</p>
<h2 id="exploitability">Exploitability</h2>
<p>Reading logs requires the <code>android.permission.READ_LOGS</code> permission.</p>
<p><strong>User apps</strong> usually do not have this permission.
It can be granted via adb (<a href="https://github.com/darshanparajuli/LogcatReader#usage">some apps</a> use this), but for the average user this is an unrealistic hurdle.</p>
<p><strong>System apps</strong> that come pre-installed sometimes have this permission.</p>
<p>And starting in Android 13, in addition to requiring the READ_LOGS permission, Android also prompts the user:</p>
<figure><img src="/img/read-logs-permission-request.png"
    alt="READ_LOGS Permission Request" width="250"><figcaption>
      <p>READ_LOGS Permission Request</p>
    </figcaption>
</figure>

<p>But how widespread is this?</p>
<p>In my own test 44 system apps had the READ_LOGS permission on OxygenOS 11 (OnePlus 7, as of June 2022),
and 21 apps on LineageOS 20 (without GApps, OnePlus 5, as of May 2023).</p>
<p>AppCensus also <a href="https://blog.appcensus.io/2021/04/27/why-google-should-stop-logging-contact-tracing-data/">noted</a> a similar problem of sensitive data exposure via logs back in April 2021.
They found that 59 apps can READ_LOGS on a Xiami Redmi Note 9, and 89 apps on a Samsung Galaxy A11.</p>
<p>The following apps/packages can READ_LOGS on OxygenOS 11 (produced with <a href="https://gist.github.com/thgoebel/1be04b5d8a36fc9efe8b75170f3391a7">this script</a>):</p>
<pre><code>android
cn.oneplus.nvbackup
com.android.dynsystem
com.android.inputdevices
com.android.keychain
com.android.localtransport
com.android.location.fused
com.android.providers.settings
com.android.server.telecom
com.android.settings
com.android.wallpaperbackup
com.dsi.ant.server
com.fingerprints.fingerprintsensortest
com.google.android.feedback
com.google.android.gms
com.google.android.gsf
com.oem.autotest
com.oem.logkitsdservice
com.oem.nfc
com.oem.oemlogkit
com.oem.rftoolkit
com.oneplus
com.oneplus.backuprestore.remoteservice
com.oneplus.brickmode
com.oneplus.camera.service
com.oneplus.config
com.oneplus.coreservice
com.oneplus.factorymode
com.oneplus.filemanager
com.oneplus.gamespace
com.oneplus.minidumpoptimization
com.oneplus.opbackup
com.oneplus.opbugreportlite
com.oneplus.orm
com.oneplus.screenrecord
com.oneplus.screenshot
com.oneplus.sdcardservice
com.oneplus.security
com.oneplus.setupwizard
com.oneplus.sound.tuner
com.qti.diagservices
com.tencent.soter.soterserver
net.oneplus.commonlogtool
net.oneplus.odm
</code></pre>
<p>And on LineageOS 20 (without GApps):</p>
<pre><code>android
com.android.dynsystem
com.android.inputdevices
com.android.keychain
com.android.localtransport
com.android.location.fused
com.android.providers.settings
com.android.server.telecom
com.android.settings
com.android.shell
com.android.wallpaperbackup
com.dsi.ant.server
com.stevesoltys.seedvault
com.tencent.soter.soterserver
lineageos.platform
org.lineageos.lineageparts
org.lineageos.lineagesettings
org.lineageos.pocketmode
org.lineageos.settings.device
org.lineageos.settings.doze
org.lineageos.setupwizard
</code></pre>
<p>Notice that this includes Google Play Services (<code>com.google.android.{gms, gsf}</code>) and various proprietary OnePlus apps.
It is unclear whether these apps do access the logs and/or sent them to vendors.
But they do have the permission do to so.</p>
<p>In addition, both OnePlus and Google Pixel devices have features that allow users to explicitly submit logs to the vendor.</p>
<ul>
<li>OnePlus: Settings &gt; System &gt; Experience Improvement Programmes &gt; System Stability program</li>
<li>Googe Pixel: Settings &gt; Tips &amp; Support &gt; Send feedback</li>
</ul>
<p>Overall, the exploitability is low.
Still, sensitive information could end up on the vendors&rsquo; servers.</p>
<h2 id="fixing-it">Fixing it</h2>
<p>Fixing this is easy.
Just remove all logging statements (network and other) that expose sensitive information to logcat (at least in production builds).</p>
<h2 id="real-world-examples">Real-World Examples</h2>
<p>Below I show the two real-world apps that I found logging sensitive information, prompting me to write this post.</p>
<p>How did I find these?
In both cases, the apps were buggy. Some unrelated feature was not working for me.
And when I investigate bugs the first thing I do is open logcat.
This is where I went &ldquo;oh dear&rdquo;.</p>
<p>Both apps have one thing in common (despite the logging issue):
they don&rsquo;t have a <a href="https://securitytxt.org/">security.txt</a> or a Vulnerability Disclosure Policy (let alone a Bug Bounty).<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>
In both cases I had to jump through hoops to find a contact.
For app 1 I luckily had a shared contact at the company that I could reach out to.
For app 2 I had to go through normal support.</p>
<p>So in 2022, it was still challenging to report vulnerabilities, even for two apps that both handle
financial transactions and that both have 100K+ downloads on Google Play.</p>
<p>In the logcat excerpts below I replaced sensitive information with 🚫🚫🚫.</p>
<h3 id="app-1-unnamed">App 1: Unnamed</h3>
<p>The first app is a financial app. It was logging passwords, but also network traffic:</p>
<pre><code>D Action  : Logon(vertragsNr=🚫🚫🚫, password=🚫🚫🚫, appInfo=AppInfo(appIdentifier=🚫🚫🚫, versionNumber=42.0, buildNumber=42, deviceName=OnePlus, ONEPLUS A5000, osVersion=Android 12 (32) | Code name: REL, unlocked=true, pushServiceType=GOOGLE), isBiometricLogon=false, biometryType=null)
D Network : GET /mobile/home/context -&gt; HomeContext(sections=[HomeSection(type=FINANZEN, position=0, title=null), HomeSection(type=SHORTCUTS, position=1, title=null), HomeSection(type=ZU_ERLEDIGEN, position=2, title=You have), HomeSection(type=MARKETING_CONTENT, position=3, title=Discover)])
&lt;!-- more network traffic omitted --&gt;
</code></pre>
<p>This log leaks the username (&ldquo;vertragsNr&rdquo;) and password.
Also notice how the network responses are logged as data classes.
They reflect the sections on the app&rsquo;s home screen.
This is bad, because the app was effectively streaming the screen state to logcat.</p>
<p>The log level &ldquo;D&rdquo; (debug) demonstrates Pitfall 1.</p>
<h4 id="disclosure-timeline">Disclosure Timeline</h4>
<ul>
<li>Wed 2022-06-22 21:30: I reach out to my shared contact at the company.</li>
<li>Thu 2022-06-23 08:18: They reply and say they will find the right contact internally.</li>
<li>Thu 2022-06-23 10:22: The security team reaches out to me.</li>
<li>Thu 2022-06-23 11:35: I send them my writeup.</li>
<li>Thu 2022-06-23 15:22: The security team acknowledges that they reproduced and patched it and will make a new release soon.</li>
<li>Thu 2022-06-23 22:45: I test their fix, and verify that it works.</li>
</ul>
<p>Within a single day the issue was acknowledged and fixed!
They clearly had the internal processes in place to handle security issues,
even if they did not have a public security contact yet (now they do<sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>).</p>
<p>(Why am I not naming them? Their handling was exemplary, it is fixed, there is no public benefit knowing the name.
If you keep your apps up-to-date, there is nothing else you as a user need to do to protect yourself.
The only public benefit is in knowing that I found more than one app, because this demonstrates that
this is a recurring issue that we as a security and developer community need to be aware of.)</p>
<h3 id="app-2-circuit-laundry">App 2: Circuit Laundry</h3>
<p>The second app is the app for a laundry service in the UK, called <a href="https://www.circuit.co.uk/">Circuit Laundry</a>.
This app allows you to log in, pay with your credit card within the app to top up your account balance,
and use that account balance to start washing machines and tumble driers.</p>
<p>Just like App 1, Circuit also streams all network traffic to logcat.
This includes credentials (passwords, bearer tokens), personally identifiable information
(first name, last name, email address), account balance, and account id.</p>
<p>Logs written during login:</p>
<pre><code>I okhttp.OkHttpClient: --&gt; POST https://phoneadmin.flashcashonline.com/api/user/authenticate/?password=🚫🚫🚫&amp;version=2&amp;email=🚫🚫🚫&amp;platform=Android
I okhttp.OkHttpClient: Content-Length: 0
I okhttp.OkHttpClient: --&gt; END POST (0-byte body)
I okhttp.OkHttpClient: &lt;-- 200 https://phoneadmin.flashcashonline.com/api/user/authenticate/?password=🚫🚫🚫&amp;version=2&amp;email=🚫🚫🚫&amp;platform=Android (1201ms)
I okhttp.OkHttpClient: cache-control: no-cache
I okhttp.OkHttpClient: pragma: no-cache
I okhttp.OkHttpClient: content-type: application/json; charset=utf-8
I okhttp.OkHttpClient: expires: -1
I okhttp.OkHttpClient: vary: Accept-Encoding
I okhttp.OkHttpClient: set-cookie: ARRAffinity=6eaf2cedfb705ed6ce633e6c1ba37f34686cbd9dce05635559dff6fd9e92ea1a;Path=/;HttpOnly;Secure;Domain=phoneadmin2.azurewebsites.net
I okhttp.OkHttpClient: set-cookie: ARRAffinitySameSite=6eaf2cedfb705ed6ce633e6c1ba37f34686cbd9dce05635559dff6fd9e92ea1a;Path=/;HttpOnly;SameSite=None;Secure;Domain=phoneadmin2.azurewebsites.net
I okhttp.OkHttpClient: x-aspnet-version: 4.0.30319
I okhttp.OkHttpClient: x-powered-by: ASP.NET
I okhttp.OkHttpClient: x-cache: CONFIG_NOCACHE
I okhttp.OkHttpClient: x-azure-ref: 0xYNjYwAAAAAEtq35BO3kQa1pmW2pi1HQTFRTRURHRTEzMTAAYWFiZjcyNTctMmE5NC00MDY5LTlkMGMtMWM1NTQzYjNlZWIz
I okhttp.OkHttpClient: date: Thu, 03 Nov 2022 09:03:01 GMT
I okhttp.OkHttpClient: {&quot;Data&quot;:{&quot;AppUserId&quot;:🚫🚫🚫,&quot;UserIdentification&quot;:&quot;🚫🚫🚫&quot;,&quot;HasPromotions&quot;:false,&quot;Token&quot;:{&quot;Value&quot;:&quot;🚫🚫🚫&quot;,&quot;Expires&quot;:null},&quot;PrimaryLocation&quot;:&quot;&quot;,&quot;AccountBalance&quot;:6.80,&quot;InternalId&quot;:🚫🚫🚫,&quot;ExternalKey&quot;:&quot;🚫🚫🚫&quot;,&quot;AccountName&quot;:&quot;🚫🚫🚫&quot;,&quot;AccountOperatorID&quot;:5,&quot;AccountMinimumPurchaseAmount&quot;:5.00,&quot;AccountLowBalanceIndicator&quot;:5.00,&quot;AccountCurrencyTypeID&quot;:3,&quot;AccountCurrencyUniCode&quot;:&quot;20AC&quot;,&quot;IsRoomViewAvailable&quot;:true,&quot;AccountWelcomeTitle&quot;:&quot;Welcome to Circuit&quot;,&quot;AccountWelcomeText&quot;:&quot;Welcome to Circuit&quot;,&quot;FirstName&quot;:&quot;Thore&quot;,&quot;LastName&quot;:&quot;Goebel&quot;,&quot;OptInNotification&quot;:false,&quot;OptInMarketing&quot;:false,&quot;EmailAddress&quot;:&quot;🚫🚫🚫&quot;,&quot;AppVersion&quot;:&quot;2&quot;,&quot;AppPlatform&quot;:&quot;Android&quot;,&quot;MessageForUser&quot;:&quot;&quot;},&quot;Success&quot;:true,&quot;Message&quot;:&quot;Authenticated&quot;}
I okhttp.OkHttpClient: &lt;-- END HTTP (1727-byte body)
</code></pre>
<p>Logs written during app usage later:</p>
<pre><code>I okhttp.OkHttpClient: --&gt; GET https://phoneadmin.flashcashonline.com/api/user/
I okhttp.OkHttpClient: authorization: bearer 🚫🚫🚫
I okhttp.OkHttpClient: --&gt; END GET
I okhttp.OkHttpClient: &lt;-- 200 https://phoneadmin.flashcashonline.com/api/user/ (217ms)
I okhttp.OkHttpClient: cache-control: no-cache
I okhttp.OkHttpClient: pragma: no-cache
I okhttp.OkHttpClient: content-type: application/json; charset=utf-8
I okhttp.OkHttpClient: expires: -1
I okhttp.OkHttpClient: vary: Accept-Encoding
I okhttp.OkHttpClient: set-cookie: ARRAffinity=6eaf2cedfb705ed6ce633e6c1ba37f34686cbd9dce05635559dff6fd9e92ea1a;Path=/;HttpOnly;Secure;Domain=phoneadmin2.azurewebsites.net
I okhttp.OkHttpClient: set-cookie: ARRAffinitySameSite=6eaf2cedfb705ed6ce633e6c1ba37f34686cbd9dce05635559dff6fd9e92ea1a;Path=/;HttpOnly;SameSite=None;Secure;Domain=phoneadmin2.azurewebsites.net
I okhttp.OkHttpClient: x-aspnet-version: 4.0.30319
I okhttp.OkHttpClient: x-powered-by: ASP.NET
I okhttp.OkHttpClient: x-cache: CONFIG_NOCACHE
I okhttp.OkHttpClient: x-azure-ref: 0yYNjYwAAAACoPdEYF50OSrWF+8q6w4IZTFRTRURHRTEzMTAAYWFiZjcyNTctMmE5NC00MDY5LTlkMGMtMWM1NTQzYjNlZWIz
I okhttp.OkHttpClient: date: Thu, 03 Nov 2022 09:03:04 GMT
I okhttp.OkHttpClient: {&quot;Data&quot;:{&quot;AppUserId&quot;:🚫🚫🚫,&quot;UserIdentification&quot;:&quot;🚫🚫🚫&quot;,&quot;HasPromotions&quot;:false,&quot;Token&quot;:null,&quot;PrimaryLocation&quot;:null,&quot;AccountBalance&quot;:6.80,&quot;InternalId&quot;:🚫🚫🚫,&quot;ExternalKey&quot;:&quot;🚫🚫🚫&quot;,&quot;AccountName&quot;:&quot;JLA LAB&quot;,&quot;AccountOperatorID&quot;:5,&quot;AccountMinimumPurchaseAmount&quot;:5.00,&quot;AccountLowBalanceIndicator&quot;:5.00,&quot;AccountCurrencyTypeID&quot;:3,&quot;AccountCurrencyUniCode&quot;:&quot;20AC&quot;,&quot;IsRoomViewAvailable&quot;:false,&quot;AccountWelcomeTitle&quot;:null,&quot;AccountWelcomeText&quot;:null,&quot;FirstName&quot;:&quot;Thore&quot;,&quot;LastName&quot;:&quot;Goebel&quot;,&quot;OptInNotification&quot;:false,&quot;OptInMarketing&quot;:false,&quot;EmailAddress&quot;:&quot;🚫🚫🚫&quot;,&quot;AppVersion&quot;:&quot;2&quot;,&quot;AppPlatform&quot;:&quot;Android&quot;,&quot;MessageForUser&quot;:null},&quot;Success&quot;:true,&quot;Message&quot;:&quot;Authorized&quot;}
I okhttp.OkHttpClient: &lt;-- END HTTP (669-byte body)
</code></pre>
<h4 id="disclosure-timeline-1">Disclosure Timeline</h4>
<ul>
<li>Mon 2022-11-07: Initial outreach to {security, info, contact, <a href="mailto:postmaster%7d@circuit.co.uk">postmaster}@circuit.co.uk</a>. {security, contact}@ bounced.</li>
<li>Mon 2022-11-14: Outreach to <a href="mailto:info@circuitcardtopup.com">info@circuitcardtopup.com</a> (found on Google Play) and <a href="mailto:dataprotection@jla.com">dataprotection@jla.com</a> (found in the Privacy Policy).
Interestingly, the data protection contact does not reply.</li>
<li>Tue 2022-11-15: Circuit support (<a href="mailto:info@circuitcardtopup.com">info@circuitcardtopup.com</a>) replies. I send them the report.</li>
<li>Sun 2023-02-04: I ask for an update and notify them that I plan to publish in 90 days (i.e. on 2023-05-05).
I decided to count the 90 days from today since I did not mention my intent to publish in November.</li>
<li>Wed 2023-02-08: Circuit support replies: &ldquo;I have passed this on to our app developers again to look into it for you and have escalated it. I will update you once they come back to me.&rdquo;</li>
<li>Mon 2023-04-17: I ask for an update.</li>
<li>Tue 2023-04-18: Circuit support replies: &ldquo;There have been no updates provided to us as of yet but I will chase up with the app development team and let you know of any updates when we get them.&rdquo;</li>
<li>2023-05-10: I publish this blog post.</li>
</ul>
<p>The issue remains unfixed, ~6 months after I first reported it, and despite the fix being super simple.
The affected version is 4.1.0 which was <a href="https://web.archive.org/web/20230504130549/https://play.google.com/store/apps/details?id=greenwald.app.circuit">released</a>
on 31 March 2022.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>As a user there is very little you can do.
You could reboot your phone after using the Circuit app (since this wipes logcat).
You could also avoid explicitly submitting logs to vendors (Google Pixel&rsquo;s &ldquo;Send feedback&rdquo;).
Or you could take your laundry somewhere else.</p>
<h2 id="conclusion">Conclusion</h2>
<p>First, if you are a developer, don&rsquo;t write sensitive information to logs.
On Android, by writing logs you are sending information outside of the app&rsquo;s sandbox.
As I have shown, tens of preinstalled apps can read logs.
It is an easy issue to fix and avoid.
But it also easily slips through PR reviews, and there are two common pitfalls for developers.</p>
<p>Second, if you are a business, have a security contact and a security.txt.
Even if you have never received a report before. Some day you will.
And even if your main business is not selling software, you still need to have a security contact.</p>
<h2 id="heading"></h2>
<p>P.S.: The <code>Expires</code> field in the security.txt is <a href="https://datatracker.ietf.org/doc/html/rfc9116#name-expires">required</a>.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>App 1 did not have a security.txt when I found this issue in June 2022. Now in May 2023 they have one.
App 2 still doesn&rsquo;t.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>There is also another app called <a href="https://play.google.com/store/apps/details?id=com.greenwald.pay.circuit">&ldquo;Circuit Laundry Plus&rdquo;</a>.
I haven&rsquo;t tested it.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Cryptographic Parameters and Bits of Security: Classical and Quantum</title><link>https://thore.io/posts/2023/02/cryptographic-parameters-and-bits-of-security-classical-and-quantum/</link><pubDate>Sun, 12 Feb 2023 20:00:00 +0000</pubDate><guid>https://thore.io/posts/2023/02/cryptographic-parameters-and-bits-of-security-classical-and-quantum/</guid><description>&lt;p>Did you ever wonder how the parameter size of cryptographic algorithms relates to their security strength?
Or how the security strength changes with quantum computers?
Or do you keep forgetting when the bits-of-security are equal to the parameter size, and when they are halved?&lt;/p>
&lt;p>You&amp;rsquo;re in luck! Here are the tables:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Security Stength&lt;/th>
&lt;th>Symmetric Crypto&lt;/th>
&lt;th>Finite Field Crypto (DSA, DH)&lt;/th>
&lt;th>Integer Factorisation Crypto (RSA)&lt;/th>
&lt;th>Elliptic Curve Crypto&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>80&lt;/td>
&lt;td>-&lt;/td>
&lt;td>1024 (public key \( g^x \)) / 160 (private key \( x \))&lt;/td>
&lt;td>RSA-1024&lt;/td>
&lt;td>160&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>112&lt;/td>
&lt;td>-&lt;/td>
&lt;td>2048 / 224&lt;/td>
&lt;td>RSA-2048&lt;/td>
&lt;td>224&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>128&lt;/td>
&lt;td>AES-128&lt;/td>
&lt;td>3072 / 256&lt;/td>
&lt;td>RSA-3072&lt;/td>
&lt;td>256&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>192&lt;/td>
&lt;td>AES-192&lt;/td>
&lt;td>7860 / 384&lt;/td>
&lt;td>RSA-7680&lt;/td>
&lt;td>384&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>256&lt;/td>
&lt;td>AES-256&lt;/td>
&lt;td>15360 / 512&lt;/td>
&lt;td>RSA-15360&lt;/td>
&lt;td>512&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Table 1: Taken from NIST&amp;rsquo;s &amp;ldquo;Recommendation for Key Management&amp;rdquo; (&lt;a href="https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final">SP 800-57 Part 1&lt;/a>, Section 5.6.1.1).
You can find similar tables on &lt;a href="https://www.keylength.com/en/4/">keylength.com&lt;/a>.&lt;/p></description><content type="html"><![CDATA[<p>Did you ever wonder how the parameter size of cryptographic algorithms relates to their security strength?
Or how the security strength changes with quantum computers?
Or do you keep forgetting when the bits-of-security are equal to the parameter size, and when they are halved?</p>
<p>You&rsquo;re in luck! Here are the tables:</p>
<table>
  <thead>
      <tr>
          <th>Security Stength</th>
          <th>Symmetric Crypto</th>
          <th>Finite Field Crypto (DSA, DH)</th>
          <th>Integer Factorisation Crypto (RSA)</th>
          <th>Elliptic Curve Crypto</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>80</td>
          <td>-</td>
          <td>1024 (public key \( g^x \)) / 160 (private key \( x \))</td>
          <td>RSA-1024</td>
          <td>160</td>
      </tr>
      <tr>
          <td>112</td>
          <td>-</td>
          <td>2048 / 224</td>
          <td>RSA-2048</td>
          <td>224</td>
      </tr>
      <tr>
          <td>128</td>
          <td>AES-128</td>
          <td>3072 / 256</td>
          <td>RSA-3072</td>
          <td>256</td>
      </tr>
      <tr>
          <td>192</td>
          <td>AES-192</td>
          <td>7860 / 384</td>
          <td>RSA-7680</td>
          <td>384</td>
      </tr>
      <tr>
          <td>256</td>
          <td>AES-256</td>
          <td>15360 / 512</td>
          <td>RSA-15360</td>
          <td>512</td>
      </tr>
  </tbody>
</table>
<p>Table 1: Taken from NIST&rsquo;s &ldquo;Recommendation for Key Management&rdquo; (<a href="https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final">SP 800-57 Part 1</a>, Section 5.6.1.1).
You can find similar tables on <a href="https://www.keylength.com/en/4/">keylength.com</a>.</p>
<table>
  <thead>
      <tr>
          <th>Algorithm</th>
          <th>Parameter Size [bits]</th>
          <th>Bits of Security (classically)</th>
          <th>Bits of Security (quantum)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>AES-128</td>
          <td>128</td>
          <td>128</td>
          <td>64 = none</td>
      </tr>
      <tr>
          <td>AES-256</td>
          <td>256</td>
          <td>256</td>
          <td>128</td>
      </tr>
      <tr>
          <td>RSA-2048</td>
          <td>2048</td>
          <td>112</td>
          <td>-</td>
      </tr>
      <tr>
          <td>RSA-3072</td>
          <td>3072</td>
          <td>128</td>
          <td>-</td>
      </tr>
      <tr>
          <td>P-256</td>
          <td>256</td>
          <td>128</td>
          <td>-</td>
      </tr>
      <tr>
          <td>P-384</td>
          <td>384</td>
          <td>192</td>
          <td>-</td>
      </tr>
      <tr>
          <td>Curve25519</td>
          <td>256</td>
          <td>128</td>
          <td>-</td>
      </tr>
      <tr>
          <td>Curve448</td>
          <td>448</td>
          <td>224</td>
          <td>-</td>
      </tr>
      <tr>
          <td>SHA-256</td>
          <td>256</td>
          <td>256 (preimage) / 128 (collision)</td>
          <td>128 / 128</td>
      </tr>
      <tr>
          <td>SHA-384</td>
          <td>384</td>
          <td>384 / 192</td>
          <td>192 / 192</td>
      </tr>
      <tr>
          <td>HMAC-SHA256</td>
          <td>256</td>
          <td>256</td>
          <td>128</td>
      </tr>
      <tr>
          <td>HMAC-SHA384</td>
          <td>384</td>
          <td>384</td>
          <td>192</td>
      </tr>
  </tbody>
</table>
<p>Table 2: Assembled by me.</p>
<p>My motivation for collecting this information and writing this post is two-fold:</p>
<ol>
<li>To answer the &ldquo;why&rdquo;: Where do these numbers come from?
You can find the NIST table quoted a lot around the internet.
But I always missed a concise summary of <em>why</em> the parameter sizes
and the security strengths relate in this way.</li>
<li>To cover quantum: All tables I found only contained the security strengths in the classical case.</li>
</ol>
<p>Point 2 is already solved by Table 2 above.
For the remainder of this post I will address point 1 and give an explanation of the &ldquo;why&rdquo;.
That is, I will explain why Table 2 has these values.</p>
<p>This post is not meant to explain all areas in depth.
Rather, it is intended as a quick, summarising overview that pulls all the concepts together in one place.
It assumes prior knowledge, refreshing only the points that are important in this context.</p>
<p>THIS POST DOES NOT CONSTITUTE CRYPTOGRAPHIC ADVICE.
DO NOT TRUST A RANDOM PERSON ON THE INTERNET.
YOU SHOULD SEEK PROPER CRYPTOGRAPHIC COUNSEL INSTEAD.</p>
<h2 id="preliminaries">Preliminaries</h2>
<p>Let&rsquo;s start with some background.
We will need this when we discuss for each type of algorithm how its parameter sizes relate
to its classical and quantum strength.</p>
<h3 id="representing-numbers">Representing Numbers</h3>
<p>We represent integers \( \leq 2^n = N \) as bit strings of length \( n \).
We use capital \( N \) for integers, and lower case \( n \) for bit string lengths.</p>
<p>Note that \( \frac{2^n}{2} = 2^{n-1} = \mathcal{O}(2^n) \).
Also note that \( \sqrt{2^n} = 2^{n/2} \).</p>
<h3 id="parameter-size">Parameter Size</h3>
<p>The &ldquo;parameter size&rdquo; is what we can tune about an algorithm to achieve different security strengths.</p>
<p>In most cases the parameter size is the key size. But not always!
For example, for unkeyed hash functions (such as SHA-256) the parameter size is the size of the output.</p>
<h3 id="security-strength-bits-of-security">Security Strength: Bits of Security</h3>
<p>We measure the &ldquo;strength&rdquo; of an algorithm in &ldquo;bits of security&rdquo;, or short &ldquo;bits&rdquo;.
An algorithm has &ldquo;\( n \) bits of security&rdquo; if it takes \( \mathcal{O}(2^n) \) operations to break it.</p>
<p>Usually, an &ldquo;operation&rdquo; is equal to one algorithm invocation and one comparison.
For example, one invocation of SHA-256 and one comparison of the output against a target value.</p>
<p>Ideally, an algorithm can only be &ldquo;broken&rdquo; by brute-forcing, i.e. by trying all possible values.
For keys of length \( n \) there are \( 2^n \) many possible keys, so an average brute-force search succeeds after
\( \frac{2^n}{2} \) attempts.
But as noted above, this is still \( \mathcal{O}(2^n) \).
So instead of &ldquo;127 bits&rdquo; we say &ldquo;128 bits&rdquo;.
Thus you can read all the bit-of-security values in the tables above with a big-\( \mathcal{O} \) in mind.</p>
<h3 id="classical-discrete-logarithm">Classical: Discrete Logarithm</h3>
<p>The Discrete Logarithm Problem is that given two numbers \( a, b \),
find a number \( x \) such that \( b^x = a \).
That is, find \( x = \log_b a \).
We work in a cyclic group \( G \) of order \( N \) (i.e. there are \( N \) group elements).
For cryptography \( N \) is usually prime.</p>
<p>There exist classical <a href="https://en.wikipedia.org/wiki/Discrete_logarithm#Algorithms">algorithms</a> such as Pollard&rsquo;s rho
that solve the DLP in <a href="https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm_for_logarithms#Complexity">time</a>
\( \mathcal{O}(\sqrt{N}) = \mathcal{O}(2^{n/2}) \).</p>
<p>Hence classically, for parameter size \( n \) bits we only get \( n/2 \) bits of security.</p>
<h3 id="quantum-integer-factorisation-and-discrete-logarithms----shors-algorithm">Quantum: Integer Factorisation and Discrete Logarithms &ndash; Shor&rsquo;s Algorithm</h3>
<p>Shor&rsquo;s <a href="https://en.wikipedia.org/wiki/Shor%27s_algorithm">period finding algorithm</a>
can be adapted to solve both the Discrete Logarithm Problem and Integer Factorisation Problem.
It is &ldquo;efficient&rdquo;, meaning that it runs in polynomial time.</p>
<p>Hence for quantum, for parameter size \( n \) bits we get \( \approx 0 \) bits of security.</p>
<h3 id="quantum-brute-force-search----grovers-algorithm">Quantum: Brute-Force Search &ndash; Grover&rsquo;s Algorithm</h3>
<p><a href="https://en.wikipedia.org/wiki/Grover%27s_algorithm">Grover&rsquo;s algorithm</a> speeds up unstructured search
from \( \mathcal{O}(N) \) classically to \( \mathcal{O}(\sqrt{N}) \).</p>
<p>Hence for quantum, for parameter size \( n \) bits we only get \( n/2 \) bits of security.</p>
<h3 id="hashing-pre-images-collisions-and-the-birthday-attack">Hashing: Pre-images, Collisions, and the Birthday Attack</h3>
<p>For pre-image resistance, the problem is that given an output \( y \) to find an input \( x \) such that \( x = h(y) \).
Both classically and quantum the best known approach is brute-force search.</p>
<p>For collision resistance, the problem is to find two arbitrary inputs \( x_1, x_2 \) such that \( h(x_1) = h(x_2) \).
Classically, this can be solved with a <a href="https://en.wikipedia.org/wiki/Birthday_attack">birthday attack</a>
in time \( \mathcal{O}(\sqrt{N}) = \mathcal{O}(2^{n/2}) \).
For quantum, there is a <a href="https://arxiv.org/abs/quant-ph/9705002">paper</a> claiming to be able to find collisions
in time \( \mathcal{O}(\sqrt[3]{N}) = \mathcal{O}(2^{n/3}) \).
However, Daniel Bernstein <a href="https://cr.yp.to/hash/collisioncost-20090823.pdf">vigorously disagrees</a>, concluding that the best practical
collision attack even with quantum is still in time \( \mathcal{O}(2^{n/2}) \).</p>
<h2 id="tying-it-all-together">Tying It All Together</h2>
<p>With the above in mind, we obtain the following relations that describe how
the security strength \( S \) varies with the parameter size \( n \).</p>
<ul>
<li>Symmetric crypto (AES, HMAC):
<ul>
<li>Random symmetric key, breakable by brute force search.</li>
<li>\( S = n \) classically.</li>
<li>\( S = n/2 \) quantum (Grover&rsquo;s).</li>
</ul>
</li>
<li>Asymmetric crypto (RSA, DH, ECC):
<ul>
<li>Discrete Logarithm and Integer Factorisation.</li>
<li>\( S = n/2 \) classically (Pollard&rsquo;s rho and others).</li>
<li>\( S \approx 0 \) quantum (Shor&rsquo;s).</li>
</ul>
</li>
<li>Hashing:
<ul>
<li>Pre-image resistance:
<ul>
<li>\( S = n \) classically.</li>
<li>\( S = n/2 \) quantum (Grover&rsquo;s).</li>
</ul>
</li>
<li>Collision-resistance:
<ul>
<li>\( S = n/2 \) classically (Birthday attack).</li>
<li>\( S = n/2 \) OR \( S = n/3 \) quantum (Bernstein OR Brassard, Høyer, and Tapp).</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Note that just like the value &ldquo;128&rdquo; in the security strength is an approximation, the \( = \) is also an approximation.</p>
<p>Also note that these relations and the values in Table 2 are upper bounds.
They only represent the security strength under generic attacks.
There can be algorithm-specific attacks.
For example, SHA-1 has an output size of 160 bit, which would imply 80 bit security against generic collision attacks.
However, the SHAttered attack <a href="https://shattered.io/static/shattered.pdf">estimates</a> that it only needs \( \approx 2^{64} \) operations.</p>
<h2 id="what-security-strength-should-you-target">What Security Strength Should You Target?</h2>
<p>For a long time, 128 bit was commonly recommended.
However, the NSA&rsquo;s latest guidance in its <a href="https://en.wikipedia.org/wiki/Commercial_National_Security_Algorithm_Suite">Commercial National Security Algorithm Suite</a>
is at least <em>192 bit</em> (except for RSA-3072, which is 128 bit).</p>
<h2 id="conclusion">Conclusion</h2>
<p>We started this post with concrete values: a table of common cryptographic algorithms, their parameter size, and
their security strength in both the classical and the quantum setting.</p>
<p>We ended this post with the formal relations that relate the parameter size to the security strength.</p>
<p>Inbetween, we refreshed our knowledge to understand the <em>why</em>. We explained where these relations come from.</p>
<p>I hope this helps as a quick reference to look up the values, the relations, and the derivation of the relations.</p>
]]></content></item><item><title>Home Office Killed My Laptop Battery</title><link>https://thore.io/posts/2022/12/home-office-killed-my-laptop-battery/</link><pubDate>Sun, 04 Dec 2022 14:00:00 +0000</pubDate><guid>https://thore.io/posts/2022/12/home-office-killed-my-laptop-battery/</guid><description>&lt;p>This post is a collection of things I learned about batteries.
This is my adventure diving into why doing too much home office killed my laptop battery,
and my journey replacing it.
It is not necessarily data-driven, but at least data-intuited.&lt;/p>
&lt;h2 id="motivation">Motivation&lt;/h2>
&lt;p>Before the pandemic, my laptop (a ThinkPad) was on and off the charger.
I was walking around university, sitting in lectures, going to the library.
I would charge my laptop when the battery was getting low, and then disconnect the charger again.&lt;/p></description><content type="html"><![CDATA[<p>This post is a collection of things I learned about batteries.
This is my adventure diving into why doing too much home office killed my laptop battery,
and my journey replacing it.
It is not necessarily data-driven, but at least data-intuited.</p>
<h2 id="motivation">Motivation</h2>
<p>Before the pandemic, my laptop (a ThinkPad) was on and off the charger.
I was walking around university, sitting in lectures, going to the library.
I would charge my laptop when the battery was getting low, and then disconnect the charger again.</p>
<p>During the pandemic, my laptop was always sitting on my desk, connected to a monitor,
a docking station &mdash; and a charger.
It spent several months at full charge.</p>
<p>As of early 2020, my laptop was 3 years old and the battery capacity still at 85%.
Over the course of the next 12 months, its capacity dropped to 65%.
With a design capacity of 57 Wh, this is a drop from 48 Wh to 37 Wh.
At a power consumption of 5 W, this is 2 hours less runtime!
<strong>And it is a drop by 20% over 1 year, versus a drop of 15% over 3 years.</strong></p>
<figure><img src="/img/battery-capacity-graph.jpg"
    alt="Graph of Battery Capacity Over Time"><figcaption>
      <p>Graph of Battery Capacity Over Time</p>
    </figcaption>
</figure>

<h2 id="factors-impacting-battery-life">Factors Impacting Battery Life</h2>
<p>Why did this happen? What can I do to prolong the life of my laptop battery?</p>
<p><a href="https://support.lenovo.com/uk/en/solutions/ht078208-how-can-i-increase-battery-life-thinkpad-and-lenovo-vbke-series-notebooks">According to</a>
Lenovo, battery life is a function of:</p>
<ul>
<li>age</li>
<li>number of charge cycles</li>
<li>amount of time at full charge</li>
<li>high temperature</li>
</ul>
<p>In other words: anything that causes physical stress to the battery/electrons/chemicals decreases battery life.
The battery &ldquo;wears out&rdquo; and is no longer able to hold the same amount of charge.</p>
<p>The &ldquo;amount of time at full charge&rdquo; killed my laptop battery.
Sitting at 100% for a large portion of 2020 was what accelerated its death so significantly.</p>
<p>The &ldquo;high temperature&rdquo; killed my phone battery. This is a different story.
But keep this in mind next summer when it is over 30°C!</p>
<h3 id="setting-an-upper-charging-limit">Setting an upper charging limit</h3>
<p>To protect my battery, I needed to prevent it from being at 100% for long periods of time (read: days non-stop).</p>
<p>To do this, I wanted to configure the battery to only charge up to a maximum value.
One option are command-line tools, such as <a href="https://linrunner.de/tlp/settings/battery.html">TLP</a> (more details below).
Another option are graphical tools, such as KDE Plasma&rsquo;s system settings:</p>
<figure><img src="/img/battery-kde-plasma.png"
    alt="Setting the charge limits in KDE Plasma 5.24 LTS"><figcaption>
      <p>Setting the charge limits in KDE Plasma 5.24 LTS</p>
    </figcaption>
</figure>

<p>Personally, I have set the &ldquo;value to start charging at&rdquo; and the &ldquo;value to stop charging at&rdquo; to 75% and 80% respectively.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>
They seem like a reasonable tradeoff, while still having a nearly-full battery for when I pack up and leave my desk.
75% and 80% are also the default values that TLP sets.
And Lenovo <a href="https://support.lenovo.com/ch/en/solutions/ht509084">agrees</a>:
&ldquo;For systems which are always connected to an AC power source, Lenovo recommends setting the upper charge limit to 80% or less.&rdquo;</p>
<p>Now when my laptop is at the docking station for 2 days, it sits their at 80% instead of at 100%.</p>
<p>The added benefit is that when it sits there at 80% and I run compute-heavy tasks,
the 20 or so watt come directly from the charger.
It does not impact the battery, i.e. it is saving me some charging cycles (see below).</p>
<h2 id="reading-battery-statistics">Reading Battery Statistics</h2>
<p>The Linux kernel reads battery statistics from the hardware and
<a href="https://www.kernel.org/doc/html/latest/power/power_supply_class.html">exposes them</a>.
To read the current power consumption in milli-Watt and the amount of full charging cycles:</p>
<pre><code>cat /sys/class/power_supply/BAT0/power_now
cat /sys/class/power_supply/BAT0/cycle_count
</code></pre>
<p>For the former I made myself a bash alias: <code>alias watt=&quot;cat /sys/class/power_supply/BAT0/power_now&quot;</code>.
I look at <code>watt</code> regularly to get an intuition of how my laptop is doing.</p>
<p>I found the following rule-of-thumb numbers for my system (4-core i5-7200U @ 2.5 GHz):</p>
<table>
  <thead>
      <tr>
          <th>Task</th>
          <th>Power consumption [Watt]</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Idle (or slowly reading through a PDF)</td>
          <td>5 W</td>
      </tr>
      <tr>
          <td>Normal usage (browsing, typing, switching applications)</td>
          <td>5.5 - 6 W</td>
      </tr>
      <tr>
          <td>Streaming a movie</td>
          <td>up to 10 W</td>
      </tr>
      <tr>
          <td>Compiling on all 4 cores</td>
          <td>20 W</td>
      </tr>
  </tbody>
</table>
<p>I also found that screen brightness is not a significant factor (on my laptop!).
At least, it is barely noticeable in the <code>watt</code> readings.
Instead of forcing brightness down to 10% to save power, I now have it at a comfortable 30% most of the time.</p>
<p>For the <code>cycle_count</code>, note that this is the number of <a href="https://www.apple.com/batteries/why-lithium-ion/">full cycles</a>.
I have had my new battery for 8 months (= 240 days) now. Despite using it daily, I am only at 60 cycles.
One contributing factor is that my laptop now spends weekends and home-office days on my desk at the charger.</p>
<p>If you like graphs, KDE Plasma also ships with an Energy Monitor that shows you the historical power consumption:</p>
<figure><img src="/img/battery-energy-monitor.png"
    alt="KDE Energy Monitor"><figcaption>
      <p>KDE Energy Monitor</p>
    </figcaption>
</figure>

<h3 id="using-tlp-to-read-statistics-and-set-thresholds">Using TLP to read statistics and set thresholds</h3>
<p><a href="https://linrunner.de/tlp/">TLP</a> is a command-line tool that can read battery statistics
and configure various settings, such as charging thresholds.
In this section I will give a short primer on how I use TLP.</p>
<p>First, <a href="https://linrunner.de/tlp/installation/index.html">install it</a>.</p>
<p>Now you can view the battery statistics:</p>
<pre><code class="language-bash">$ sudo tlp-stat --battery
--- TLP 1.5.0 --------------------------------------------

+++ Battery Care
Plugin: thinkpad
Supported features: charge thresholds, recalibration
Driver usage:
* natacpi (thinkpad_acpi) = active (charge thresholds)
* tpacpi-bat (acpi_call)  = active (recalibration)
Parameter value ranges:
* START_CHARGE_THRESH_BAT0/1:  0(off)..96(default)..99
* STOP_CHARGE_THRESH_BAT0/1:   1..100(default)

+++ ThinkPad Battery Status: BAT0 (Main / Internal)
/sys/class/power_supply/BAT0/manufacturer                   = LGC
/sys/class/power_supply/BAT0/model_name                     = 01AV494
/sys/class/power_supply/BAT0/cycle_count                    =     60
/sys/class/power_supply/BAT0/energy_full_design             =  57000 [mWh]
/sys/class/power_supply/BAT0/energy_full                    =  59180 [mWh]
/sys/class/power_supply/BAT0/energy_now                     =  30780 [mWh]
/sys/class/power_supply/BAT0/power_now                      =   4883 [mW]
/sys/class/power_supply/BAT0/status                         = Discharging

/sys/class/power_supply/BAT0/charge_control_start_threshold =     75 [%]
/sys/class/power_supply/BAT0/charge_control_end_threshold   =     80 [%]
tpacpi-bat.BAT0.forceDischarge                              =      0

Charge                                                      =   52.0 [%]
Capacity                                                    =  103.8 [%]
</code></pre>
<p>As mentioned above, you can also obtain the <code>power_supply</code> values by <code>cat</code>-ing the files directly
(this is my <code>watt</code> shortcut).
The <code>tlp-stat</code> command just nicely aggregates them.</p>
<p>Next, configure the charging thesholds.
To do this, create a file <code>/etc/tlp.d/01-charge-thresholds.conf</code> with the following content: <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<pre><code>START_CHARGE_THRESH_BAT0=75
STOP_CHARGE_THRESH_BAT0=80
</code></pre>
<p>Make sure this file has the correct owner and correct permissions:</p>
<pre><code class="language-bash">$ sudo chown root:root /etc/tlp.d/01-charge-thresholds.conf
$ sudo chmod 644 /etc/tlp.d/01-charge-thresholds.conf
</code></pre>
<p>Then apply the TLP config by running <code>sudo tlp start</code>.
You should now see these changes when you run <code>sudo tlp-stat -b</code>.</p>
<p>What if you have a trip coming up, and you want to temporarily charge to 100%?
Instead of messing with the config, just connect your charger and run:</p>
<pre><code class="language-bash">$ sudo tlp fullcharge
Setting temporary charge thresholds for BAT0:
  stop  = 100
  start =  96
Charging starts now, keep AC connected.
</code></pre>
<p><code>sudo tlp-stat -b</code> shows you the updated thresholds.
Simply run <code>sudo tlp start</code> to revert back to the settings in your config file.</p>
<p>Note: The command <code>tlp start</code> takes the value from the config file, and writes them
to the embedded controller (EC) via ACPI.
<code>tlp fullcharge</code> does the same, but with the default values 96 and 100.
The EC is a piece of hardware that controls the charging process.
This way, charging will stop at 80% even if the laptop is turned off.
But this also means that you have to manually run <code>start</code> or <code>fullcharge</code> for your changes to take effect!</p>
<p>For more information, read <a href="https://linrunner.de/tlp/usage/index.html">the docs</a>,
the <a href="https://linrunner.de/tlp/faq/battery.html">FAQ</a> or the manpage (<code>man tlp</code>).</p>
<h2 id="replacing-the-battery">Replacing the Battery</h2>
<p>Now I knew how to slow down battery aging, and how to monitor the battery.
But what if the battery is already dead?</p>
<p>Disclaimer: repeat this at your own risk.
In my case, my laptop was 4 years old, so the warranty was void anyway.</p>
<p>When my old battery reached 65% capacity, I decided to replace it.
Only having 6 hours of runtime was getting too impractical.</p>
<p>I ordered a replacement battery on AliExpress for 35 €, including shipping.
For comparison: official replacement batteries cost 100-150 €.</p>
<p>Replacing the battery requires only a few screw drivers.
I recommend searching YouTube for <em>any</em> replacement video (even if it is not your exact model).
It is a good way to get a rough view of what to expect, and to build confidence before you open up your own laptop.</p>
<p>Here are the steps for my ThinkPads (others should be similar):</p>
<ol>
<li>Disconnect the charger.</li>
<li>Discharge the battery to 20-30%. Less electrical charge reduces the risk if something goes badly wrong.</li>
<li>Touch some grounded metal to ensure you are grounded as well.
Prevent <a href="https://www.ifixit.com/News/63909/what-is-esd">electrostatic discharge (ESD)</a>.</li>
<li>Shut down the laptop and reboot into the BIOS.</li>
<li>In the BIOS, go to Config &gt; Power &gt; Disable Built-In Battery. Then click Enter.
(This ensures the power is cut and the battery is fully disconnected from the other electronics inside the laptop.
You won&rsquo;t be able to turn the laptop on again without a charger.)</li>
<li>Close the lid and turn the laptop upside down.</li>
<li>Remove the screws that are holding the back plate and remove the back plate.</li>
<li>Disconnect the internal battery cable.</li>
<li>Remove the screws that fix the battery in-place.</li>
<li>Take the old battery out, and put the new one in.</li>
<li>Screw the new battery in place. Then re-connect the internal battery cable.</li>
<li>Close the back-plate and screw it tight.</li>
<li>Connect a charger and boot your laptop.</li>
<li>Done! Proceed to calibrating the battery.</li>
</ol>
<figure><img src="/img/battery-bios.jpg"
    alt="Disabling the battery in the BIOS"><figcaption>
      <p>Disabling the battery in the BIOS</p>
    </figcaption>
</figure>

<h3 id="calibrating-the-new-battery">Calibrating the new battery</h3>
<p>After I installed the new battery, it was time to calibrate it.
Calibration means pushing the battery to both the low and the high extreme.
This helps the battery controller figure out what level of charge constitutes
&ldquo;full charge&rdquo; and &ldquo;empty charge&rdquo;.</p>
<p>This changes over the lifetime of the battery, because as the battery ages it is able to hold less charge.
The controller remembered a lower charge value as &ldquo;full&rdquo; from the old battery.
Calibrating it means teaching it that &ldquo;full&rdquo; is now at a higher charge.</p>
<p>This paper card that iFixit ships with phone replacement batteries sums up the steps:</p>


<img src="/img/battery-calibration.jpg"   width="50%"  class="center" />

<h3 id="determining-the-quality-of-the-replacement-battery">Determining the Quality of the Replacement Battery</h3>
<p>35 € for a laptop battery is rather cheap. Sure, I did some diligence.
I compared batteries on AliExpress. I read through comments and reviews.
I looked at clues indicating seller reputation and quality.
But it is still a guessing game.
With seller and buyer so far away, there is little accountability.</p>
<p>How can I verify that the cheap battery is not of low quality?
What if the battery reports a higher capacity than it actually has?
Can I trust the hardware readings?
After all, the &ldquo;Last full charge = 59.18 Wh&rdquo; (see Energy Monitor screenshot above)
seems strange given that &ldquo;Design capacity = 57 Wh&rdquo;.</p>
<p>It turns out that batteries are <a href="https://en.wikipedia.org/wiki/Smart_battery">smart</a>. <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>
They have a built-in chip that reports the voltage, current, etc to the laptop.
This means that the laptop relies on the values measured and reported by the battery.</p>
<p>This also means that a scam battery can report wrong values.
For example, it can report a larger capacity than it actually has.
I know that this happens with smartphones:
the Android system settings on phones that are cheap &ldquo;offers&rdquo; on AliExpress claims that
the phone has 16 GB RAM but in reality it only has 0.5 GB RAM!
(<a href="https://www.heise.de/ratgeber/Wie-Betrueger-Smartphones-faelschen-und-seit-Jahren-damit-durchkommen-6208337.html">German news article</a>)</p>
<p>Without taking the battery apart and doing more analysis, I just have to trust the battery.</p>
<p>One data point that I can control, though, is the overall runtime.
With a nominal capacity of 57 Wh and a power consumption of 5.5 W, the new battery should last about 10 hours.
So I measured how long the new battery would last during normal laptop usage.
And indeed: the new battery got me back to running an entire day at university without having to charge.
This has held up so far over the past 8 months.
Because of this, I now also trust the <code>watt</code> readings &ndash; they vary with my laptop usage
patterns in the way I expect them to.</p>
<p>I assume the 59.18 &gt; 57 is either due to the uncertainty in the physical measurement/calculation.
Or the factory capacity really is too large, to account for manufacturing uncertainties,
that is, to prevent returns and angry customers.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this post I explained what factors impact the lifespan of a modern laptop battery
(age, number of charge cycles, amount of time at full charge, high temperature).
Based on this, I also explained what you can do to prolong the lifespan (don&rsquo;t keep it at 100% for long times).
I also described how you can view battery statistics (use TLP).
Finally, I showed how I replaced my laptop battery.</p>
<p>Note that I only focused on ThinkPads running Linux.
Please <a href="/about/">let me know</a> if you find similar ways to set the charging thresholds on MacOS.
There might be, but I haven&rsquo;t researched it.
Apple has <a href="https://support.apple.com/en-us/HT210512">Optimised Charging</a>,
but this seems to only work when charging overnight.
It is not a solution if you keep your MacBook connected to your monitor via USB-C-with-power-delivery
during an entire workday &mdash; it will charge to 100%.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>The lower bound ensures that the battery does not constantly fluctate between &ldquo;discharging&rdquo; and &ldquo;charging&rdquo;.
This would send the electrons back and forth, also wearing out the battery.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>You <em>could</em> also put these lines in <code>/etc/tlp.conf</code>.
But I prefer leaving <code>tlp.conf</code> untouched, and instead put all my values
into the <code>tlp.d</code> directory.
This way, it is easier to distinguish what are TLP&rsquo;s factory settings
and what are my settings.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Wikipedia has more information on <a href="https://en.wikipedia.org/wiki/Battery_management_system">battery management systems</a>.
I originally learnt about the Smart Battery System (SBS) standard from
<a href="https://zmatt.net/unlocking-my-lenovo-laptop-part-1/">this blog post</a> about reversing
the embedded controller firmware (the controller in the ThinkPad, not in the battery).
That blog post also references <a href="https://media.blackhat.com/bh-us-11/Miller/BH_US_11_Miller_Battery_Firmware_Public_WP.pdf">this Black Hat paper</a>
on reversing the battery firmware, which is an equally interesting read.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>FIDO's Future</title><link>https://thore.io/posts/2022/07/fidos-future/</link><pubDate>Sun, 10 Jul 2022 14:00:00 +0000</pubDate><guid>https://thore.io/posts/2022/07/fidos-future/</guid><description>&lt;p>In honor of World Password Day on May 5th the FIDO Alliance, together with
&lt;a href="https://blog.google/technology/safety-security/one-step-closer-to-a-passwordless-future/">Google&lt;/a>,
&lt;a href="https://www.apple.com/newsroom/2022/05/apple-google-and-microsoft-commit-to-expanded-support-for-fido-standard/">Apple&lt;/a> and
&lt;a href="https://techcommunity.microsoft.com/t5/azure-active-directory-identity/expansion-of-fido-standard-and-new-updates-for-microsoft/ba-p/3290633">Microsoft&lt;/a>,
&lt;a href="https://fidoalliance.org/apple-google-and-microsoft-commit-to-expanded-support-for-fido-standard-to-accelerate-availability-of-passwordless-sign-ins/">announced&lt;/a>
&amp;ldquo;plans to expand support for a common passwordless sign-in standard&amp;rdquo;.
In other words, they (once again) publicly committed to FIDO.&lt;/p>
&lt;p>This is not new. All three companies have long supported FIDO to some extent.
Both Google Chrome and
&lt;a href="https://www.microsoft.com/en-us/microsoft-365/blog/2018/11/20/sign-in-to-your-microsoft-account-without-a-password-using-windows-hello-or-a-security-key/">Microsoft Edge&lt;/a>
have had WebAuthn and CTAP2 support for a few years now.
iOS also has WebAuthn support &lt;a href="https://twitter.com/rmondello/status/1387073010369056769">since 14.5&lt;/a>.&lt;/p></description><content type="html"><![CDATA[<p>In honor of World Password Day on May 5th the FIDO Alliance, together with
<a href="https://blog.google/technology/safety-security/one-step-closer-to-a-passwordless-future/">Google</a>,
<a href="https://www.apple.com/newsroom/2022/05/apple-google-and-microsoft-commit-to-expanded-support-for-fido-standard/">Apple</a> and
<a href="https://techcommunity.microsoft.com/t5/azure-active-directory-identity/expansion-of-fido-standard-and-new-updates-for-microsoft/ba-p/3290633">Microsoft</a>,
<a href="https://fidoalliance.org/apple-google-and-microsoft-commit-to-expanded-support-for-fido-standard-to-accelerate-availability-of-passwordless-sign-ins/">announced</a>
&ldquo;plans to expand support for a common passwordless sign-in standard&rdquo;.
In other words, they (once again) publicly committed to FIDO.</p>
<p>This is not new. All three companies have long supported FIDO to some extent.
Both Google Chrome and
<a href="https://www.microsoft.com/en-us/microsoft-365/blog/2018/11/20/sign-in-to-your-microsoft-account-without-a-password-using-windows-hello-or-a-security-key/">Microsoft Edge</a>
have had WebAuthn and CTAP2 support for a few years now.
iOS also has WebAuthn support <a href="https://twitter.com/rmondello/status/1387073010369056769">since 14.5</a>.</p>
<p>The two hot new things are:</p>
<ol>
<li>smartphones as roaming authenticators via Bluetooth, and</li>
<li>multi-device credentials (&ldquo;passkeys&rdquo;), via cloud sync.
<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></li>
</ol>
<p>The announcement has brought some renewed attention to FIDO.
Reason enough to write down my thoughts on the current state of the FIDO ecosystem!</p>
<p>First, I will give a short introduction/refresher about FIDO and its concepts.
Then, I will go into what I think is great about FIDO, as well as some of the problems that I see.</p>
<h2 id="background">Background</h2>
<p>Back in the early days, there was the <em>password</em>.
Unfortunately, people took that too literally and chose words like &ldquo;password&rdquo; or &ldquo;qwerty&rdquo;
(is that a word?) as their password.</p>
<p>In response to that (and recalling that good passwords should be long) we collectively decided
to call them <em>passphrase</em> instead (phrase, as in &ldquo;sentence&rdquo;).
Surely sentences are easier to remember!
But that didn&rsquo;t work either &ndash; people kept chosing &ldquo;letmein&rdquo;.</p>
<p>So now, &ldquo;the industry has introduced the term <em>passkeys</em>&rdquo;
(<a href="https://www.yubico.com/blog/making-sense-of-the-alphabet-soup-within-authentication-and-modern-mfa/">source</a>).
&ldquo;The industry&rdquo; meaning <a href="https://developer.apple.com/videos/play/wwdc2021/10106/">Apple</a>. <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>This is where FIDO comes in.
The basic idea behind FIDO is that instead of user-chosen passwords
we can use <em>public key cryptography</em> to authenticate users.
Hence the word &ldquo;passkey&rdquo;.</p>
<p>Here is how FIDO replaces the registration and login processes (roughly speaking):</p>
<ol>
<li>Upon registration, you create a public-private key pair.
The server provides you with a challenge, you sign, and &ndash; bam &ndash; you are now registered.
This is trust-on-first-use.</li>
<li>Upon authentication (aka login), the server again sends you a challenge.
You sign it, the server verifies it, and you are logged in!</li>
</ol>
<p>Basically, this is all that FIDO is. Public key crypto and a challenge-response protocol.</p>
<p>Unfortunately, you (the human) already have a hard time keeping 256-bit numbers in your head,
let alone computing ECDSA signatures with those numbers.
Luckily, all this cryptography is done for you by an <em>authenticator</em>.
There are two main types of authenticators:
First, <em>platform authenticators</em>, which are built into your device. Think Touch ID, Face ID, or Windows Hello.
Second, <em>roaming authenticators</em>, that can &ldquo;roam&rdquo; around, between multiple devices.
Think physical keys (YubiKeys, &hellip;).
They communicate with your computer via USB, NFC or BLE (using the
<a href="https://fidoalliance.org/specs/fido-v2.1-rd-20210309/fido-client-to-authenticator-protocol-v2.1-rd-20210309.html">CTAP protocol</a>). <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>In addition, there is <a href="https://www.w3.org/TR/webauthn/#webauthn-client">WebAuthn</a>.
WebAuthn is the API that websites or desktop/mobile apps interact with
(see the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API">Mozilla docs</a>).
The browser or OS then handle the communication with the authenticator
(either internally for platform authenticators, or via CTAP for roaming authenticators).</p>
<p>So overall, when people speak about FIDO or FIDO2, they mean WebAuthn and CTAP.
Here is my amateur drawing of an overview of FIDO:</p>
<figure><img src="/img/fido-overview.jpg"
    alt="FIDO: The protocols, the entities and devices involved"><figcaption>
      <p>FIDO: The protocols, the entities and devices involved</p>
    </figcaption>
</figure>

<p>For a deeper dive, see
<a href="https://www.yubico.com/blog/making-sense-of-the-alphabet-soup-within-authentication-and-modern-mfa/">this glossary</a>
and <a href="https://techcommunity.microsoft.com/t5/identity-standards-blog/all-about-fido2-ctap2-and-webauthn/ba-p/288910">this blog post</a>
as starting points for further reading.
<a href="https://www.imperialviolet.org">Adam Langley</a> also has multiple great posts on security keys.
<a href="https://developer.apple.com/videos/play/wwdc2022/10092/">Apple&rsquo;s WWDC22 video</a> nicely shows
how the UX flows can look like.</p>
<p>By the way, did you know that the <a href="https://www.swisspass.ch/new-swisspass?lang=en">new SwissPass</a>
can act as a roaming authenticator over NFC?
<em>Every public transport user in Switzerland now gets a security key included in their travelcard!</em>
Since it is FIDO-compliant, you can use it to log in to
<a href="https://sbbcffffs-community.sbb.ch/t5/Digitale-Services/Sicheres-Anmelden-im-Internet-mit-dem-neuen-SwissPass/ba-p/40398">any website</a>
that supports WebAuthn (on your phone, or on a laptop with an NFC reader).</p>
<h3 id="whats-new">What&rsquo;s new?</h3>
<p>One big UX problem for FIDO so far was that keys were bound to a single device.
That meant you would need to manually enroll two or more security keys (in case you loose one),
or manually enroll both your laptop and your phone.
What is more, you would need to manually do this for every single service where you used FIDO.
Just imagine switching phones, having to manually enrol your new phone in 10+ services again.</p>
<p>FIDO now proposed to solve this with multi-device keys.
Effectively it lifts the requirement that a key needs to be bound to a secure hardware element,
and allows it to be synced.
Notably, the standard does not impose any requirements (security or other) on the
nature of the sync service, and instead leaves it up to the vendor (e.g. iCloud).</p>
<p>Yes, this lowers the high bar that you get from hardware-bound secrets.
But for the average user reusing their passwords, it still a major step up.
In high-security contexts, you can continue to use device-bounds keys.</p>
<p>A second UX problem was the need to buy a security key.
Without such a roaming authenticator that can plug into a USB port, how would you log into a new device?</p>
<p>This second problem is solved by specifying how smartphones can act as roaming authenticators.
If you have a registered FIDO key on your smartphone, and you want to log into your email account
on a workstation in a public library, you can scan a QR count on the workstation.
The QR code contains information for local pairing over Bluetooth, thus proving proximity.
Then your phone and the workstation will run the normal CTAP protocol, with your phone acting
as a roaming authenticator. <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<p>These changes are exciting because they promise to clear the way
and remove the two main blockers of mainstream adoption.</p>
<hr>
<h2 id="the-good">The good</h2>
<p>The good: things that are great about FIDO and that we should do more of.</p>
<h4 id="no-shared-secrets">No shared secrets</h4>
<p>One thing I love about FIDO is that it eliminates shared secrets.
Instead, the secret (aka. private) key stays solely on the user&rsquo;s device.</p>
<p>The long history of password leaks has shown that it is difficult to protect the treasure chests
that password databases are.
It is much easier to break into a single central server, than millions of end-user devices.</p>
<p>By using public key crypto we also get phishing protection:
the secret never leaves the device, so there is nothing to be phished. <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<h4 id="no-human-generated-secrets">No human-generated secrets</h4>
<p>With FIDO we move away from mostly human-generated secrets and towards (pseudo-)randomly generated secrets.
Sure, we have mitigations like salting or special hash functions (scrypt, Argon2).
But in the end, they are still band-aids working around a low-entropy source.</p>
<h4 id="industry-push">Industry push</h4>
<p>Any technology can only make a difference if it has broad user adoption and
widespread software support.
Unfortunately, widespread adoption doesn&rsquo;t just happen.
Companies and people need to invest money and time.
And sometimes, you need peer pressure to make a step.</p>
<p>We have seen this before with biometrics on laptops:
Thinkpads have had fingerprint sensors for generations.
Yet only after Apple pushed Touch ID on MacBooks we started seeing improved software support
(imho because people know it from Apple and also demand it from other products).
Even on <a href="https://invent.kde.org/plasma/plasma-desktop/-/merge_requests/149">Linux</a>
fingerprint sensors are starting to &ldquo;just work&rdquo;!</p>
<p>With FIDO we can hope for the same effect.
Google, Apple, Microsoft and Mozilla laid the foundations over the past few years
(and took on the initial risk of investment!).</p>
<p>We are still far away from people being so used to passkeys that they
start demanding it from all products.
But with industry leaders committing and leading the way, we can get there.</p>
<hr>
<h2 id="the-bad">The bad</h2>
<p>The bad: things that I think are problematic about FIDO,
and that should be talked about more.</p>
<p>This is not to say we should throw FIDO out of the window and start anew!
In fact you will see that some problems are very familiar and keep coming up
in different areas of IT.</p>
<h4 id="tls-client-certificates-revisited">TLS client certificates revisited</h4>
<p>First of all, why are we inventing a new protocol?</p>
<p>FIDO and its use of public key cryptography inherently reminds me of TLS client certificates.
In both cases, the user/client holds a private key and uses it to authenticate itself to the server.</p>
<p>The only difference is <em>where</em> the server&rsquo;s <em>trust</em> in the private key comes from
(or rather, its trust in the binding from the key to a human).
In FIDO, it is trust-on-first use, i.e. the server remembers the (public key, identity)-binding.
In TLS client authentication on the other hand, the server derives its trust from the certificate chain
that is presented alongside the public key.</p>
<p>Other than that, the two are pretty similar:</p>
<ul>
<li>Both use public key crypto.</li>
<li>Both can have their secret key material either stored simply on disk or in secure hardware (YubiKeys, smartcards). <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></li>
<li>Both have some form of freshness. This guarantees to the server that the client was recently alive
(FIDO: challenge response, TLS: signing the session transcript).</li>
</ul>
<p>Which begs the question:
<em>why are we not using TLS client certificates?</em></p>
<p>Or, in other words: if nobody outside enterprise uses TLS client certs, if no consumer site offers client certs,
if client cert usability is so bad &ndash; why should FIDO succeed where client certs did not?</p>
<p>And, more concretely: <em>what does FIDO do better than TLS?</em></p>
<p>I already mentioned that FIDO has hardware attestation, and TLS client certs don&rsquo;t. <sup id="fnref1:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>
Also, you might argue that it makes sense to separate transport and authentication into separate protocols.</p>
<p>On the other hand, I would argue that having both together is beneficial, since it allows you
to bind the security of your channel to an identity.
That is, you can run FIDO over a TLS connection that is being MITMed
(assuming the TLS client trusted the server cert, or a trusted CA has been compromised)
&ndash; the server won&rsquo;t notice that the connection to the WebAuthn client is not private.</p>
<p>Also, in terms of performance it makes sense to bind transport and authentication together.
In almost all cases you need a secure channel anyway to communicate further after authentication.
Why spend extra round trips with FIDO if you can integrate it into TLS?
At Google-scale, the extra requests will make a difference.</p>
<p>I would love to hear your thoughts on this question (FIDO vs TLS client certs)!</p>
<h4 id="proprietary-solutions">Proprietary solutions</h4>
<p>Open standards don&rsquo;t lead to open solutions.</p>
<p>For Android, Google implements FIDO support in their proprietary
<a href="https://developers.google.com/identity/fido/android/native-apps">Play Services</a>
(rather than in AOSP).
That means all the CustomROMs and Android-based OSes without ties to Google won&rsquo;t
have FIDO support for a long while.</p>
<p>Meanwhile, Microsoft&rsquo;s <a href="https://techcommunity.microsoft.com/t5/azure-active-directory-identity/expansion-of-fido-standard-and-new-updates-for-microsoft/ba-p/3290633">announcement</a>
on World Password Day (while everybody else was announcing their push for FIDO)
used the terms &ldquo;Azure&rdquo;, &ldquo;Windows&rdquo;, &ldquo;Microsoft&rdquo; noticably more often than it did say &ldquo;FIDO&rdquo; or &ldquo;Webauthn&rdquo;.
So far, my impression is that they are boasting with FIDO and open standards,
all while pushing their proprietary Authenticator app.</p>
<p>Additionally, banks love to build their own 2FA apps rather than use TOTP for their online banking logins.
Will they switch to FIDO?</p>
<p>Furthermore, how will the new multi-device credentials work?
Will users be locked into the iCloud ecosystem?
Or will Apple offer a way for 1Password or Keepass to plug into its FIDO APIs
and function as a passkey sync provider?
This is especially critical since FIDO does not specify how multi-device keys are synced.
The sync services will be the Achilles&rsquo; heel for the security of users&rsquo; passkeys.</p>
<h4 id="higher-complexity-for-developers">Higher complexity for developers</h4>
<p>Implementing FIDO is more complex than username+password.
For the time being, this will continue to pose a barrier for entry.</p>
<p>You need to parse binary messages, handle keys, verify signatures, generate challenges,
adhere to a specification, and so on.
Of course, all of this will be (and should be!) outsourced into
<a href="https://developers.yubico.com/Software_Projects/WebAuthn-FIDO2/WebAuthn-FIDO2_Server_Libraries/">libraries</a>
&ndash; after all, you also don&rsquo;t implement your own TLS code.</p>
<p>But even with the bit-juggling abstracted away, developers still need to
learn the concepts and the terminology.
It is not simply a matter of <code>new HTTPSConnection(url)</code>.
The WebAuthn API seems innocent: it is just <code>create()</code> and <code>get()</code>.
But you need to understand how to prepare your inputs and how to interpret the outputs.</p>
<p>FIDO has many options and knobs that you can configure.
What&rsquo;s the difference between attestation and assertion?
What are PublicKeyCredentials, and which ones should I choose?
What level of user verification do I want?
Do I really need to verify that counter?
Should I allow multi-device credentials, or only keys that reside in TPMs?</p>
<p>I can imagine a world where web frameworks and CMS systems offer FIDO support out of
the box as part of the user management.
But this will take time.
Until then, developers will need to go through this learning curve.
It is not impossible &ndash; but it is an barrier that I think is often neglected in the hype around FIDO.</p>
<h4 id="widespread-support">Widespread support</h4>
<p>With all the hype around FIDO:
how good and how widespread will FIDO support actually be in reality?</p>
<p>On the <em>authenticator side:</em></p>
<ul>
<li>
<p>Firefox still does not support CTAP2 on MacOS and Linux, only on Windows using
<a href="https://blog.mozilla.org/security/2019/03/19/passwordless-web-authentication-support-via-windows-hello/">Windows Hello</a>
(but they are <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1530370">working on it</a>).
Which means even though it has a WebAuthn API exposed to JavaScript, you cannot use features like
<a href="https://www.w3.org/TR/webauthn-2/#discoverable-credential">discoverable credentials</a>.
Discoverable credentials are important because they allow usernameless signin (as opposed to &ldquo;only&rdquo; passwordless).
They were introduced in CTAP2.
In practice, this means that you still <a href="https://github.com/webcompat/web-bugs/issues/103230"><em>cannot</em> use</a>
your YubiKey for passwordless sign-in to Microsoft&rsquo;s ecosystem using Firefox.</p>
<p>I.e. &ldquo;FIDO support&rdquo; in Firefox in July 2022 means &ldquo;WebAuthn wrapped around CTAP1/U2F&rdquo;.</p>
</li>
<li>
<p>Support on the Linux desktop (for desktop apps, similar to Windows Hello) will (most likely) take a while.</p>
</li>
<li>
<p>AOSP won&rsquo;t support FIDO either any time soon (due to it being implemented in Play Services, see above).</p>
</li>
</ul>
<p>On the <em>website/client side</em>:</p>
<ul>
<li>
<p>I have over 200 entries in my password manager.
Only a fraction of those offers TOTP (20%). And an even smaller fraction offers WebAuthn (5%).
Given FIDO&rsquo;s complexity: will FIDO surpass TOTP? Will it become the password-killer?</p>
<p>A real world example: ETH Zürich is planning to
<a href="https://ethz.ch/staffnet/en/news-and-events/internal-news/archive/2022/07/mfa-more-security-for-your-data.html">roll out</a>
2FA in autumn 2022 for its single sign-on.
But it will use OTP (presumably TOTP), not WebAuthn.</p>
</li>
<li>
<p>Almost all consumer websites offer WebAuthn merely for 2FA. That is, they are <em>not</em> replacing passwords.
One exception is Nextcloud, which <a href="https://nextcloud.com/blog/nextcloud-hub-brings-productivity-to-home-office/">offers</a>
it for <em>passwordless</em> signin.
Not a single website I use offers <em>usernameless</em> signins via WebAuthn.</p>
</li>
<li>
<p>On the upside, FIDO support is already significantly more widespread on
<em>consumer websites</em> than TLS cert support is.</p>
</li>
</ul>
<h4 id="research--academia">Research &amp; academia</h4>
<p>From an academic perspective, FIDO is a relatively new protocol, and research into
it is just getting started.</p>
<p>There are some relatively recent papers formally modelling and formally verifying it
(formal as in <a href="https://en.wikipedia.org/wiki/Formal_methods">formal methods</a>).
<a href="https://hal.inria.fr/hal-01966563/document">One</a> using ProVerif,
<a href="https://eprint.iacr.org/2020/756.pdf">another</a> looking at the crypto in the computational model.
<a href="https://arxiv.org/pdf/2205.08071.pdf">Others</a> are already presenting real-world attacks.</p>
<p>This reminds me of SSL/TLS and WEP/WPA: industry builds it, academia breaks it, industry patches it, repeat.</p>
<p>TLS 1.3 broke this cycle: it involved academia early on in the standardisation process.
There was a lot of research into both the
<a href="https://datatracker.ietf.org/doc/html/rfc8446#appendix-E.1.6">handshake</a> and the
<a href="https://datatracker.ietf.org/doc/html/rfc8446#appendix-E.2.1">record layer</a>
that was incorporated into the drafts.
Also the research attacked the spec from multiple angles:
proving cryptographic security computationally (as opposed to information theoretically),
tool-based approaches (Tamarin, ProVerif), and formally verifying implementations.</p>
<p>This is not a central criticism of FIDO! FIDO is just starting out, you cannot expect
dozens of researchers already jumping onto it.
But if FIDO does prove itself to be there to stay and gains significant adoption,
FIDO3 or FIDO4 should involve academia more early on in the process, just like TLS 1.3 did.</p>
<h4 id="the-name">The name</h4>
<p>WebAuthn has not even reached broad adoption, yet the name is already outdated:
WebAuthn started out as a web standard, but with native/mobile/desktop support,
it is now breaking out of the browser.
Native iOS and Mac apps can use the WebAuthn protocol over native, non-browser APIs.
Thus the term <em>Web</em>Authn has become too narrow.</p>
<p>Even within FIDO (or should I say FIDO2? Or FIDO/WebAuthn?) there are legacy names that keep
getting changed (e.g. resident keys aka. resident credentials aka.
<a href="https://www.w3.org/TR/webauthn-2/#discoverable-credential">discoverable credentials</a>).</p>
<p>In addition, it is often unclear what someone means when they talk about having &ldquo;FIDO support&rdquo;.
Do they mean only WebAuthn? Do they mean CTAP2 as well (cf. Firefox)? What about U2F?
And CTAP1? Wait, U2F and CTAP1 are the <a href="https://www.yubico.com/resources/glossary/ctap/">same thing</a>.</p>
<p>The naming is not (yet) as messy as with USB (hello, USB 3.0 and USB 3.1 Gen 1 and USB 3.2 Gen 1x1).
But it is definitely not very human friendly either &ndash; neither for consumers, nor for developers.</p>
<h2 id="will-we-see-a-broad-migration-from-passwords-to-passkeys">Will we see a broad migration from passwords to passkeys?</h2>
<p>Mainstream adoption of passkeys depends on two questions:
First: will passkeys be broadly available?
And second: will users actually be willing to use them?</p>
<p>In terms of availability, we need both service-side and client-side support.
For the service providers (social media, online shops, email providers, &hellip;) it is relatively
straight-forward: just pull in a WebAuthn library, consider all my discussions above,
and don&rsquo;t forget to get the recovery process right.
On the client-side big vendors such as Microsoft, Google and Apple are finally making a push.
But even they have more work to do:
the reality of syncable credentials is still very much open. It is unclear if and how
third-party services (such as today&rsquo;s password managers) can hook into the client and sync passkeys.</p>
<p>And when everything is ready, all my favourite services, and even my obscure
Linux distro and my smart TV support FIDO &ndash; will users adopt it?
The UX of passkeys is remarkably similar to the UX of using a password manager:</p>
<ul>
<li>One click to generate a new password/passkey.</li>
<li>One click to auto-fill an existing password/use the passkey.</li>
<li>Various features to list and manage all your passwords/keys.</li>
</ul>
<p>Yet password managers have not taken off.
If we as security professionals could never provide enough incentives to convince the broad public
to use password managers &ndash; how will we be able to convince them to adopt passkey managers?
How will we convince someone with an Apple iPad, a Windows laptop and an Android phone
that passkeys are easier and faster than passwords?</p>
<h2 id="conclusion">Conclusion</h2>
<p>Are passwords bad? Yes.
Is FIDO the solution? (Some of) the industry definitely thinks so.</p>
<p>In reality however we are still a long way away.
Even Google <a href="https://blog.google/technology/safety-security/one-step-closer-to-a-passwordless-future/">admits</a>
that &ldquo;passwords will continue to be part of our lives&rdquo; for a while.
There are <a href="https://www.wired.com/story/fido-alliance-ios-android-password-replacement/">a lot of challenges</a>
yet to be solved.</p>
<p>This all sounds very pessimistic, but it shouldn&rsquo;t.
I <em>am</em> excited about replacing passwords.
I am excited to see cryptography being applied to solve a real everyday problem.
And I do want to be able to use my YubiKey on more than just 10 out of 200 accounts.</p>
<p>Apple has a history of pushing things forward, simply by adopting something and everybody
else following suit.
And with Microsoft and Google on board as well, there is a good chance that they can bridge
the chicken-and-egg problem:
website don&rsquo;t offer FIDO because there is poor client support,
and clients don&rsquo;t offer FIDO because it is not a feature that is widely requested among websites.</p>
<p>For us computer scientists and engineers there are a lot of interesting challenges ahead.
Naming, discussing and understanding the good things as well as the bad things,
the opportunities as well as the weaknesses, is key to tackling these challenges.</p>
<hr>
<p>Please <a href="/about/">let me know</a> if you found this useful, have any comments, found an error,
or outright disagree with me &ndash; I would love to hear your opinion!</p>
<h2 id="---hack-for-some-extra-space-before-the-footnotes--"><!-- raw HTML omitted --></h2>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Yubico already <a href="https://www.yubico.com/blog/what-does-the-future-hold-for-modern-authentication/">wrote about it</a>
back in March and the
<a href="https://fidoalliance.org/white-paper-multi-device-fido-credentials/">white paper</a> also dates earlier.
Apple even tech-previewed syncing passkeys at <a href="https://developer.apple.com/videos/play/wwdc2021/10106/">WWDC 2021</a>.
Nevertheless, both two are pretty recent developments from a daily user point-of-view, and thus worth the news!&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>&ldquo;Passkey&rdquo; is not (yet) an official FIDO term afaik (as of May 2022).
Apple coined it (in this context) at WWDC2021 afaik.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>But: don&rsquo;t confuse Apple&rsquo;s/FIDO&rsquo;s passkeys with Bluetooth&rsquo;s passkeys!
(see <a href="https://www.bluetooth.com/specifications/specs">Bluetooth Core Specification 5.3, Volume 3, Part C, Section 3.2.3</a>)&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Interestingly, a smartphone and its Touch ID can be both:
you can use it to log in to a website on your phone (same platform).
Or you can use it to log you in to a website on your laptop (roaming via Bluetooth).&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>For reliability reasons, Bluetooth is only used for an initial key exchange.
After that, the devices communicate over the internet.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>On top of that, FIDO implementations ensure that a key is only used to log in on the intended site
(much like password managers only prompt to autofill when the domain matches).
This adds another layer of protection.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>One difference, however, is that FIDO has <a href="https://www.w3.org/TR/webauthn-2/#attestation">attestation</a>
to prove that a secret key is indeed stored in secure hardware.
I am not aware that TLS client auth has this feature.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>TLS 1.3 0-RTT and the real world</title><link>https://thore.io/posts/2021/11/tls-1.3-0-rtt-and-the-real-world/</link><pubDate>Sun, 07 Nov 2021 14:30:00 +0100</pubDate><guid>https://thore.io/posts/2021/11/tls-1.3-0-rtt-and-the-real-world/</guid><description>&lt;p>Recently I was implementing some of the &lt;a href="https://www.rfc-editor.org/rfc/rfc8446">TLS 1.3&lt;/a> handshake
as part of the Information Security Lab at ETH Zurich.&lt;/p>
&lt;p>When working on the lab I was googling around and by chance came across &lt;a href="https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html">this OpenSSL man page&lt;/a>.
Specifically, its &amp;ldquo;NOTES&amp;rdquo; section at the bottom.
You can read it on your own, but the TLDR is:
under certain operating systems and TCP settings, and given a not-too-large amount of application data,
0-RTT may inadvertently end up being 1-RTT.
In other words, you go to all the lengths to build a protocol that has low latency
but wind up back on square one.
(You can find the original issue &lt;a href="https://github.com/openssl/openssl/issues/3906">here&lt;/a>.)&lt;/p></description><content type="html"><![CDATA[<p>Recently I was implementing some of the <a href="https://www.rfc-editor.org/rfc/rfc8446">TLS 1.3</a> handshake
as part of the Information Security Lab at ETH Zurich.</p>
<p>When working on the lab I was googling around and by chance came across <a href="https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html">this OpenSSL man page</a>.
Specifically, its &ldquo;NOTES&rdquo; section at the bottom.
You can read it on your own, but the TLDR is:
under certain operating systems and TCP settings, and given a not-too-large amount of application data,
0-RTT may inadvertently end up being 1-RTT.
In other words, you go to all the lengths to build a protocol that has low latency
but wind up back on square one.
(You can find the original issue <a href="https://github.com/openssl/openssl/issues/3906">here</a>.)</p>
<p>For me this is a reminder of two things:</p>
<ol>
<li>
<p>Measuring performance matters (just like writing tests).
Without measuring it, you wouldn&rsquo;t have noticed that not all of your packets are doing 0-RTT.</p>
</li>
<li>
<p>You can have a nice higher level protocol, but the lower part of the stack can cause unexpected effects.
Abstraction works only so far.
Thus even if you generally work higher up, you need to have a solid understanding of what is happening underneath.</p>
</li>
</ol>
]]></content></item><item><title>Beautiful UI</title><link>https://thore.io/posts/2020/05/beautiful-ui/</link><pubDate>Sat, 23 May 2020 19:00:00 +0200</pubDate><guid>https://thore.io/posts/2020/05/beautiful-ui/</guid><description>&lt;p>What makes an app great? A novel idea, a day-to-day problem that it solves elegantly,
a smooth user experience, a beautiful interface.&lt;/p>
&lt;p>A beautiful interface.&lt;/p>
&lt;p>What is &amp;ldquo;beautiful&amp;rdquo;? How do we grasp that intuition and put it into something
that we as designers and developers can implement in our apps?&lt;/p>
&lt;p>In this post, I want to explore a number of things that I found make
me stumble when I use an app.
Things that I now watch out for when building an app.
Things that I go to my company&amp;rsquo;s designers to &lt;del>complain&lt;/del> discuss about.
Things that I open issues and PRs with open source projects on Github for.&lt;/p></description><content type="html"><![CDATA[<p>What makes an app great? A novel idea, a day-to-day problem that it solves elegantly,
a smooth user experience, a beautiful interface.</p>
<p>A beautiful interface.</p>
<p>What is &ldquo;beautiful&rdquo;? How do we grasp that intuition and put it into something
that we as designers and developers can implement in our apps?</p>
<p>In this post, I want to explore a number of things that I found make
me stumble when I use an app.
Things that I now watch out for when building an app.
Things that I go to my company&rsquo;s designers to <del>complain</del> discuss about.
Things that I open issues and PRs with open source projects on Github for.</p>
<blockquote>
<p>Basically, I describe a number of characteristics that a Beautiful UI has.</p>
</blockquote>
<p><strong>Disclaimer:</strong></p>
<p>Firstly, I am not a designer. I have no clue about the concepts and structured
approaches they teach in design school. I am writing this from the view of a user
with a very keen eye, very high standards and a background in Android development.</p>
<p>Secondly, the last thing I want to do is to point fingers.
The (anti-)examples I give are to illustrate. We simply learn more from our errors
than from the things we already do right.</p>
<p>Lastly, I am biased towards Android, since this is what I know most about.
However, the general rules should equally apply to other platforms.</p>
<h3 id="rule-1-stick-to-the-guidelines">Rule 1: Stick to the guidelines</h3>
<p>Design systems exist for a reason: to provide a consistent set of rules how things
are to be done, and to save us time since a lot of design problems are
already solved for us.</p>
<p><a href="https://material.io/">Material Design</a> is the go-to choice for many Android apps. It
contains a huge list of building blocks that we can use to build an app, allowing us
to create a consistent and beautiful experience.</p>
<p>Choose a design system, and then stick to its guidelines. Be consistent.
Not doing so gives the user the impression that we don&rsquo;t really care about our
brand&rsquo;s appearance after all.</p>
<p>For example, Material defines how an <a href="https://material.io/components/app-bars-top">app bar</a> should look like.
<a href="https://github.com/jitsi/jitsi-meet#mobile-apps">Jitsi</a> however does not adhere to that. First, the app bar height is
too small &ndash; notice how the space to the left of the back arrow is greater
than the space below it. Second, the title is centered, whereas in Material
for Android it should be left-aligned.</p>
<p>Another issue here is colouring: if we define a primary brand colour, we should use
it everywhere. The ugly default green on the switches does not go well with
the blue.</p>


<img src="/img/details-matter/jitsi-appbar.png"   width="300"  class="center" />

<p>Jitsi also provides us with an example of a <a href="https://material.io/components/navigation-drawer">modal navigation drawer</a>,
colloquially known as the &ldquo;hamburger menu&rdquo; (since it hides behind a button
that vaguely looks like a hamburger).
To be fair, the <a href="https://material.io/components/navigation-drawer#specs">Material specs</a> are not particularly helpful,
as they imply that (on a phone) the drawer should always take the full width
minus the size of the app bar. Not even Google does this with their own apps,
and there are <a href="https://tips.seebrock3r.me/material-navigation-drawer-sizing-558aea1ad266">various</a> <a href="https://android.jlelse.eu/navigation-drawer-styling-under-material-design-f0767882e692">different</a> articles
discussing what might be the right width. Anyway, the width that Jitsi uses
is far smaller than what anybody else uses. This break with practical Material
Design is distracting.</p>


<img src="/img/details-matter/jitsi-drawer.png"   width="300"  class="center" />

<p>Icons need to be consistent, too:
<a href="https://protonvpn.com/">ProtonVPN</a> uses an old Holo icon amidst their Material-themed app
(but <a href="https://github.com/ProtonVPN/android-app/pull/21">hopefully not for much longer!)</a>.</p>


<img src="/img/details-matter/pvpn-icon.png"   width="300"  class="center" />

<p>Finally, leaving random, unthemed and seemingly unfinished screens
in our app is not just not beautiful. It&rsquo;s ugly.
This is an actual settings page from the <a href="https://www.publibike.ch/">Publibike</a> app:
in the default Android theme, without any app bar or back button.</p>


<img src="/img/details-matter/publibike-unfinished.png"   width="300"  class="center" />

<p>Stick to the guidelines. Everywhere.</p>
<p>To end on a good note, I would like to point out two apps that have done an
awesome job in encorporating the latest Material Design:
<a href="https://github.com/zhanghai/MaterialFiles">this files app</a> and <a href="https://threema.ch/">Threema</a>.
Case studies of well-executed and more custom design systems can be found
with <a href="https://play.google.com/store/apps/details?id=com.Slack">Slack</a>, <a href="https://play.google.com/store/apps/details?id=ch.asvz.asvz">ASVZ</a> and <a href="https://github.com/DP-3T/dp3t-app-android-ch">SwissCovid</a>.</p>
<h3 id="rule-2-be-responsive">Rule 2: Be responsive</h3>
<p>By &ldquo;responsive&rdquo; I mean fast, not skipping animation frames, lagging, or jumping
around. This rule concerns the dynamic aspect of our interface.</p>
<p>Lack of responsiveness quickly results in the user experience being
consciously or subconsciously worsened.</p>
<p>Most often this happens to apps that are not native
to Android, but written in some cross-platform framework like <a href="https://reactnative.dev/">React Native</a>
or <a href="https://cordova.apache.org/">Cordova</a>. This is not to say that we cannot build responsive apps with them,
but we need to go to greather lengths to achieve that.
One cross-platform framework for which this is not true is
<a href="https://flutter.dev/">Flutter</a>, at least in my experience so far. I am yet to see a
non-responsive Flutter app.</p>
<h3 id="rule-3-have-touch-states">Rule 3: Have touch states</h3>
<p>Touch states are the difference between interacting with a panel of glass
and interacting with something natural and beautiful.</p>
<p>It doesn&rsquo;t matter whether it&rsquo;s the classic default-hover-focus-press state list or
the animated Material ripple effect.
I believe that touch states contribute a great length to an app feeling
&ldquo;native&rdquo;, &ldquo;fluent&rdquo; or &ldquo;responsive&rdquo;.
In web apps the effect is even stronger: distinct hover states make the app
feel much more &ldquo;native&rdquo;, even though it only runs in the browser.
Thus touch states are closely related to responsiveness, but deserve
to be considered on their own.</p>
<p>Unfortunately, there are numerous examples where touch states are missing.
I&rsquo;m sure you&rsquo;ll find some in an app near you.
If the user can click it and it does something, it needs a touch state.</p>
<p>When they are present, however, touch states should be a single colour.
Not two, like in this example:</p>


<img src="/img/details-matter/pm-touch.png"   width="300"  class="center" />

<h3 id="rule-4-align-and-pad">Rule 4: Align and pad</h3>
<p>Consistent alignment gives an app a structured appearance.
Malaligned items on the other hand make the app look messy and cluttered.</p>
<p>This effect is increased by too little padding.
Remember Jitsi&rsquo;s settings screen from above? Everything is crammed together,
making texts harder to read and sections harder to differentiate at first glance.</p>
<p>One alignment example from ProtonMail:</p>


<img src="/img/details-matter/pm-alignment.png"   width="300"  class="center" />

<p>And a very subtle centering example from Threema:</p>


<img src="/img/details-matter/3ma-center.png"   width="300"  class="center" />

<p>Subconsciously, something in the green header feels odd.
It is only when we turn on layout bounds in the developer tools,
that we see that the white content is top-aligned instead of being aligned
to the horizontal center line:</p>


<img src="/img/details-matter/3ma-center-dev.png"   width="300"  class="center" />

<p>Knowing this, it is easier to see (in the original image) that the
green space above <em>Hang up</em> is smaller than the green space below.
It&rsquo;s like the arrow in the FedEx logo: once you know it, you can&rsquo;t stop noticing it.</p>
<h2 id="summary">Summary</h2>
<p>In this post, I described a number of points that I found to be common
pitfalls when giving an app its final polish.
I gave a few examples that I learned from and that continue to help me
in not making the same mistakes.</p>
<p>These points complement <a href="https://www.oreilly.com/library/view/clean-code/9780136083238/">Clean Code</a>: just like Clean Code should be elegant,
Beautiful UI should be delightful. Just like Clean Code should be pleasing to read
for the developer, Beautiful UI should be pleasing to look at for the user.</p>
<p>Beautiful UI can be summarised in four rules:</p>
<ol>
<li>Stick to the guidelines</li>
<li>Be responsive</li>
<li>Have touch states</li>
<li>Align and pad</li>
</ol>
<p>Listing those is easy. Implementing them is hard.</p>
]]></content></item><item><title>Stitching Screenshots in GIMP</title><link>https://thore.io/posts/2020/05/stitching-screenshots-in-gimp/</link><pubDate>Thu, 21 May 2020 19:20:00 +0200</pubDate><guid>https://thore.io/posts/2020/05/stitching-screenshots-in-gimp/</guid><description>&lt;p>Today I once again found myself needing to stitch screenshots together.
It has been a while since I last had to do this (back then, I used some random app).
Because I started using &lt;a href="https://www.gimp.org/">GIMP&lt;/a> for more and more tasks, I wanted to do this in GIMP
as well now.&lt;/p>
&lt;p>Luckily, I found &lt;a href="https://www.reddit.com/r/GIMP/comments/9s7j09/how_to_mix_2_screenshots_in_1/">this Reddit post&lt;/a>. I will repeat the steps here,
both as a mental aid and in case that the original posts disappears.
Also, I have slightly adjusted the steps.&lt;/p></description><content type="html"><![CDATA[<p>Today I once again found myself needing to stitch screenshots together.
It has been a while since I last had to do this (back then, I used some random app).
Because I started using <a href="https://www.gimp.org/">GIMP</a> for more and more tasks, I wanted to do this in GIMP
as well now.</p>
<p>Luckily, I found <a href="https://www.reddit.com/r/GIMP/comments/9s7j09/how_to_mix_2_screenshots_in_1/">this Reddit post</a>. I will repeat the steps here,
both as a mental aid and in case that the original posts disappears.
Also, I have slightly adjusted the steps.</p>
<ol start="0">
<li>In another tool (e.g., Gwenview), crop the screenshots so that the top and bottom system bars that
are in the overlapping regions are gone.</li>
<li>Open GIMP</li>
<li><code>File &gt; Open</code> the top most screenshot</li>
<li><code>File &gt; Open as Layers...</code> all other screenshots</li>
<li>∀ layers: set opacity to ~50%. (Select layer in the layer list on the left, then click opacity bar above.)</li>
<li><code>Image &gt; Canvas Size...</code>: liberally increase the canvas height. Make sure that &ldquo;Resize layers&rdquo; is set to &ldquo;None&rdquo;.</li>
<li>Click <code>M</code> to select the <em>Move</em> tool</li>
<li>∀ layers: select the layer and use the arrow keys to move them up/down.
Use Shift+⇅ for rough moving. Zoom in on the canvas to get the alignment pixel-perfect.
Increase the canvas height again if necessary.</li>
<li>∀ layers: set the opacity back to 100%</li>
<li><code>Image &gt; Fit Canvas to Layers</code></li>
<li><code>File &gt; Export As...</code></li>
</ol>
]]></content></item><item><title>Filling the Proximity Tracing Gap</title><link>https://thore.io/posts/2020/05/filling-the-proximity-tracing-gap/</link><pubDate>Thu, 21 May 2020 14:45:00 +0200</pubDate><guid>https://thore.io/posts/2020/05/filling-the-proximity-tracing-gap/</guid><description>&lt;p>Tracing apps are all around the news these days.
Some countries have actively used them for some time now, others are in the process
of launching them, while even others are stuck in various debates.&lt;/p>
&lt;p>Consequently, there has been a lot of press about tracing apps.
However, I feel like most news sites - even the tech media - have failed to
underline some crucial points on how these apps (could) work.
Sure, some have noted, maybe even explained them. But many have not, and those
that have did not sufficiently stress their importance.&lt;/p></description><content type="html"><![CDATA[<p>Tracing apps are all around the news these days.
Some countries have actively used them for some time now, others are in the process
of launching them, while even others are stuck in various debates.</p>
<p>Consequently, there has been a lot of press about tracing apps.
However, I feel like most news sites - even the tech media - have failed to
underline some crucial points on how these apps (could) work.
Sure, some have noted, maybe even explained them. But many have not, and those
that have did not sufficiently stress their importance.</p>
<p>What do I mean by <em>important</em>? Important, in the sense that understanding them
will enable you to develop a much better mental model of what tracing apps are.
Important, because understanding them enables you to better participate in the
current debate on tracing apps.</p>
<p>My goal is to explain the concepts, while striking a balance between too
little detail and overwhelming the reader.
If you want little detail, stay with the mainstream media.
If you want to really dive into the topic, read the various white papers.
(Especially if you are studying Computer Science. They are a great case study
of security protocols.)</p>
<hr>
<p>A note before I start:</p>
<ul>
<li>I won&rsquo;t go into the pros and cons of tracing apps and the concerns they raise.
I will simply try to explain a couple technical points.</li>
<li>Whenever I speak of &ldquo;tracing apps&rdquo;, I mean tracing apps based on the
<a href="https://github.com/DP-3T/documents">DP^3T system</a>. It is the one currently being implemented in
Switzerland (among other countries).
I cannot speak for other approaches.</li>
<li><em>Contact tracing</em> or <em>proximity tracing</em>?
The Swiss Federal Office for Public Health FOPH as well as Google and Apple
(mostly) use the term <em>proximity tracing</em>, so for the sake of consistency I will, too.</li>
<li>I am going to make simplifications in order to strike a middle ground.</li>
</ul>
<h2 id="1-what-data-is-uploaded-to-the-server">1. What data is uploaded to the server?</h2>
<p>TLDR:</p>
<ul>
<li>always: random seed</li>
<li>opt-in: contact event data <strong>only for contacts with infected patients</strong></li>
<li>never: location data, contact event data for unifected contacts</li>
</ul>
<p>Some terminology: a &ldquo;contact&rdquo; is not an entry in your address book, but rather the
event of being in close proximity with another person for some time.</p>
<p>Understanding what data is uploaded and why requires a brief
explanation of what happens during your use of the app.</p>
<p>In the design described in section 2 of the <a href="https://github.com/DP-3T/documents/blob/master/DP3T%20White%20Paper.pdf">DP^3T white paper</a>,
your app creates a long and random (and thus unguessable) sequence,
the so-called <em>seed</em>.
That seed is initally secret and only stored on your phone.
From that seed a list of so-called <em>ephemeral IDs</em> are derived.
Note that the other way around is unfeasible:
Given an ephemeral ID you cannot compute the seed.
Also note that without knowledge of the seed, you cannot learn whether or
not two given IDs come from the same seed, i.e. come from the same user.</p>
<p>While using the app, it sends out these ephemeral IDs, going through the list one-by-one.
One ID is broadcasted for some time, then the next, and so on.
Regularly changing the IDs is what makes it harder to track you, since for
anyone but you, the IDs look random.
Nevertheless, your app stores all the other apps&rsquo; ephemeral IDs that it receives.</p>
<p><strong>If and only if you are tested positive</strong> (and you enter the code the test
center gives you), <strong>then the app uploads your seed to a central server,</strong>
usually run by the local health authority.
(Then, your app generates a new seed to start fresh.)</p>
<p>One reason for uploading the seed is to save data: the list of ephemeral IDs
is huge since you change them regularly.
And you do need to change IDs in order to prevent tracking &ndash; recall that there is no
obvious connection between any two IDs.</p>
<p>The server collects a day&rsquo;s worth of seeds from newly infected patients.
Once a day, your app downloads the list of seeds of infected patients.</p>
<p>Then locally on your phone, your app goes through this list of &ldquo;infected seeds&rdquo;.
For each seed it computes the corresponding ephemeral IDs, just like the
infected user did to send them out.
Your app then checks whether it previously &ldquo;saw&rdquo; any one of them.
Under certain conditions (e.g. if it finds a minimum number of contact events
with infected persons) it issues a warning.
Thus, only now your app can make sense of the ephemeral IDs that it &ldquo;met&rdquo;.</p>
<hr>
<p>DP^3T also describes a slight variant of the above (white paper section 3).
This approach is currently <strong>not</strong> implemented by Google/Apple/Swiss PT, but it is still
interesting enough to be mentioned as an outlook.</p>
<p>In this variant, your app would in the last step <strong>not</strong> receive a
list of &ldquo;infected seeds&rdquo; and would <strong>not</strong> compute all the ephemeral IDs
of the infected patients. Here is what happens instead:</p>
<p>The server still receives the seeds from the infected users like before.
From them, it builds a so-called <a href="https://en.wikipedia.org/wiki/Cuckoo_filter">Cuckoo filter</a> and sends that to all apps.
Your app can check whether an ephemeral ID of another phone that it encountered
was generated from a seed that the server put into the Cuckoo filter.
Thus it can still issue a warning if needed.
However it <strong>cannot</strong> in practise extract the &ldquo;infected seeds&rdquo; from the
Cuckoo filter, thanks to the underlying maths.</p>
<hr>
<p>Furthermore, DP^3T describes that the app can
<strong>upload data about your contact with infected patients</strong>
(e.g. when, how long, how often).
This is to support the work of epidemiologists.
It is purely optional and currently not implemented in the Swiss app.</p>
<h2 id="2-where-do-i-have-privacy">2. Where do I have privacy?</h2>
<p>Privacy in this is many-fold:</p>
<h4 id="privacy-against-other-usersapps">Privacy against other users/apps</h4>
<p>Privacy against other users is preserved.</p>
<p>Other apps do not learn your identity, since the only link between your random
seed and your identity is the code from the test centre. But that is not send
to other users, it stays on the server.</p>
<p>Privacy is even stronger in DP^3T&rsquo;s second variant: here, other users do not
even learn the &ldquo;infected seeds&rdquo;. They only learn a Cuckoo filter, and from
that the only thing that they can learn is whether or not they have a match.</p>
<h4 id="privacy-against-the-central-server">Privacy against the central server</h4>
<p>Privacy against the server depends on your situation:</p>
<ol>
<li>You never test positive (or if you do, never enter the test centre
code). Then <strong>no data</strong> is sent to the server.</li>
<li>You test positive and enter the code in the app.
Then the server learns:</li>
</ol>
<ul>
<li>that you are infected. Okay, the health authority saw your positive test anyway.</li>
<li>your seed. Useless on its own though. Only useful to someone who
met with you and can check for matching ephemeral IDs.</li>
</ul>
<p>Crucially however, since the ephemeral IDs <em><strong>of your contacts</strong></em> do not leave your phone,
the server is unable to build a social graph, a network of who is meeting whom.
The only data your app sends to the server is &ldquo;I am infected and this is my random sequence&rdquo;
but not &ldquo;this is who I met&rdquo;.</p>
<h2 id="3-how-are-google-and-apple-involved">3. How are Google and Apple involved?</h2>
<p>The Swiss proximity tracing app is going to use the software interface (API)
that <a href="https://www.google.com/covid19/exposurenotifications/">Google</a> and <a href="https://www.apple.com/covid19/contacttracing/">Apple</a> provide via system updates.
What are the implications of this?</p>
<p>The idea behind using the operating systems&rsquo;s API is to split responsibilities:
The OS handles the exchange of ephemeral IDs and the proximity measuring.
Since it has much deeper access to Bluetooth, the hope is that the accuracy
of the system will be better.
The app can then locally query the operating system for the encounters,
and handle all the logic for storing and comparing the IDs,
communicating with the server, and displaying a pretty UI.</p>
<p>Another advantage arising from the collaboration of the two tech companies
is increased compatibility, since they agreed on a common interface.
Have you ever tried sending a file via Bluetooth from an Android phone
to an iPhone? See what I mean.</p>
<p>Also, both Android and iOS give you control over which app has access to the
proximity data, similar to the way you can control permissions.</p>
<p>Note though, that the latest <a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-FAQv1.1.pdf">FAQ</a> (as of writing) seems to be very
careful not to explicitly say that <strong>no</strong> data will be shared with Google or Apple.
It only talks about not sharing the <em>identities</em> of users with anyone,
including Google and Apple.</p>
<figure><img src="/img/ios135-covid.png"
    alt="iOS 13.5 exposure notifications screen" width="250"><figcaption>
      <p>Exposure logging settings in iOS 13.5</p>
    </figcaption>
</figure>

<hr>
<h2 id="final-words">Final words</h2>
<p>I hope this helps a little bit in understanding conceptually what is going on
with these tracing apps.</p>
<p>Yet, in the end, it all comes down to trust.
Trust that the implementation really does what the specification says.
Trust that the software contains no critical bugs.
Trust that the maths and formalisms of the specification are correct.
How this trust is earned and lost is a different matter.</p>
<p>Should you find any error, feel free to <a href="/about/">contact me</a>.</p>
<hr>
<h4 id="sources-and-further-reading">Sources and further reading:</h4>
<ul>
<li><a href="https://github.com/DP-3T/documents">DP^3T documents</a></li>
<li><a href="https://www.apple.com/covid19/contacttracing/">Apple ressources</a></li>
<li><a href="https://www.google.com/covid19/exposurenotifications/">Google ressources</a></li>
</ul>
]]></content></item><item><title>Learnings From Two Student Cluster Competitions</title><link>https://thore.io/posts/2019/11/learnings-from-two-student-cluster-competitions/</link><pubDate>Wed, 27 Nov 2019 21:50:00 +0100</pubDate><guid>https://thore.io/posts/2019/11/learnings-from-two-student-cluster-competitions/</guid><description>&lt;p>Having taken part in two Student Cluster Competitions now, I want to take the opportunity to take a step back and reflect on what we learnt. That will aid me organise my thought and hopefully will help other teams prepare for the challenge, since with HPC being such a niche field there is not much writing about the cluster competitions out there (though there does exist one &lt;a href="https://www.amazon.com/Student-Supercomputer-Challenge-Guide-Supercomputing-ebook/dp/B07BQQ5S2G?SubscriptionId=AKIAILSHYYTFIVPWUY6Q&amp;amp;tag=duckduckgo-d-20&amp;amp;linkCode=xm2&amp;amp;camp=2025&amp;amp;creative=165953&amp;amp;creativeASIN=B07BQQ5S2G">book&lt;/a>! But I am yet to read it&amp;hellip;).&lt;/p></description><content type="html"><![CDATA[<p>Having taken part in two Student Cluster Competitions now, I want to take the opportunity to take a step back and reflect on what we learnt. That will aid me organise my thought and hopefully will help other teams prepare for the challenge, since with HPC being such a niche field there is not much writing about the cluster competitions out there (though there does exist one <a href="https://www.amazon.com/Student-Supercomputer-Challenge-Guide-Supercomputing-ebook/dp/B07BQQ5S2G?SubscriptionId=AKIAILSHYYTFIVPWUY6Q&amp;tag=duckduckgo-d-20&amp;linkCode=xm2&amp;camp=2025&amp;creative=165953&amp;creativeASIN=B07BQQ5S2G">book</a>! But I am yet to read it&hellip;).</p>
<p>There are three significant Student Cluster Competitions: ASC in Asia, ISC in Frankfurt (Germany) and SC in the US. The last two are paired with supercomputing conferences. The oldest and &ldquo;original&rdquo; Supercomputing Conference (SC) takes place since 1988 and is the largest with over 11,000 visitors.</p>
<p>During each conference a Student Cluster Competition takes place: teams of 6 students build a small supercomputer with the help of their advisors and industry partners. They are given a set of benchmarks and real-world applications that they need to run within a power limit of 3 kW. Teams are then judged on the performance of their system as well as interviews with a jury where they need to demonstrate their knowledge of HPC.</p>
<p>I was lucky to be part of <a href="https://racklette.ethz.ch/">RACKlette</a>, the first team from Switzerland to take part in one of these competitions. We first competed at ISC19 in June and now again in November at SC19.
Despite being a newcomer we were quite successfull: in Frankfurt we placed third overall and won the LINPACK award and in Denver we placed 5th in a highly competitive field.</p>
<p>In this post, I will outline the main learnings our team  had in the hope that it will be helpful to future teams. Among others, I will go over what you should remember to bring with you, some tips on how to tune both your software and hardware and finally what to expect from the competition in general.</p>
<h2 id="what-to-bring">What to bring</h2>
<p>It&rsquo;s easy, right? Your local supercomputing centre organises the shipment of the cluster, you bring your laptop, and you are all set.</p>
<p>Unfortunately, that&rsquo;s far from it. Here is a - most likely incomplete - list of things you should bring to the competition:</p>
<ol start="0">
<li>
<p>Cabling:</p>
<ul>
<li>6 Ethernet cables: each of you needs to connect to the cluster via wire.</li>
<li>Ethernet-to-USB-C adapters (thank you Tim Apple)</li>
<li>Multiple socket outlet</li>
<li>CH-to-US adapter: different sockets!</li>
</ul>
</li>
<li>
<p>Monitoring:</p>
<ul>
<li>External monitor: Provided at SC but not at ISC, ask CSCS to ship one with the cluster</li>
<li>HDMI cable</li>
<li>Raspberry Pi: Setup InfluxDB and Grafana to read out IPMI readings</li>
<li>Second laptop: Always good if yours fails, plus you can use it do display the Grafana dashboard (the Pi is quite busy running the DB). Alternatively bring your iPad to be more productive with Sidecar (please can somebody build an equivalent for Linux?)</li>
</ul>
</li>
<li>
<p>Varia:</p>
<ul>
<li>Coffein: Very important at SC where the competition lasts 48 hours non-stop. The organisers also provide coke, but quickly there is only diet coke left, so buy some yourself at the local supermarket.</li>
<li>Replacement SSD: One team lost their boot drive. It&rsquo;s unlikely, but if it happens you want to be prepared.</li>
<li>Paper clip: In case your team mate locked the rack but is now asleep and you need to reboot after a power outage.</li>
<li>National flag: a Swiss flag always attracts extra love from your human fans, and more people stop by a nicely decorated booth. Looks great if blowing in the wind of the cooling fans.</li>
</ul>
</li>
</ol>
<h2 id="tuning-applications">Tuning applications</h2>
<p>Tuning things is what this competition is all about. There are a thousand different means to that end, and thanks to the complexity of modern systems much of it comes down to lots of time invested and trial-and-error.
But if you suddenly get a 2x speedup it can feel very worthwhile! (Remember, running inputs naively can take 6ish hours each!)</p>
<p>Other than getting speedup, the other thing to keep in mind is the power limit. You cannot throw 16 Nvidia V100s at it, each consuming 250 W peak power, if the committee&rsquo;s alarm goes off at 3 kW!</p>
<h3 id="hardware">Hardware</h3>
<p>First GPUs. When we competed we - like most teams - had Nvidia cards. You can use the CLI tool <code>nvidia-smi</code> to instruct your GPUs to run at a maximum frequency or maximum power. Try both, depending on the task one may be faster or one may result in a more stable power consumption.</p>
<p>Second CPUs. Use <code>cpupower frequency-info -p</code> to read out and <code>cpupower frequency-set</code> to set frequencies. We wrote a script for that to quickly set frequencies across all nodes using <code>pdsh</code>.</p>
<p>And frequency matters! At SC19, for <a href="https://sst-simulator.org/">SST Ember</a> the input had ten iterations with each repetitively doing the same kind of work. When running at 2.6 GHz one iterations took 38 min on our hardware. At 2.8 GHz it only took 33 min. For ten iterations that saves you 50 minutes!</p>
<p>You can also set frequencies manually during a run. (Or automatically, if your so inclined to script it.) One prime example is LINPACK which has a big spike at the beginning and than uses less power if kept capped at the same frequency. In addition, here is an example of us manually adjusting the CPU frequency for SST Ember during SC19 (notice how each iteration has this bump at the beginning, and how close we are driving it to 3 kW):</p>

    <img src="/img/sst-power.png"  alt="SST power example"  class="center"  />


<p>Also be aware of turbo boost. To avoid sudden unexpected (and unnecessary) spikes over the power limit, you can limit the CPU frequency to something which the CPU can continuously maintain.</p>
<p>And third, cooling. Fans use power, too. During specially important things like LINPACK it is possible (but not necessarily recommended) to slow down the fans via your motherboard&rsquo;s IPMI. Luckily our Gigabyte motherboards had a webinterface to do that, but there is also a CLI available.</p>
<p>DISCLAIMER: You MUST test this before the competition. If you set the fans too slow and your systems becomes too hot during the run, it becomes unstable, components go into lets-rescue-myself mode and you need to reboot!</p>
<p>Temperature matters too. At SC19 we ran HPCG in the morning just fine, though reproducibly very close below the power limit. When we re-run it in the afternoon, all three attempts spiked over the 3 kW limit (with the exact same configuration, i.e. same inputs, frequencies, fan speeds). We currently acknowledge this to a 1-2°C increase in temperature in the conference hall (because the IPMI was reading a 1-2°C higher CPU temperature, and our cooling fans were at fixed speeds).</p>
<h3 id="software">Software</h3>
<p>Try different compilers: gcc, icc, you name it. <code>-O3</code> is always good, plus <code>-march=native</code> to tell the compiler it can use vectorisation. Do not overdo it with flags, at some point you will get worse results! Also be aware of flags that icc only has for compatibility reasons: e.g use <code>-xSKYLAKE-AVX512</code> instead of <code>-march=native</code>.</p>
<p>Also try different MPIs: OpenMPI, IntelMPI, MVAPICH, MPICH. According to their docs MPICH has checkpointing. We only found that out during SC19, but that sounds like something worth looking into. Note that all of them may have slightly different syntax.</p>
<h3 id="input-files">Input files</h3>
<p>Understand your input files! The organisers - especially at SC - give you inputs that are not optimal and are meant to test your understanding of the application. For example for SST the input we got used <code>--partitioner=linear</code> but there are something like five others to partition the workload.</p>
<p>Or if there are matrices involved think about how much you assign to each MPI rank.</p>
<p>Ideally you had a chance to play with these parameters beforehand and know what to do.
However it&rsquo;s not unheard of that people (that is, I) have found out about other tuning opportunities while the competition was already going on. So don&rsquo;t be afraid of a blind shot if you think it can reasonably give you more performance!</p>
<h3 id="varia">Varia</h3>
<p>Always check the power reading on the provided official PDU! For one, it generally updates in real-time (i.e. every second) while you or the organisers&rsquo; Grafana may only update every five to thirty seconds.
Our team lost two hours of compute time during 3am and 5am because we were only watching our Grafana, which unfortunately decided to update with outdated data so we didn&rsquo;t notice our job had finished. So watch the PDU!</p>
<h2 id="the-cluster-competition-experience-on-the-conference-floor">The Cluster Competition Experience: On the conference floor</h2>
<p>Very exciting, you are finally there at the Supercomputing Conference! You spend a day searching your cluster because it was shipped to a completely different booth somewhere else in the hall, but now you are all set up and ready to go!</p>
<p>Here are some tips:</p>
<ul>
<li>Be ready to mingle with the other teams. Everyone is really nice and very outgoing, and chatting about how you optimise applications or what results you got for that input file is completely normal and okay. It great to see more people doing HPC!</li>
<li>Expect to be interviewed. Not only by the judges, but also by the conference organisers, your sponsors and Dan Olds. Dan publishes articles about HPC (e.g. on <a href="https://www.hpcwire.com/">HPCwire</a>) and is an incredibly kind, chatty though eloquent and entertaining character. You will notice when you see him! He interviews all teams every year. Because he has been at the cluster competitions since the beginning he knows them inside out.</li>
<li>At SC (and maybe at ISC in the future?) there is a power outage, planned by the committee. It is meant to test your ability to recover from such an event. This year at SC19 they took everyone by surprise by pulling the power not only once but twice!</li>
<li>If you can, walk around the conference hall and check out the exhibition. There is cool stuff on display, and sometimes you even get merchandise. Some booths host raffles, so there&rsquo;s your chance to win a NUC!</li>
</ul>
<h2 id="final-words">Final words</h2>
<p>The student cluster competition is an incredible experience. Meeting like-minded students, experiencing the conference itself, learning a thousand things about HPC, computer systems, networking, compiling and application optimisation in the progress makes it a very unique challenge but also opportunity.</p>
<p>Although secretly, it&rsquo;s only an international sweets exchange really: we brought Swiss chocolate and received sweets from Estonia, Poland and Shanghai in return.</p>
<p><em>This post also appeared on the <a href="https://racklette.ethz.ch/blog/">RACKlette team blog</a></em></p>
]]></content></item><item><title>What is HPC?</title><link>https://thore.io/posts/2019/11/what-is-hpc/</link><pubDate>Wed, 27 Nov 2019 14:36:22 +0100</pubDate><guid>https://thore.io/posts/2019/11/what-is-hpc/</guid><description>&lt;p>Computer Science in itself is a huge field, and one of it sub-fields is HPC. HPC, short for &lt;em>High Performance Computing&lt;/em> is little known, even among Computer Scientists and even more so in the general public.
You might have heard of, or seen pictures of, &amp;ldquo;supercomputers&amp;rdquo;. They fill huge rooms with aisle after aisle of cabinets (and often feature some pretty graphic on the outside).&lt;/p>
&lt;p>So you might ask, what&amp;rsquo;s the difference between a supercomputer and one of Google&amp;rsquo;s datacentres?&lt;/p></description><content type="html"><![CDATA[<p>Computer Science in itself is a huge field, and one of it sub-fields is HPC. HPC, short for <em>High Performance Computing</em> is little known, even among Computer Scientists and even more so in the general public.
You might have heard of, or seen pictures of, &ldquo;supercomputers&rdquo;. They fill huge rooms with aisle after aisle of cabinets (and often feature some pretty graphic on the outside).</p>
<p>So you might ask, what&rsquo;s the difference between a supercomputer and one of Google&rsquo;s datacentres?</p>
<p>First is their configuration: even though both have lots of cabinets stuffed with computer hardware, the hardware in a normal datacentre is set up in a way such that it functions as many &ldquo;small&rdquo; computers (but those are still bigger than your PC at home!).
The hardware in a supercomputer on the other hand is all tied together to form one massive computer where you can run your program on.</p>
<p>And the second difference is their use case: common services like websites, databases or application backends usually run in datacentres.
Supercomputers on the other hand are mainly used for scientific simulations. Those might be academic (simulating expanding galaxies or protein reactions) but can also be industrial (simulating airflow over a new airplane design iteration rather than having to physically build and test it in a windtunnel).
So both require a huge amount of compute power, but the first does so because it needs to be able to handle large amounts of clients and the second because it solves inherently difficult problems with brute force.</p>
<p>And even if you didn&rsquo;t fly lately, HPC directly affects you every single day: Every few hours, a <a href="https://www.cscs.ch/computers/kesch-escha-meteoswiss">supercomputer</a> in the Swiss Supercomputing Centre (CSCS) in Lugano crunches the latest weather data and runs the meteorologists&rsquo; simulations to come up with a new weather forecast(*). Meteo Swiss is a leader in this area and thanks to being <a href="https://www.hpc-ch.org/meteoswiss-and-cscs-pave-the-way-for-more-detailed-weather-forecasts/">one of the first</a> to run these simulations on GPUs it is able to achieve predictions for a much finer grid than neighbouring countries.</p>
<p>That&rsquo;s a short overview of what HPC is and does. If you want to find out more have a look at the field&rsquo;s two big news websites <a href="https://www.hpcwire.com/">HPCwire</a> and <a href="https://insidehpc.com/">insideHPC</a>.</p>
<p>(*) Please stop giving bad reviews in the App Store if the weather prediction is bad, it&rsquo;s usually not the app developer&rsquo;s fault but the meteorologist&rsquo;s!</p>
]]></content></item></channel></rss>