Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://www.maths.tcd.ie/%7Efionn/misc/feed.xml

  1. <?xml version='1.0' encoding='UTF-8'?>
  2. <rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  3.  <channel>
  4.    <title>misc</title>
  5.    <link>https://www.maths.tcd.ie/~fionn/misc/</link>
  6.    <description>Fionn has no mouth but he must scream</description>
  7.    <atom:link href="https://www.maths.tcd.ie/~fionn/misc/feed.xml" rel="self"/>
  8.    <docs>http://www.rssboard.org/rss-specification</docs>
  9.    <generator>fionn-feed</generator>
  10.    <image>
  11.      <url>https://www.maths.tcd.ie/~fionn/me.jpg</url>
  12.      <title>misc</title>
  13.      <link>https://www.maths.tcd.ie/~fionn/misc/</link>
  14.    </image>
  15.    <language>en</language>
  16.    <lastBuildDate>Fri, 23 Aug 2024 16:13:11 +0000</lastBuildDate>
  17.    <managingEditor>fionn@this.domain</managingEditor>
  18.    <webMaster>fionn@this.domain</webMaster>
  19.    <item>
  20.      <title>Biometric FIDO2/U2F SSH Keys</title>
  21.      <link>https://www.maths.tcd.ie/~fionn/misc/fido_ssh/</link>
  22.      <description>Smartcards have traditionally supported SSH public key authentication using two methods: PIV and PGP. […]</description>
  23.      <content:encoded><![CDATA[<p>
  24.      Smartcards have traditionally supported SSH public key authentication using two
  25.      methods: PIV and PGP.
  26.      </p>
  27.      <p>
  28.      In PIV mode, you end up hacking around with <code>opensc</code> to get
  29.      <code>ssh-agent</code> to use the certificate as a key.
  30.      This also doesn’t play well with <code>gpg-agent</code>, which tends to acquire
  31.      a lock on the smartcard.
  32.      </p>
  33.      <p>
  34.      In PGP mode, you have to ditch <code>ssh-agent</code> and use
  35.      <code>gpg-agent</code> instead, which is a significantly degraded experience.
  36.      </p>
  37.      <h3 id="openssh"><a class="anchor" href="#openssh"></a>OpenSSH</h3>
  38.      <p>
  39.      As of <a href="https://www.agwa.name/blog/post/ssh_signatures">OpenSSH version
  40.      8.0</a> you can use SSH keys to sign arbitrary data.
  41.      </p>
  42.      <p>
  43.      As of <a href="https://www.openssh.com/txt/release-8.2">OpenSSH version 8.2</a>
  44.      you can use SSH keys derived from the FIDO2 application on smartcards, using
  45.      either Ed25519 or ECDSA.
  46.      </p>
  47.      <h3 id="yubikeys"><a class="anchor" href="#yubikeys"></a>YubiKeys</h3>
  48.      <p>
  49.      Yubico manufacture a few different smartcards (YubiKeys, from here on out). The
  50.      <a href="https://www.yubico.com/products/yubikey-5-overview/">YubiKey 5
  51.      series</a> support all of the above modes, whereas the <a
  52.      href="https://www.yubico.com/products/security-key/">YubiKey Security Key</a>
  53.      only supports FIDO2 (since it’s designed just for 2FA on websites and so on).
  54.      The Security Key is also significantly cheaper.
  55.      </p>
  56.      <p>
  57.      There’s also the <a
  58.      href="https://www.yubico.com/products/yubikey-bio-series/">YubiKey Bio</a>,
  59.      which has the same support as the Security Key, but has a fingerprint reader and
  60.      comes in at a little over 3 times the price.
  61.      </p>
  62.      <p>
  63.      I held off on buying the Bio because I store my PGP key on my YubiKey and wanted
  64.      to retain this functionality. But I finally decided to try it out, for several
  65.      reasons:
  66.      </p>
  67.      <ul>
  68.      <li>I can use it for SSH,</li>
  69.      <li>I can use that SSH key for signing files and <a
  70.      href="https://calebhearth.com/sign-git-with-ssh">Git commits</a>,</li>
  71.      <li>I can secure the SSH key with a passphrase and a fingerprint,</li>
  72.      <li>I expensed it to my employer,</li>
  73.      <li>nobody sends me <a href="/~fionn/contact/#email">PGP-encrypted emails</a>
  74.      any more anyway 🙁.</li>
  75.      </ul>
  76.      <h2 id="fingerprint"><a class="anchor" href="#fingerprint"></a>Adding a
  77.      Fingerprint</h2>
  78.      <p>
  79.      Out of the box, when I plugged it in it was flashing orange. I don’t know why.
  80.      </p>
  81.      <pre class="shell">
  82. ykman info
  83. Device type: YubiKey C Bio - FIDO Edition
  84. Serial number: 17244581
  85. Firmware version: 5.5.6
  86. Form factor: Bio (USB-C)
  87. Enabled USB interfaces: FIDO
  88.  
  89. Applications
  90. FIDO2       Enabled
  91. OTP         Not available
  92. FIDO U2F     Enabled
  93. OATH         Not available
  94. YubiHSM Auth Not available
  95. OpenPGP     Not available
  96. PIV         Not available
  97. </pre>
  98.      <p>
  99.      To add a fingerprint, we first have to set a PIN.
  100.      The PIN can be alphanumeric (extended ASCII) and relatively long (63
  101.      characters).
  102.      </p>
  103.      <pre class="shell">
  104. ykman fido access change-pin
  105. Enter your new PIN:
  106. Repeat for confirmation:
  107. </pre>
  108.      <p>
  109.      Then add a fingerprint.
  110.      </p>
  111.      <pre class="shell">
  112. ykman fido fingerprints add "right-index"
  113. Enter your PIN:
  114. Place your finger against the sensor now...
  115. 4 more scans needed.
  116. Place your finger against the sensor now...
  117. 3 more scans needed.
  118. Place your finger against the sensor now...
  119. 2 more scans needed.
  120. Place your finger against the sensor now...
  121. 1 more scans needed.
  122. Place your finger against the sensor now...
  123. Capture complete.
  124. </pre>
  125.      <p>
  126.      We can then list the fingerprints.
  127.      </p>
  128.      <pre class="shell">
  129. ykman fido fingerprints list
  130. Enter your PIN:
  131. ID: c83b (right-index)
  132. </pre>
  133.      <p>
  134.      I remain optimistic that revealing which finger I’ve enrolled doesn’t put me at
  135.      significantly greater risk of losing it. If your threat model includes this,
  136.      rest easy knowing that the list is protected by the PIN.
  137.      </p>
  138.      <h2 id="key-generation"><a class="anchor" href="#key-generation"></a>Generating
  139.      a Resident Ed25519 SSH Key</h2>
  140.      <p>
  141.      There are <a
  142.      href="https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html#_discoverable_vs_non_discoverable_credentials">two
  143.      types</a> of FIDO2 SSH keys: resident and non-resident.
  144.      </p>
  145.      <p>
  146.      I’m using a resident key because the PIN/fingerprint access control is good
  147.      enough for me and I value the ability to move the YubiKey between different
  148.      devices.
  149.      </p>
  150.      <p>
  151.      We generate the key with <code>ssh-keygen -t ed25519-sk</code>. This will fail
  152.      if your YubiKey’s firmware is <a
  153.      href="https://www.yubico.com/blog/whats-new-in-yubikey-firmware-5-2-3/">older
  154.      than 5.2.3</a>, before they supported Ed25519 curves.
  155.      If so, you can fall back to <code>ecdsa-sk</code>, or get a new YubiKey (<a
  156.      href="https://safecurves.cr.yp.to/">recommended</a>).
  157.      </p>
  158.      <p>
  159.      The below command makes a key that requires not just user presence (a touch) but
  160.      also verification. This means a PIN for normal non-biometric YubiKeys but,
  161.      despite the <a
  162.      href="https://man.archlinux.org/man/ssh-keygen.1#verify-required"><code>ssh-keygen</code>
  163.      documentation</a> insisting otherwise, the Bio will accept a fingerprint to
  164.      unlock the key.
  165.      </p>
  166.      <blockquote cite="https://man.archlinux.org/man/ssh-keygen.1#verify-required">
  167.      <strong><code>verify-required</code></strong>
  168.      <br/>
  169.          Require signatures made using this key indicate that the user was first
  170.      verified.
  171.          This option only makes sense for the FIDO authenticator algorithms
  172.      <code>ecdsa-sk</code> and <code>ed25519-sk</code>.
  173.          Currently PIN authentication is the only supported verification method, but
  174.      other methods may be supported in the future.
  175.      </blockquote>
  176.      <p>
  177.      I also increase the key derivation rounds and add a comment.
  178.      </p>
  179.      <pre class="shell">
  180. ssh-keygen -t ed25519-sk -O resident -O verify-required -a 128 -C 17244581
  181. Generating public/private ed25519-sk key pair.
  182. You may need to touch your authenticator to authorize key generation.
  183. Enter PIN for authenticator:
  184. Enter file in which to save the key (/home/fionn/.ssh/id_ed25519_sk):
  185. Enter passphrase (empty for no passphrase):
  186. Enter same passphrase again:
  187. Your identification has been saved in /home/fionn/.ssh/id_ed25519_sk
  188. Your public key has been saved in /home/fionn/.ssh/id_ed25519_sk.pub
  189. The key fingerprint is:
  190. SHA256:2fl1x8+ACfUB2UA3eV5mXLJY5Wr04K93N7nH6iN4OoY 17244581
  191. The key's randomart image is:
  192. +[ED25519-SK 256]-+
  193. |           .==*++|
  194. |           ..=o**|
  195. |          . . ==o|
  196. |         o o = =.|
  197. |        S o o * =|
  198. |           . o =o|
  199. |         . ..  .=|
  200. |        E + o .+*|
  201. |         ..+ o+=*|
  202. +----[SHA256]-----+
  203. </pre>
  204.      <h2 id="connecting"><a class="anchor" href="#connecting"></a>Using the FIDO2 SSH
  205.      Key</h2>
  206.      <p>
  207.      Now test it out. I usually use GitHub for this. Upload
  208.      <code>~/.ssh/id_ed25519_sk.pub</code>, add
  209.      </p>
  210.      <p>
  211.      </p>
  212.      <pre>
  213. Host github.com
  214.    User git
  215.    PubkeyAuthentication yes
  216.    IdentityFile ~/.ssh/id_ed25519_sk
  217. </pre>
  218.      <p>
  219.      to <code>~/.ssh/config</code> and try to connect.
  220.      </p>
  221.      <pre class="shell">
  222. ssh -T github.com
  223. Enter passphrase for key '/home/fionn/.ssh/id_ed25519_sk':
  224. Confirm user presence for key ED25519-SK SHA256:2fl1x8+ACfUB2UA3eV5mXLJY5Wr04K93N7nH6iN4OoY
  225. User presence confirmed
  226. Hi <a href="https://github.com/fionn" rel="me">fionn</a>! You've successfully authenticated, but GitHub does not provide shell access.
  227. </pre>
  228.      <p>
  229.      Then try to connect again and notice that <code>ssh-agent</code> has cached the
  230.      passphrase.
  231.      </p>
  232.      <p>
  233.      To use it on another machine, plug it into the new machine and run
  234.      </p>
  235.      <pre class="shell">
  236. ssh-keygen -K
  237. Enter PIN for authenticator:
  238. You may need to touch your authenticator to authorize key download.
  239. Enter passphrase (empty for no passphrase):
  240. Enter same passphrase again:
  241. Saved ED25519-SK key to id_ed25519_sk_rk
  242. </pre>
  243.      <p>
  244.      to download the key handles to the working directory. Move them to
  245.      <code>~/.ssh/</code> and connect like usual.
  246.      </p>
  247.      ]]></content:encoded>
  248.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  249.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/fido_ssh/</guid>
  250.      <pubDate>Wed, 21 Sep 2022 00:00:00 +0000</pubDate>
  251.    </item>
  252.    <item>
  253.      <title>RSS and Atom Feeds</title>
  254.      <link>https://www.maths.tcd.ie/~fionn/misc/feed/</link>
  255.      <description>I think decentralised syndication is a good thing so I made RSS and Atom feeds for this pseudo-blog</description>
  256.      <content:encoded><![CDATA[<p>
  257.                  I read <a
  258.      href="https://twobithistory.org/2018/09/16/the-rise-and-demise-of-rss.html">The
  259.      Rise and Demise of RSS</a> and was motivated to syndicate this <a
  260.      href="../">list of things I write here</a>.
  261.                  </p>
  262.      <p>
  263.                  One of the challenges is that typically people use some sort of
  264.      publishing platform which generates RSS feeds for you. Since this site is
  265.      entirely static (well, aside from some PHP to keep things tidy on the server
  266.      side), I have to generate the feed myself. Since it’s just XML, I could in
  267.      principle do it by hand. However, the pain-point that that would introduce every
  268.      time I (occasionally) add to this list would almost guarantee that I wouldn’t
  269.      update it.
  270.                  </p>
  271.      <p>
  272.                  To solve this, I wrote a pretty basic script that scrapes this page,
  273.      grabs all the articles and figures out how to turn them into feed entries. Then
  274.      it generates a feed with all the relevant metadata and adds each one. The
  275.      process is still manual, but reduced to a “one-click” deployment.
  276.                  </p>
  277.      <p>
  278.                  The code is <a href="https://github.com/fionn/feed">here</a>. This
  279.      page is publishing syndicated feeds; you should be able to see it if your
  280.      browser knows what to do with them. (Firefox looks to be deprecating its live
  281.      bookmarks functionality. Get <a
  282.      href="https://addons.mozilla.org/en-US/firefox/addon/awesome-rss/">Awesome
  283.      RSS</a> to add the RSS feed back in the address bar.)
  284.                  </p>
  285.      <p>
  286.                  Subscribe via <a href="../feed.xml">RSS</a> or <a
  287.      href="../feed.atom">Atom</a>. Or don’t. But do subscribe to other things. It’s
  288.      such a shame that this technology is going out of favour, but also no accident.
  289.      We have to fight for the internet we want.
  290.                  </p>
  291.      <p>
  292.                  (<em>Syndication feeds validate for <del>both</del> <a
  293.      href="https://www.feedvalidator.org/check.cgi?url=https%3A%2F%2Fwww.maths.tcd.ie%2F%257Efionn%2Fmisc%2Ffeed.xml">RSS</a>
  294.      <del>and <a
  295.      href="https://www.feedvalidator.org/check.cgi?url=https%3A%2F%2Fwww.maths.tcd.ie%2F%257Efionn%2Fmisc%2Ffeed.atom">Atom</a></del>.</em>)
  296.                  </p>
  297.      ]]></content:encoded>
  298.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  299.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/feed/</guid>
  300.      <pubDate>Tue, 18 Sep 2018 00:00:00 +0000</pubDate>
  301.    </item>
  302.    <item>
  303.      <title>Encrypting a Volume</title>
  304.      <link>https://www.maths.tcd.ie/~fionn/misc/encrypt_volume/</link>
  305.      <description>It’s really easy. Let’s assume sdc is the drive (because it is for me). Open up gdisk, make a new GPT and fill the disk with a partition of type FD00 (this is Linux RAID, which allegedly is conventional). […]</description>
  306.      <content:encoded><![CDATA[<p>
  307.      It’s really easy. Let’s assume <code>sdc</code> is the drive (because it is for
  308.      me). Open up <code>gdisk</code>, make a new GPT and fill the disk with a
  309.      partition of type <code>FD00</code> (this is Linux RAID, which allegedly is
  310.      conventional).
  311.      </p>
  312.      <pre>
  313. Number  Start (sector)    End (sector)  Size       Code  Name
  314.   1            2048       124735454   59.5 GiB    FD00  Linux RAID
  315. </pre>
  316.      <p>
  317.      You can also rename the partition to LUKS or something.
  318.      </p>
  319.      <p>
  320.      <code>cryptsetup</code> <em>should</em> be compiled with sane defaults (you can
  321.      check with <code>--help</code>), so encryption is done with
  322.      </p>
  323.      <pre class="root-shell">
  324. cryptsetup -v --verify-passphrase luksFormat /dev/sdc1
  325. </pre>
  326.      <p>
  327.      (which can be elaborated on if the compiled defaults are not to your liking).
  328.      </p>
  329.      <p>
  330.      Open the LUKS container with
  331.      </p>
  332.      <pre class="root-shell">
  333. cryptsetup open /dev/sdc1 <em>luks_volume</em>
  334. </pre>
  335.      <p>
  336.      (where <code><em>luks_volume</em></code> is the unimaginative name of the
  337.      container).
  338.      </p>
  339.      <pre>
  340. sdc                  8:32   1  59.5G  0 disk
  341. └─sdc1               8:33   1  59.5G  0 part
  342.  └─<em>luks_volume</em>     254:2   0  59.5G  0 crypt
  343. </pre>
  344.      <p>
  345.      This creates a handle in <code>/dev/mapper/<em>luks_volume</em></code>. It’s not
  346.      a filesystem yet, though.
  347.      </p>
  348.      <p>
  349.      </p>
  350.      <pre class="root-shell">
  351. mkfs.ext4 /dev/mapper/<em>luks_volume</em>
  352. </pre>
  353.      <p>
  354.      Now we can mount it! See <a href="../mount_encrypted_volume/"><em>Mounting an
  355.      encrypted LUKS volume</em></a> for how to do that.
  356.      </p>
  357.      ]]></content:encoded>
  358.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  359.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/encrypt_volume/</guid>
  360.      <pubDate>Thu, 24 May 2018 00:00:00 +0000</pubDate>
  361.    </item>
  362.    <item>
  363.      <title>WireGuard</title>
  364.      <link>https://www.maths.tcd.ie/~fionn/misc/wg/</link>
  365.      <description>This is the future of VPNs, etc. Read about it here. It really is amazing. There’s also manual configuration steps there, which you should do first. […]</description>
  366.      <content:encoded><![CDATA[<p>
  367.      This is the future of VPNs, etc. Read about it <a
  368.      href="https://www.wireguard.com/">here</a>. It really is amazing. There’s also
  369.      manual configuration steps there, which you should do first.
  370.      </p>
  371.      <p>
  372.      It’s super easy to set up configurations for use with <code>wg-quick</code>.
  373.      Here’s a simple server + client configuration for tunnelling all traffic
  374.      throught the VPN.
  375.      </p>
  376.      <p>
  377.      Note that “server” and “client” are artificial terms here; really both machines
  378.      are peers, we’re imposing the server + client relationship on them to align with
  379.      traditional VPNs.
  380.      </p>
  381.      <p>
  382.      Generate private keys with <code>umask 077 &amp;&amp; wg genkey &gt;
  383.      private.key</code>. Corresponding public keys are derived from private ones with
  384.      <code>wg pubkey &lt; private.key &gt; public.key</code>. The preshared key is
  385.      used for post-quantum resilience, generated with <code>wg genpsk &gt;
  386.      preshared.key</code>.
  387.      </p>
  388.      <pre><code class="ini">
  389. # server wg0.conf
  390. [Interface]
  391. PrivateKey = [server private key]
  392. Address = 10.10.0.1/24, fd80::1/64
  393. ListenPort = 2307
  394. SaveConfig = true
  395. PostUp = iptables -A FORWARD -i wg0 -j ACCEPT &amp;&amp; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
  396. PostDown = iptables -D FORWARD -i wg0 -j ACCEPT &amp;&amp; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
  397.  
  398. [Peer]
  399. PublicKey = [client public key]
  400. PresharedKey = [preshared.key]
  401. AllowedIPs = 10.10.0.2/32, fd80::2/128
  402. </code></pre>
  403.      <p>
  404.      Not a whole lot is happening here. IP addresses and ports are just examples—here
  405.      we’re allocating <code>10.10.0.1</code> to the server and <code>10.10.0.2</code>
  406.      to the client. The <code>SaveConfig</code> line allows WireGuard to override
  407.      this file with its current state, so you can make manual, persistent changes as
  408.      it runs.
  409.      </p>
  410.      <pre><code class="ini">
  411. # client wg0.conf
  412. [Interface]
  413. PrivateKey = [client private key]
  414. Address = 10.10.0.2/24, fd80::2/64
  415. ListenPort = 2307
  416. DNS = 10.10.0.1
  417. PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
  418. PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
  419.  
  420. [Peer]
  421. PublicKey = [server public key]
  422. PresharedKey = [preshared.key]
  423. AllowedIPs = 0.0.0.0/0, ::/0
  424. Endpoint = [wireguard server]:2307
  425. </code></pre>
  426.      <p>
  427.      The ports match for NAT traversal, but it’s not strictly necessary. The client
  428.      allows its peer to send traffic from any IP, since it’s going to be proxying the
  429.      entire internet.
  430.      </p>
  431.      <p>
  432.      On both server and client, run <code>wg-quick up wg0</code>. This can also run
  433.      as a systemd service, with <code>systemctl start wg-quick@wg0.service</code>.
  434.      </p>
  435.      ]]></content:encoded>
  436.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  437.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/wg/</guid>
  438.      <pubDate>Thu, 07 Dec 2017 00:00:00 +0000</pubDate>
  439.    </item>
  440.    <item>
  441.      <title>Vim Plugins, the Right Way</title>
  442.      <link>https://www.maths.tcd.ie/~fionn/misc/vim/</link>
  443.      <description>It’s good to be a software minimalist (and a minimalist in general). This is how to be one when it comes to Vim plugins (aside from not using plugins, of course). […]</description>
  444.      <content:encoded><![CDATA[<p>
  445.      It’s good to be a software minimalist (and a minimalist in general). This is how
  446.      to be one when it comes to Vim plugins (aside from not using plugins, of
  447.      course).
  448.      </p>
  449.      <h2 id="why"><a class="anchor" href="#why"></a>Why Plugin Managers?</h2>
  450.      <p>
  451.      Vim’s directory hierarchy is traditionally something like this.
  452.      </p>
  453.      <pre>
  454. .vim/
  455. ├── autoload/
  456. ├── colors/
  457. ├── doc/
  458. ├── ftplugin/
  459. ├── indent/
  460. ├── plugin/
  461. ├── spell/
  462. ├── syntax/
  463. └── undo/
  464. </pre>
  465.      <p>
  466.      It looks quite sensible. Plugins follow this hierarchy, with their
  467.      <code>.vim</code> files going into <code>plugins/</code> (and sometimes
  468.      <code>autoload/</code>), help files in <code>doc/</code>, etc. This makes
  469.      uninstalling or updating plugins a real pain.
  470.      </p>
  471.      <p>Plugin managers solve this problem by abstracting this hierarchy, so you
  472.      don’t have to think about it.
  473.      </p>
  474.      <h2 id="howto"><a class="anchor" href="#howto"></a>How to Get Rid of Plugin
  475.      Managers?</h2>
  476.      <p>
  477.      Vim 8 introduced the notion of a <em>package</em> (see <a
  478.      href="https://vimhelp.org/repeat.txt.html#packages"><code>:h
  479.      packages</code></a>). Plugins (i.e. their entire directory hierarchy) can live
  480.      in <code>.vim/pack/plugins/start/<em>plugin_name</em>/</code> and Vim will add
  481.      this to its runtime path. (The <code>plugins/</code> directory can actually be
  482.      named however you like.)
  483.      </p>
  484.      <p>
  485.      This is pretty great, because now our plugins can be kept under version control.
  486.      Getting them is just a clone, they can be easily updated and they can be rolled
  487.      back.
  488.      </p>
  489.      <p>
  490.      However, the <code>.vim/</code> directory is probably already under version
  491.      control, along with the rest of the dotfiles.
  492.      </p>
  493.      <p>
  494.      To deal with this: instead of cloning, use <code><a
  495.      href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">git submodule</a> add
  496.      <var>repository</var>.git</code>. Then just keep it up to date by pulling it
  497.      every so often. To update all plugins, <code>git submodule foreach git
  498.      pull</code>.
  499.      </p>
  500.      <p>
  501.      When cloning the dotfile repository, use the <code>--recursive</code> flag to
  502.      get the submodules as well. Alternatively, clone as normal and then initialise
  503.      and update the submodules with <code>git submodule init &amp;&amp; git submodule
  504.      update</code>.
  505.      </p>
  506.      <p>
  507.      Run <code>:helptags ALL</code> to generate helptags for all plugins.
  508.      </p>
  509.      <h2 id="right"><a class="anchor" href="#right"></a>Is This Really the Right
  510.      Way?</h2>
  511.      <p>
  512.      I think so. Some might disagree and argue for using <a
  513.      href="https://www.atlassian.com/git/tutorials/git-subtree"><code>git-subtree</code></a>
  514.      instead.
  515.      </p>
  516.      <h2 id="remove"><a class="anchor" href="#remove"></a>How to Remove a
  517.      Submodule?</h2>
  518.      <p>
  519.      There’s a lot of disinformation out there. Just <code>git rm
  520.      <var>path</var>/<var>to</var>/<var>submodule</var></code>, like the <a
  521.      href="https://git-scm.com/docs/gitsubmodules#_forms">docs say</a>.
  522.      </p>
  523.      <blockquote cite="https://git-scm.com/docs/gitsubmodules">
  524.      The deletion removes the superproject’s tracking data, which are both the
  525.      <code>gitlink</code> entry and the section in the <code>.gitmodules</code> file.
  526.      The submodule’s working directory is removed from the file system, but the Git
  527.      directory is kept around as <span class="sic">it</span> to make it possible to
  528.      checkout past commits without requiring fetching from another repository.
  529.      </blockquote>
  530.      <h2 id="dotfiles"><a class="anchor" href="#dotfiles"></a>Where Are Your
  531.      Dotfiles?</h2>
  532.      <p>
  533.      <code><a href="https://github.com/fionn/.dotfiles">.dotfiles</a>/vim/<a
  534.      href="https://github.com/fionn/.dotfiles/tree/master/vim/.vim">.vim</a>/<a
  535.      href="https://github.com/fionn/.dotfiles/tree/master/vim/.vim/vimrc">vimrc</a></code>.
  536.      </p>
  537.      ]]></content:encoded>
  538.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  539.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/vim/</guid>
  540.      <pubDate>Sun, 17 Sep 2017 00:00:00 +0000</pubDate>
  541.    </item>
  542.    <item>
  543.      <title>Elliptic Curves and OpenVPN</title>
  544.      <link>https://www.maths.tcd.ie/~fionn/misc/ec_vpn/</link>
  545.      <description>The standard OpenVPN installation uses RSA and a hefty Diffie-Hellman parameters file. This is not ideal, but it’s possible to run OpenVPN using elliptic curves. […]</description>
  546.      <content:encoded><![CDATA[<p>
  547.      The standard OpenVPN installation uses RSA and a hefty Diffie-Hellman parameters
  548.      file. This is not ideal, but it’s possible to run OpenVPN using elliptic curves.
  549.      </p>
  550.      <p>
  551.      This was all done on OpenVPN 2.4.1. As far as I know, elliptic curve
  552.      cryptography support in OpenVPN is for 2.4.0+.
  553.      </p>
  554.      <h2>PKI</h2>
  555.      <p>
  556.      Get Easy-RSA and set up variables in the <code>vars</code> file.
  557.      </p>
  558.      <pre>
  559. set_var EASYRSA_ALGO     ec
  560. set_var EASYRSA_CURVE    secp521r1
  561. set_var EASYRSA_DIGEST   "sha512"
  562. </pre>
  563.      <p>
  564.      The choice of curve is a personal one. <code>secp521r1</code> is P-521. DJB <a
  565.      href="https://blog.cr.yp.to/20140323-ecdsa.html">considers it a nice prime</a>.
  566.      All supported curves are listed with <code>openvpn --show-curves</code> (<a
  567.      href="curves.txt">these are mine</a>).
  568.      </p>
  569.      <p>
  570.      There’s <a href="https://github.com/OpenVPN/easy-rsa/issues/111">a bug</a> in
  571.      Easy-RSA regarding sourcing this file. The workaround is to <code>export
  572.      EASYRSA_VARS_FILE=/etc/easy-rsa/vars</code> (or put it in <code>.bashrc</code>
  573.      or whatever).
  574.      </p>
  575.      <p>
  576.      Make the PKI and build the CA with <code>easyrsa init-pki</code>, <code>easyrsa
  577.      build-ca</code>.
  578.      </p>
  579.      <pre>
  580. <span class="root-shell">easyrsa gen-req <em>servername</em> nopass</span>
  581. <span class="root-shell">easyrsa sign-req server <em>servername</em></span>
  582. <span class="root-shell">easyrsa gen-req <em>clientname</em> [nopass]</span>
  583. <span class="root-shell">easyrsa sign-req client <em>clientname</em></span>
  584. </pre>
  585.      <p>We now have all the server files
  586.      </p>
  587.      <pre>
  588. pki/ca.crt
  589. pki/issued/<em>servername</em>.crt
  590. pki/private/<em>servername</em>.key
  591. </pre>
  592.      <p>
  593.      and all the client files
  594.      </p>
  595.      <pre>
  596. pki/ca.crt
  597. pki/issued/<em>clientname</em>.crt
  598. pki/private/<em>clientname</em>.key
  599. </pre>
  600.      <p>
  601.      (there’s some nonsense about 3DES-encrypting the client key, which I’m
  602.      ignoring).
  603.      </p>
  604.      <p>
  605.      If you didn’t set the <code>nopass</code> option but now regret it, run
  606.      <code>openssl ec -in <em>clientname</em>.key -out
  607.      <em>clientname</em>_nopass.key</code>, enter your password and rename the keys.
  608.      </p>
  609.      <h2>VPN</h2>
  610.      <p>
  611.      Copy the server and client files to their respective OpenVPN directories.
  612.      </p>
  613.      <p>
  614.      Here’s an example server configuration.
  615.      </p>
  616.      <pre>
  617. port 1194
  618. proto udp
  619. dev tun
  620.  
  621. ca ecc/ca.crt
  622. cert ecc/servername.crt
  623. key ecc/servername.key
  624.  
  625. dh none
  626.  
  627. server 10.8.0.0 255.255.255.0
  628. ifconfig-pool-persist ipp.txt
  629. push "redirect-gateway def1"
  630. push "dhcp-option DNS 1.2.3.4"
  631.  
  632. keepalive 10 120
  633.  
  634. tls-crypt ecc/tc.key
  635. auth SHA512
  636. keysize 256
  637. tls-server
  638. tls-version-min 1.2
  639. tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
  640. cipher AES-256-GCM
  641. reneg-sec 360
  642. remote-cert-eku "TLS Web Client Authentication"
  643. script-security 2
  644. auth-user-pass-verify /etc/openvpn/server/auth/auth.py via-file
  645.  
  646. user nobody
  647. group nobody
  648.  
  649. persist-key
  650. persist-tun
  651.  
  652. status openvpn-status.log
  653. explicit-exit-notify 1
  654. </pre>
  655.      <p>
  656.      And a client configuration.
  657.      </p>
  658.      <pre>
  659. client
  660. dev tun
  661. proto udp
  662. remote serverurl 1194
  663. resolv-retry infinite
  664. nobind
  665. #user nobody
  666. #group nobody
  667. persist-key
  668. persist-tun
  669. tls-client
  670. mute-replay-warnings
  671. ca servername/ecc/ca.crt
  672. cert servername/ecc/clientname.crt
  673. key servername/ecc/clientname.key
  674. remote-cert-eku "TLS Web Server Authentication"
  675. verify-x509-name 'CN=servername' subject
  676. remote-cert-tls server
  677. tls-crypt servername/ecc/tc.key
  678. cipher AES-256-GCM
  679. auth SHA512
  680. tls-version-min 1.2
  681. tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
  682. reneg-sec 360
  683. #comp-lzo
  684. verb 3
  685. #mute 20
  686.  
  687. auth-user-pass servername/secret.password
  688. redirect-gateway def1
  689. script-security 2
  690. up /etc/openvpn/client/servername/update-resolv-conf.sh
  691. down /etc/openvpn/client/servername/update-resolv-conf.sh
  692. </pre>
  693.      <p>
  694.      For several devices/users, managing certs, etc., can be tedious to do by hand. I
  695.      wrote some code to <a href="https://github.com/fionn/vpn-auth">automate it</a>.
  696.      </p>
  697.      ]]></content:encoded>
  698.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  699.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/ec_vpn/</guid>
  700.      <pubDate>Thu, 27 Apr 2017 00:00:00 +0000</pubDate>
  701.    </item>
  702.    <item>
  703.      <title>The Mersenne Twister</title>
  704.      <link>https://www.maths.tcd.ie/~fionn/misc/mt/</link>
  705.      <description>The Mersenne Twister is a 623-dimensionally equidistributed uniform pseudorandom number generator. This is how it works. […]</description>
  706.      <content:encoded><![CDATA[<p>
  707.      The Mersenne Twister is <a
  708.      href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf">a
  709.      623-dimensionally equidistributed uniform pseudorandom number generator</a>.
  710.      This is how it works.
  711.      </p>
  712.      <p>
  713.      The paper first defines a $k$-distribution as a very reasonable definition of
  714.      randomness. Read the paper first.
  715.      </p>
  716.      <h2 id="recurrence"><a class="anchor" href="#recurrence"></a>The Linear
  717.      Recurrence</h2>
  718.      <p>
  719.      Equation 2.1 in <em>M&amp;N</em> 1998 is the linear recurrence
  720.      $$
  721.      \mathbf{x}_{k + n} := \mathbf{x}_{k + m} \oplus (\mathbf{x}_k^u |
  722.      \mathbf{x}^l_{k + 1}) A
  723.      $$
  724.      ($k = 0, 1, \ldots$). The paper says the following.
  725.      </p>
  726.      <blockquote
  727.      cite="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf#page=6">
  728.      We have several constants: an integer $n$, which is the degree of the
  729.      recurrence, an integer $r$ (hidden in the definition of $\mathbf{x}_k^u$), $0
  730.      \leq r \leq w - 1$, an integer $m$, $1 \leq m \leq n$, and a constant $w \times
  731.      w$ matrix $A$ with entries in $\mathbb{F}_2$.
  732.      </blockquote>
  733.      <p>
  734.      From the paper, $w$ is the “word length”, so $\mathbf{x}_i \, \in \,
  735.      \mathbb{F}_2^w$ are “word vectors” of length $w$.
  736.      </p>
  737.      <p>
  738.      On the right, we have this $\mathbf{x}_k^u | \mathbf{x}^l_{k + 1}$ term. This is
  739.      the concatonation of $\mathbf{x}_k^u$ with $\mathbf{x}^l_{k + 1}$.
  740.      $\mathbf{x}_k^u$ is the “upper $w - r$ bits” of $\mathbf{x}_k$ and
  741.      $\mathbf{x}^l_{k + 1}$ is the “lower $r$ bits” of $\mathbf{x}_{k + 1}$, i.e.
  742.      denoting
  743.      $$
  744.      \mathbf{x}_k = (x_{w - 1}, \ldots, x_{r}, x_{r - 1}, \ldots, x_0),
  745.      $$
  746.      then
  747.      $$
  748.      \mathbf{x}_k^u = (x_{w - 1}, \ldots, x_{r}), \qquad
  749.      \mathbf{x}_k^l = (x_{r - 1}, \ldots, x_0).
  750.      $$
  751.      </p>
  752.      <p>
  753.      Given $n$ initial seeds $\mathbf{x}_0, \ldots, \mathbf{x}_{n - 1}$, we can
  754.      generate
  755.      $$
  756.      \mathbf{x}_{n} := \mathbf{x}_{m} \oplus (\mathbf{x}_0^u | \mathbf{x}^l_{1}) A
  757.      $$
  758.      (where $k = 0$). The only constants here are $n$, $m$, $r$ and $A$.
  759.      </p>
  760.      <p>
  761.      $A$ is the sparse matrix
  762.      $$
  763.      A = \begin{pmatrix}
  764.      0 &amp; 1 &amp; 0 &amp; \cdots &amp; 0 \\
  765.      0 &amp; 0 &amp; 1 &amp;        &amp; 0 \\
  766.      \vdots &amp; \vdots &amp; &amp; \ddots &amp; \vdots \\
  767.      0 &amp; 0 &amp; &amp; &amp; 1 \\
  768.      a_{w - 1} &amp; a_{w - 2} &amp; a_{w - 3} &amp; \cdots &amp; a_0
  769.      \end{pmatrix}
  770.      $$
  771.      where we denote the bottom row as $\mathbf{a} = (a_{w - 1}, \ldots, a_0)$.
  772.      </p>
  773.      <p>
  774.      For $\mathbf{x} = (x_{w - 1}, \ldots, x_0)$,
  775.      $$
  776.      \mathbf{x}A = (x_0 a_{w - 1}, x_{w - 1} + x_0 a_{w - 2}, \ldots, x_1 + x_0 a_0).
  777.      $$
  778.      </p>
  779.      <p>
  780.      Notice that if $x_0 = 0$, this simplifies to
  781.      $$
  782.      \mathbf{x}A = (0, x_{w - 1}, \ldots, x_1)
  783.      $$
  784.      which amounts to a right bitshift, i.e. $\mathbf{x}A = \mathbf{x} \gg 1$.
  785.      If $x_0 = 1$ instead, then
  786.      $$
  787.      \mathbf{x}A = (a_{w - 1}, x_{w - 1} + a_{w - 2}, \ldots, x_1 + a_0)
  788.      $$
  789.      and this reduces to an addition of $\mathbf{a}$, i.e. $\mathbf{x}A = (\mathbf{x}
  790.      \gg 1) \oplus \mathbf{a}$. (Recall that this is an xor, since we are working in
  791.      $\mathbb{F}_2$.)
  792.      </p>
  793.      <p>
  794.      For MT19937, the parameters are $w = 32$, $n = 624$, $m = 397$, $r = 31$ and
  795.      $\mathbf{a} = \mathtt{0x9908B0DF}$ (<em>M&amp;N</em> 1998, Table II).
  796.      </p>
  797.      <h2 id="initialisation"><a class="anchor"
  798.      href="#initialisation"></a>Initialisation</h2>
  799.      <p>
  800.      There is an undocumented parameter $f$ which is used to initialise the internal
  801.      state as
  802.      $$
  803.      \mathbf{x}_i = f \cdot (\mathbf{x}_{i - 1} \oplus (\mathbf{x}_{i - 1} \gg (w -
  804.      2))) + i.
  805.      $$
  806.      This is <a href="https://eprint.iacr.org/2005/165.pdf#page=4">given the
  807.      value</a> $f = 1812433253$.
  808.      </p>
  809.      <h2 id="tempering"><a class="anchor" href="#tempering"></a>Tempering</h2>
  810.      <p>
  811.      The linear operator $T$ is a $w \times w$ invertible matrix. We define
  812.      “tempering” to be the operation
  813.      $$
  814.      \mathbf{x} \mapsto \mathbf{z} = \mathbf{x} T.
  815.      $$
  816.      $T$ consists of the following bitwise operations.
  817.      $$\begin{aligned}
  818.      \mathbf{y} &amp;:= \mathbf{x} \oplus (\mathbf{x} \gg u), \\
  819.      \mathbf{y} &amp;:= \mathbf{y} \oplus \bigl((\mathbf{y} \ll s) \otimes
  820.      \mathbf{b}\bigr), \\
  821.      \mathbf{y} &amp;:= \mathbf{y} \oplus \bigl((\mathbf{y} \ll t) \otimes
  822.      \mathbf{c}\bigr), \\
  823.      \mathbf{z} &amp;:= \mathbf{y} \oplus (\mathbf{y} \gg l)
  824.      \end{aligned}$$
  825.      (equations 2.2 to 2.5). These parameters are $u = 11$, $s = 7$, $\mathbf{b} =
  826.      \mathtt{0x9D2C5680}$, $t = 15$, $\mathbf{c} = \mathtt{0xEFC60000}$ and $l = 18$
  827.      (<em>M&amp;N</em> 1998, Table II).
  828.      </p>
  829.      <h2 id="implementation"><a class="anchor" href="#implementation"></a>An
  830.      Implementation</h2>
  831.      <p>
  832.      This is the Mersenne Twister in Python. The linear recurrence occurs in
  833.      <code>_twist</code> and the tempering in <code>temper</code>.
  834.      </p>
  835.      <pre><code class="language-python">
  836. #!/usr/bin/env python3
  837. """The Mersenne Twister"""
  838.  
  839. class MT19937:
  840.    u = 11
  841.    s, b = 7, 0x9d2c5680
  842.    t, c = 15, 0xefc60000
  843.    l = 18
  844.  
  845.    def __init__(self, seed: int) -&gt; None:
  846.        self.index = 624
  847.        self.state = [0] * 624
  848.        self.state[0] = seed &amp; 0xffffffff
  849.        for i in range(1, 624):
  850.            self.state[i] = 0x6c078965 \
  851.                            * (self.state[i - 1] ^ self.state[i - 1] &gt;&gt; 30) \
  852.                            + i &amp; 0xffffffff
  853.  
  854.    @staticmethod
  855.    def temper(y: int) -&gt; int:
  856.        y ^= y &gt;&gt; MT19937.u
  857.        y ^= y &lt;&lt; MT19937.s &amp; MT19937.b
  858.        y ^= y &lt;&lt; MT19937.t &amp; MT19937.c
  859.        y ^= y &gt;&gt; MT19937.l
  860.        return y
  861.  
  862.    def random(self) -&gt; int:
  863.        if self.index &gt;= 624:
  864.            self._twist()
  865.        y = self.temper(self.state[self.index])
  866.        self.index += 1
  867.        return y
  868.  
  869.    def _twist(self) -&gt; None:
  870.        for i in range(624):
  871.            y = (self.state[i] &amp; 0x80000000) \
  872.                + (self.state[(i + 1) % 624] &amp; 0x7fffffff)
  873.            self.state[i] = self.state[(i + 397) % 624] ^ y &gt;&gt; 1
  874.            if y % 2 != 0:
  875.                self.state[i] ^= 0x9908b0df
  876.        self.index = 0
  877.  
  878. def main() -&gt; None:
  879.    x = MT19937(5489)      # Seed from mt19937ar.c
  880.    for _ in range(1000):
  881.        print(x.random())
  882.  
  883. if __name__ == "__main__":
  884.    main()
  885. </code></pre>
  886.      <h2 id="untempering"><a class="anchor" href="#untempering"></a>Untempering</h2>
  887.      <p>
  888.      The Mersenne Twister is not cryptographically secure since the transformation
  889.      $T$ is bijective. Due to the existence of $T^{-1}$, we can create an
  890.      “untempering” function. If we can record $n$ consecutive outputs of the Mersenne
  891.      Twister and untemper them, this will give us the internal state of the random
  892.      number generator and allow us to predict all future values.
  893.      </p>
  894.      <pre><code class="language-python">
  895. #!/usr/bin/env python3
  896. """Clone an MT19937 RNG from its output"""
  897.  
  898. from mt import MT19937
  899.  
  900. def untemper(y: int) -&gt; int:
  901.    y ^= y &gt;&gt; MT19937.l
  902.    y ^= y &lt;&lt; MT19937.t &amp; MT19937.c
  903.    for _ in range(7):
  904.        y ^= y &lt;&lt; MT19937.s &amp; MT19937.b
  905.    for _ in range(3):
  906.        y ^= y &gt;&gt; MT19937.u
  907.    return y
  908.  
  909. def clone_mt(mt: MT19937) -&gt; MT19937:
  910.    mt_clone = MT19937(0)
  911.    for i in range(624):
  912.        mt_clone.state[i] = untemper(mt.random())
  913.    return mt_clone
  914.  
  915. def main() -&gt; None:
  916.    mt = MT19937(5489)
  917.    mt_clone = clone_mt(mt)
  918.  
  919.    for _ in range(2000):
  920.        assert mt_clone.random() == mt.random()
  921.  
  922.    print(mt_clone)
  923.  
  924. if __name__ == "__main__":
  925.    main()
  926. </code></pre>
  927.      <p>
  928.      See <code><a
  929.      href="https://github.com/fionn/cryptopals/blob/master/m21.py">m21.py</a></code>
  930.      and <code><a
  931.      href="https://github.com/fionn/cryptopals/blob/master/m23.py">m23.py</a></code>
  932.      on <a href="https://github.com/fionn">my GitHub account</a>.
  933.      </p>
  934.      ]]></content:encoded>
  935.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  936.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/mt/</guid>
  937.      <pubDate>Tue, 23 May 2017 00:00:00 +0000</pubDate>
  938.    </item>
  939.    <item>
  940.      <title>Symmetry in Particle Physics</title>
  941.      <link>https://www.maths.tcd.ie/~fionn/misc/symmetry/</link>
  942.      <description>A while ago, I wrote an article for non-physicists about symmetry and the Standard Model. […]</description>
  943.      <content:encoded><![CDATA[<p>
  944.                  A while ago, I wrote an article for non-physicists about symmetry
  945.      and the Standard Model.
  946.                  </p>
  947.      <br/>
  948.      ]]></content:encoded>
  949.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  950.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/symmetry/</guid>
  951.      <pubDate>Mon, 26 Sep 2016 00:00:00 +0000</pubDate>
  952.    </item>
  953.    <item>
  954.      <title>The Padding Oracle Attack</title>
  955.      <link>https://www.maths.tcd.ie/~fionn/misc/padding_oracle/</link>
  956.      <description>There are a bunch of writeups on this attack, such as
  957. Robert Heaton's blog post,
  958. SkullSecurity
  959. (and their follow-up),
  960. GDS,
  961. mpgn,
  962. Grymoire,
  963. this crypto.SX post
  964. and the paper by Serge Vaudenay.
  965. Dan Boneh has a lecture on it
  966. and this video is good too.
  967. Here’s my digestion of it. […]</description>
  968.      <content:encoded><![CDATA[<p>
  969.      There are a bunch of writeups on this attack, such as
  970.      <a href="https://robertheaton.com/2013/07/29/padding-oracle-attack/">Robert
  971.      Heaton's blog post</a>,
  972.      <a
  973.      href="https://blog.skullsecurity.org/2013/padding-oracle-attacks-in-depth">SkullSecurity</a>
  974.      (and their <a
  975.      href="https://blog.skullsecurity.org/2013/a-padding-oracle-example#">follow-up</a>),
  976.      <a
  977.      href="https://blog.gdssecurity.com/labs/2010/9/14/automated-padding-oracle-attacks-with-padbuster.html">GDS</a>,
  978.      <a href="https://github.com/mpgn/Padding-oracle-attack">mpgn</a>,
  979.      <a
  980.      href="https://grymoire.wordpress.com/2014/12/05/cbc-padding-oracle-attacks-simplified-key-concepts-and-pitfalls/">Grymoire</a>,
  981.      this <a href="https://crypto.stackexchange.com/a/3772">crypto.SX post</a>
  982.      and the <a
  983.      href="https://www.iacr.org/archive/eurocrypt2002/23320530/cbc02_e02d.pdf">paper
  984.      by Serge Vaudenay</a>.
  985.      Dan Boneh has a <a
  986.      href="https://www.youtube.com/watch?v=evrgQkULQ5U">lecture</a> on it
  987.      and <a class="dead" title="https://www.youtube.com/watch?v=D-4mmc7frR4">this
  988.      video</a> is good too.
  989.      Here’s my digestion of it.</p>
  990.      <p>Let there be $n$ blocks of plaintext, each of blocksize $k$. For $i \in [1,
  991.      n]$,
  992.      $$\begin{aligned}
  993.      c_i &amp;= E(p_i \oplus  c_{i-1}), \\
  994.      p_i &amp;= D(c_i) \oplus c_{i-1}
  995.      \end{aligned}$$
  996.      where $c_i$ is the $i$<sup>th</sup> cyphertext block, $p_i$ the $i$<sup>th</sup>
  997.      plaintext block and $c_0$ the initialisation vector.
  998.      </p>
  999.      <p>
  1000.      Construct some block, which we will call $c'$. If we concatenate it with the
  1001.      last cyphertext block $c_n$, the corresponding plaintext of $c'|c_n$ would be
  1002.      $p_1'|p_2'$,
  1003.      $$\begin{aligned}
  1004.      p'_1 = D(c') \oplus c_0, \quad p'_2 &amp;= D(c_n) \oplus c' \\
  1005.      &amp;= D(E(p_n \oplus c_{n-1})) \oplus c' \\
  1006.      &amp;= p_n \oplus c_{n-1} \oplus c',
  1007.      \end{aligned}$$
  1008.      giving
  1009.      $$
  1010.      p_n = p_2' \oplus c' \oplus c_{n-1}.
  1011.      $$
  1012.      </p>
  1013.      <p>
  1014.      As $p_2'$ is at the end of our plaintext block it must have valid padding. This
  1015.      puts a constraint on $c'$. If only there was some way to tell if the plaintext
  1016.      had valid padding...
  1017.      </p>
  1018.      <h2>The Padding Oracle</h2>
  1019.      <p>
  1020.      For $p$ the plaintext corresponding to cyphertext $c$, define the padding oracle
  1021.      $\mathcal{O}$ as
  1022.      $$ \mathcal{O}(c) =
  1023.      \begin{cases}
  1024.      1 &amp; \text{if } p \text{ has valid padding}, \\
  1025.      0 &amp; \text{otherwise}.
  1026.      \end{cases}
  1027.      $$
  1028.      We can now construct $c'$ such that $p_2' = D(c_n) \oplus c'$ has valid padding,
  1029.      by submitting $c'|c_n$ to the oracle. If $\mathcal{O}(c'|c_n) = 1$, the padding
  1030.      in $p_2'$ is valid.
  1031.      </p>
  1032.      <h2>The Last Byte</h2>
  1033.      <p>
  1034.      Borrowing some programming notation, if we consider the last byte in $p_2'$ to
  1035.      be $p_2'[k] = \mathtt{\backslash x01}$, $p_2'$ will (trivially) have valid
  1036.      padding. If we can construct a $c'$ such that this is the case, we will know
  1037.      that the last byte of $p_2'$ is one.
  1038.      </p>
  1039.      <p>
  1040.      For such a $c'$, $c'_k$, say,
  1041.      $$\begin{aligned}
  1042.      p_n[k] &amp;= p_2'[k] \oplus c'_k[k] \oplus c_{n-1}[k] \\
  1043.             &amp;= 1 \oplus c'_k[k] \oplus c_{n-1}[k].
  1044.      \end{aligned}$$
  1045.      (Here $1 = \mathtt{\backslash x01}$. We’ll use this shorthand throughout.)
  1046.      </p>
  1047.      <p>
  1048.      To construct $c'_k$, it is enough to notice that since $p'_2 = D(c_n) \oplus
  1049.      c'_k$ and we are only interested in $p'_2[k] = D(c_n)[k] \oplus c'_k[k]$, we can
  1050.      let
  1051.      $$
  1052.      c'_k = (\mathtt{\backslash x00}, \mathtt{\backslash x00}, \ldots,
  1053.      \mathtt{\backslash x00}, b)$$
  1054.      (i.e. 15 bytes of zero, or whatever, and the final byte $c'_k[k] = b$).
  1055.      Iterating over all possible values of $b$ and submitting the cyphertext to the
  1056.      oracle will give us the value of $b$ that produces valid padding. Thus, we’ve
  1057.      found the last byte of the plaintext.
  1058.      </p>
  1059.      <h2>The Second-Last Byte</h2>
  1060.      <p>
  1061.      Another valid plaintext would be $p_2'[k] = p_2'[k-1] = \mathtt{\backslash
  1062.      x02}$.
  1063.      </p>
  1064.      <p>
  1065.      To construct $c'_{k-1}$, notice that $c'_{k-1}[k]$ will simply be the previous
  1066.      $c'_k[k]$ xored appropriately.
  1067.      $$\begin{aligned}
  1068.      p_2'[k] \oplus c'_k[k] &amp;= 1, \\
  1069.      p_2'[k] \oplus c'_k[k] &amp;\oplus 1 \oplus 2 = 2,
  1070.      \end{aligned}$$
  1071.      but
  1072.      $$
  1073.      p_2'[k] \oplus c'_{k-1}[k] = 2
  1074.      $$
  1075.      by definition of $c'_{k-1}$, so equating these we get
  1076.      $$
  1077.      p_2'[k] \oplus c'_{k-1}[k] = p_2'[k] \oplus c'_k[k] \oplus 1 \oplus 2,
  1078.      $$
  1079.      giving
  1080.      $$
  1081.      c'_{k-1}[k] = c'_k[k] \oplus 1 \oplus 2.
  1082.      $$
  1083.      </p>
  1084.      <p>$c'_{k-1}[k-1]$ is found by testing all possible values until
  1085.      $\mathcal{O}(c'_{k-1}|c_n) = 1$. Then the second-last byte is
  1086.      $$
  1087.      p_n[k-1] = 2 \oplus c'_{k-1}[k-1] \oplus c_{n-1}[k-1].
  1088.      $$
  1089.      </p>
  1090.      <h2>All the Bytes</h2>
  1091.      <p>
  1092.      In general, we get each byte of the plaintext block via
  1093.      $$
  1094.      p_n[k - i] = (i + 1) \oplus c_{k-i}'[k-i] \oplus c_{n-1}[k-i],
  1095.      $$
  1096.      for $i \in [0, k)$, where $c_i'$ is $c'$ constructed for the $i$<sup>th</sup>
  1097.      byte via
  1098.      $$
  1099.      c'_{k-i}[k - j] = c'_{k - i + 1}[k - j] \oplus i \oplus (i + 1)
  1100.      $$
  1101.      where $j \leq i$.
  1102.      </p>
  1103.      <h2>All the Blocks</h2>
  1104.      <p>
  1105.      This is repeated for each block, excluding the first (because we don’t know the
  1106.      initialisation vector).
  1107.      </p>
  1108.      <h2>Caveats</h2>
  1109.      <p>
  1110.      Notice that for finding the last byte $p_n[k]$ we iterated over all possible
  1111.      values of $c'[k] = b$ until $\mathcal{O}(c'|c_n) = 1$ and concluded then that
  1112.      $p_2'[k] = \mathtt{\backslash x01}$. However, there is a small probability
  1113.      ($\frac{1}{256}$) that $p_2'[k-1] = \mathtt{\backslash x02}$ and our oracle is
  1114.      satisfied because we’ve inadvertently found the cyphertext byte that corresponds
  1115.      to $p_2'[k] = \mathtt{\backslash x02}$.
  1116.      </p>
  1117.      <p>
  1118.      This could similarly happen if $p_2'[k-2] = p_2'[k-1] = \mathtt{\backslash
  1119.      x03}$, where we would get a positive result if $p_2' = \mathtt{\backslash x03}
  1120.      \neq \mathtt{\backslash x01}$, and so on. This becomes increasingly unlikely,
  1121.      but is easy to mitigate by instead approaching the problem from the left.
  1122.      </p>
  1123.      <p>
  1124.      Take $c_{n-1}|c_n$, which will obviously satisfy the oracle (and give $p_2' =
  1125.      p_n$). Then vary the bytes in $c_{n-1}$ from left to right and query the oracle
  1126.      each time. If the oracle returns false on the $i$<sup>th</sup> byte, then the
  1127.      remaining $k - i$ bytes are all equal to $k-i$. We also gain a substantial
  1128.      speedup on the last block as we get all the plaintext at once.
  1129.      </p>
  1130.      <p>
  1131.      Alternatively, we can check that when we determine the last byte it really is
  1132.      $\mathtt{\backslash x01}$. Then all the other bytes must be correct, too. To do
  1133.      this, vary the second last byte. If the padding is invalid, we know that we were
  1134.      wrong about the last byte so we try again. This only needs to be checked once
  1135.      per block. We lose the speedup advantage above, but it is simpler.
  1136.      </p>
  1137.      <h2>Code</h2>
  1138.      <p>
  1139.      I wrote a <a
  1140.      href="https://github.com/fionn/cryptopals/blob/master/m17.py">program</a> that
  1141.      does this.
  1142.      </p>
  1143.      <p>
  1144.      Here it is in action.
  1145.      </p>
  1146.      <noscript><p>
  1147.      You must enable JavaScript to see this :(
  1148.      </p></noscript>
  1149.      <asciinema-player author="Fionn Fitzmaurice"
  1150.      author-img-url="https://www.maths.tcd.ie/~fionn/me.jpg"
  1151.      author-url="https://www.maths.tcd.ie/~fionn/" cols="97" font-size="0.79em"
  1152.      poster="npt:1" rows="34" src="tyger.json" title="Padding Oracle Attack">
  1153.      </asciinema-player>
  1154.      <hr size="1"/>
  1155.      <p>
  1156.      Update: I gave a talk on this, the slides are <a
  1157.      href="padding_oracle.pdf">here</a>.
  1158.      </p>
  1159.      ]]></content:encoded>
  1160.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  1161.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/padding_oracle/</guid>
  1162.      <pubDate>Sat, 06 Aug 2016 00:00:00 +0000</pubDate>
  1163.    </item>
  1164.    <item>
  1165.      <title>Arch on a MacBook</title>
  1166.      <link>https://www.maths.tcd.ie/~fionn/misc/macbook/</link>
  1167.      <description>This is what I did to put Arch Linux on my MacBook Pro 12,1 (A1502, 2015) with dm-crypt (LVM on LUKS). Much of the start is taken from this blog post, but it’s reproduced here because of fear of link-rot. […]</description>
  1168.      <content:encoded><![CDATA[<p>
  1169.      This is what I did to put Arch Linux on my MacBook Pro <a
  1170.      href="https://support.apple.com/kb/sp715" title="Technical
  1171.      specifications">12,1</a> (A1502, 2015) with dm-crypt (LVM on LUKS). Much of the
  1172.      start is taken from <a
  1173.      href="https://loicpefferkorn.net/2015/01/arch-linux-on-macbook-pro-retina-2014-with-dm-crypt-lvm-and-suspend-to-disk/">this
  1174.      blog post</a>, but it’s reproduced here because of fear of link-rot.
  1175.      </p>
  1176.      <p>
  1177.      Here’s my hardware (from <code>lspci</code>).
  1178.      </p>
  1179.      <pre>
  1180. 00:00.0 Host bridge: Intel Corporation Broadwell-U Host Bridge -OPI (rev 09)
  1181. 00:02.0 VGA compatible controller: Intel Corporation Broadwell-U Integrated Graphics (rev 09)
  1182. 00:03.0 Audio device: Intel Corporation Broadwell-U Audio Controller (rev 09)
  1183. 00:14.0 USB controller: Intel Corporation Wildcat Point-LP USB xHCI Controller (rev 03)
  1184. 00:15.0 DMA controller: Intel Corporation Wildcat Point-LP Serial IO DMA Controller (rev 03)
  1185. 00:15.4 Serial bus controller [0c80]: Intel Corporation Wildcat Point-LP Serial IO GSPI Controller #1 (rev 03)
  1186. 00:16.0 Communication controller: Intel Corporation Wildcat Point-LP MEI Controller #1 (rev 03)
  1187. 00:1b.0 Audio device: Intel Corporation Wildcat Point-LP High Definition Audio Controller (rev 03)
  1188. 00:1c.0 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #1 (rev e3)
  1189. 00:1c.1 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #2 (rev e3)
  1190. 00:1c.2 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #3 (rev e3)
  1191. 00:1c.4 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #5 (rev e3)
  1192. 00:1c.5 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #6 (rev e3)
  1193. 00:1f.0 ISA bridge: Intel Corporation Wildcat Point-LP LPC Controller (rev 03)
  1194. 00:1f.3 SMBus: Intel Corporation Wildcat Point-LP SMBus Controller (rev 03)
  1195. 00:1f.6 Signal processing controller: Intel Corporation Wildcat Point-LP Thermal Management Controller (rev 03)
  1196. 02:00.0 Multimedia controller: Broadcom Corporation 720p FaceTime HD Camera
  1197. 03:00.0 Network controller: Broadcom Corporation BCM43602 802.11ac Wireless LAN SoC (rev 01)
  1198. 04:00.0 SATA controller: Samsung Electronics Co Ltd Device a801 (rev 01)
  1199. 05:00.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
  1200. 06:00.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
  1201. 06:03.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
  1202. 06:04.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
  1203. 06:05.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
  1204. 06:06.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
  1205. 07:00.0 System peripheral: Intel Corporation DSL5520 Thunderbolt 2 NHI [Falcon Ridge 4C 2013]
  1206. </pre>
  1207.      <p>
  1208.      This is the partition scheme we’ll end up with (45 GiB for OS X, 10 GiB for a
  1209.      shared HFS+ partition and the rest (~177.8 GiB) for a LVM container).
  1210.      </p>
  1211.      <pre class="shell">
  1212. sudo gdisk -l /dev/sda
  1213. GPT fdisk (gdisk) version 1.0.1
  1214.  
  1215. Partition table scan:
  1216.  MBR: hybrid
  1217.  BSD: not present
  1218.  APM: not present
  1219.  GPT: present
  1220.  
  1221. Found valid GPT with hybrid MBR; using GPT.
  1222. Disk /dev/sda: 490234752 sectors, 233.8 GiB
  1223. Logical sector size: 512 bytes
  1224. Disk identifier (GUID): XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
  1225. Partition table holds up to 128 entries
  1226. First usable sector is 34, last usable sector is 490234718
  1227. Partitions will be aligned on 8-sector boundaries
  1228. Total free space is 262150 sectors (128.0 MiB)
  1229.  
  1230. Number  Start (sector)    End (sector)  Size       Code  Name
  1231.   1              40          409639   200.0 MiB   EF00  EFI System Partition
  1232.   2          409640        94865191   45.0 GiB    AF05  Customer
  1233.   3        94865192        96134727   619.9 MiB   AB00  Recovery HD
  1234.   4        96396872       117368391   10.0 GiB    AF00  hfs
  1235.   5       117368392       490234718   177.8 GiB   8E00  archlinux
  1236. </pre>
  1237.      <p>
  1238.      It’s probably a good idea to make a backup first. I didn’t because I like to
  1239.      live on the edge. You can boot into recovery mode later if you need to with
  1240.      <kbd>⌘</kbd> + <kbd>R</kbd>.
  1241.      </p>
  1242.      <h2 id="osx"><a class="anchor" href="#osx"></a>OS X</h2>
  1243.      <p>
  1244.      Get an <a href="https://archlinux.org/download/">Arch image</a>, verify it and
  1245.      burn it to a USB key with something like
  1246.      </p>
  1247.      <pre class="root-shell">
  1248. dd if=archlinux-2016.05.01-dual.iso of=/dev/rdisk2 bs=4M &amp;&amp; sync
  1249. </pre>
  1250.      <p>
  1251.      where we use <code><b>r</b>disk2</code> to write to the raw disk and skip some
  1252.      buffering. Use <code>diskutil</code> to figure out which disk to use.
  1253.      </p>
  1254.      <p>
  1255.      Then resize the OS X partition and encrypt it with FileVault.
  1256.      </p>
  1257.      <h2 id="archlinux"><a class="anchor" href="#archlinux"></a>Arch Linux</h2>
  1258.      <p>
  1259.      Boot into Arch by holding the right <kbd>alt</kbd> key. To make the console font
  1260.      larger, use <code>setfont sun12x22</code> (the biggest one on the system).
  1261.      </p>
  1262.      <p>
  1263.      I had to set
  1264.      </p>
  1265.      <pre class="root-shell">
  1266. echo 0 &gt; /sys/module/hid_apple/parameters/iso_layout
  1267. </pre>
  1268.      <p>
  1269.      to fix the keyboard layout, swapping <kbd>`</kbd> and <kbd>~</kbd> with
  1270.      <kbd>&lt;</kbd> and <kbd>&gt;</kbd>. (See <a
  1271.      href="https://wiki.archlinux.org/title/Apple_Keyboard#%3C_and_%3E_have_changed_place_with_^_and_%C2%B0_(or_@_and_#,_or_%60_and_~)">aw:
  1272.      Apple Keyboard</a>.)
  1273.      </p>
  1274.      <p>
  1275.      Then run <code>timedatectl set-ntp true</code>, connect to the internet and
  1276.      update.
  1277.      </p>
  1278.      <h2 id="partitioning"><a class="anchor"
  1279.      href="#partitioning"></a>Partitioning</h2>
  1280.      <p>
  1281.      Apple <a
  1282.      href="https://developer.apple.com/library/archive/technotes/tn2166/_index.html">recommend</a>
  1283.      leaving a 128 MiB gap between partitions.
  1284.      </p>
  1285.      <blockquote
  1286.      cite="https://developer.apple.com/library/archive/technotes/tn2166/_index.html">
  1287.      We leave free space after each partition to make it easier for future system
  1288.      software to manipulate the partition map in ways that we can’t anticipate
  1289.      currently.
  1290.      </blockquote>
  1291.      <p>
  1292.      It’s debatable whether this is worthwhile.
  1293.      </p>
  1294.      <p>
  1295.      With <code>cgdisk</code>:
  1296.      </p>
  1297.      <ul>
  1298.      <li>delete the empty Apple partition;</li>
  1299.      <li>make a small future HFS/HFS+ (<code>af00</code>) partition starting with
  1300.      <code>+128M</code>;</li>
  1301.      <li>make a large LVM (<code>8e00</code>) partition for the rest of the
  1302.      disk;</li>
  1303.      <li>write.</li>
  1304.      </ul>
  1305.      <p>
  1306.      It should look like this in the end.
  1307.      </p>
  1308.      <pre>
  1309. Part. #     Size        Partition Type            Partition Name
  1310. ----------------------------------------------------------------
  1311.            3.0 KiB     free space
  1312.   1        200.0 MiB   EFI System                EFI System Partition
  1313.   2        45.0 GiB    Apple Core Storage        Customer
  1314.   3        619.9 MiB   Recovery HD               Recovery HD
  1315.            128.0 MiB   free space
  1316.   4        10.0 GiB    Apple HFS/HFS+            hfs
  1317.   5        177.8 GiB   Linux LVM                 archlinux
  1318. </pre>
  1319.      <h2 id="encrypting"><a class="anchor" href="#encrypting"></a>Encrypting</h2>
  1320.      <p>
  1321.      We’re going to encrypt <code>/dev/sdc5</code> with <a
  1322.      href="https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#LVM_on_LUKS">LVM
  1323.      on LUKS</a>. These are approximately the results I got from <code>cryptsetup
  1324.      benchmark</code>.
  1325.      </p>
  1326.      <pre class="root-shell">
  1327. cryptsetup benchmark
  1328. # Tests are approximate using memory only (no storage IO).
  1329. PBKDF2-sha1      1213629 iterations per second for 256-bit key
  1330. PBKDF2-sha256    1354749 iterations per second for 256-bit key
  1331. PBKDF2-sha512    1100289 iterations per second for 256-bit key
  1332. PBKDF2-ripemd160  897753 iterations per second for 256-bit key
  1333. PBKDF2-whirlpool  666185 iterations per second for 256-bit key
  1334. #  Algorithm | Key |  Encryption |  Decryption
  1335.     aes-cbc   128b   601.2 MiB/s  2589.5 MiB/s
  1336. serpent-cbc   128b    78.5 MiB/s   511.4 MiB/s
  1337. twofish-cbc   128b   178.7 MiB/s   328.4 MiB/s
  1338.     aes-cbc   256b   443.6 MiB/s  1964.6 MiB/s
  1339. serpent-cbc   256b    79.6 MiB/s   511.2 MiB/s
  1340. twofish-cbc   256b   180.1 MiB/s   328.4 MiB/s
  1341.     aes-xts   256b  2194.5 MiB/s  2182.6 MiB/s
  1342. serpent-xts   256b   492.9 MiB/s   496.6 MiB/s
  1343. twofish-xts   256b   319.2 MiB/s   324.4 MiB/s
  1344.     aes-xts   512b  1703.8 MiB/s  1689.3 MiB/s
  1345. serpent-xts   512b   513.7 MiB/s   496.8 MiB/s
  1346. twofish-xts   512b   285.3 MiB/s   324.8 MiB/s
  1347. </pre>
  1348.      <p>
  1349.      First we must <a
  1350.      href="https://gitlab.com/cryptsetup/cryptsetup/-/wiki_pages/FrequentlyAskedQuestions#5-security-aspects">fill
  1351.      the partition</a> with random-looking data. There is a clever way to do this
  1352.      with dm-crypt.
  1353.      </p>
  1354.      <pre>
  1355. <span class="root-shell">cryptsetup open --type plain /dev/sdc5 container --key-file /dev/random</span>
  1356. <span class="root-shell">dd if=/dev/zero of=/dev/mapper/container bs=1M status=progress</span>
  1357. <span class="root-shell">cryptsetup close container</span>
  1358. </pre>
  1359.      <p>
  1360.      This took about 700 seconds. Next, encrypt the partition and put a logical
  1361.      volume on it.
  1362.      </p>
  1363.      <pre>
  1364. <span class="root-shell">cryptsetup -v --cipher aes-xts-plain64 --key-size 256 --hash sha256 --iter-time 2000 --use-urandom --verify-password luksFormat /dev/sdc5</span>
  1365. <span class="root-shell">cryptsetup luksOpen /dev/sdc5 lvm</span>
  1366. <span class="root-shell">pvcreate /dev/mapper/lvm</span>
  1367. <span class="root-shell">vgcreate vgcrypt /dev/mapper/lvm</span>
  1368. <span class="root-shell">lvcreate --extents 100%FREE -n root vgcrypt</span>
  1369. <span class="root-shell">mkfs.ext4 /dev/mapper/vgcrypt-root</span>
  1370. </pre>
  1371.      <p>
  1372.      Now we can mount the volume with
  1373.      </p>
  1374.      <pre>
  1375. <span class="root-shell">mount /dev/mapper/vgcrypt-root /mnt</span>
  1376. <span class="root-shell">mkdir /mnt/boot</span>
  1377. <span class="root-shell">mount /dev/sdc1 /mnt/boot</span>
  1378. </pre>
  1379.      <p>
  1380.      where <code>/dev/sdc1</code> is the EFI system partition.
  1381.      </p>
  1382.      <h2 id="chrooting"><a class="anchor" href="#chrooting"></a>Chrooting</h2>
  1383.      <p>
  1384.      The rest follows the <a
  1385.      href="https://wiki.archlinux.org/title/Installation_guide">wiki</a> quite
  1386.      closely.
  1387.      </p>
  1388.      <pre>
  1389. <span class="root-shell">pacstrap -i /mnt base base-devel</span>
  1390. <span class="root-shell">genfstab -U /mnt &gt;&gt; /mnt/etc/fstab</span>
  1391. </pre>
  1392.      <p>
  1393.      The <code>-U</code> flag tells <code>genfstab</code> to use UUIDs. Now would be
  1394.      a good time to edit the <code>fstab</code> to add the <em>discard</em> option
  1395.      for TRIM, but let’s hold off on that.
  1396.      </p>
  1397.      <pre>
  1398. <span class="root-shell">arch-chroot /mnt /bin/bash</span>
  1399. <span class="root-shell">echo <em>xyza</em> &gt; /etc/hostname</span>
  1400. </pre>
  1401.      <p>
  1402.      Edit <code>/etc/locale.gen</code> and uncomment <code>#en_IE.UTF-8</code>.
  1403.      </p>
  1404.      <pre>
  1405. <span class="root-shell">locale-gen</span>
  1406. <span class="root-shell">echo "LANG=en_IE.UTF-8" &gt; /etc/locale.conf</span>
  1407. <span class="root-shell">ln -s /usr/share/zoneinfo/Europe/Dublin /etc/localtime</span>
  1408. </pre>
  1409.      <p>
  1410.      Edit the <code>/etc/mkinitcpio.conf</code> <code>MODULES</code> and
  1411.      <code>HOOKS</code>
  1412.      </p>
  1413.      <pre>
  1414. MODULES="i915"    # for a smoother boot screen
  1415. HOOKS="base udev consolefont autodetect modconf block keymap keyboard encrypt lvm2 filesystems fsck"
  1416. </pre>
  1417.      <p>
  1418.      and build the initial ramdisk with <code>mkinitcpio -p linux</code>.
  1419.      </p>
  1420.      <p>
  1421.      Now set up the bootloader.
  1422.      </p>
  1423.      <pre>
  1424. <span class="root-shell">mkdir -p /boot/loader/entries</span>
  1425. <span class="root-shell">vi /boot/loader/loader.conf</span>
  1426. </pre>
  1427.      <p>
  1428.      and add
  1429.      </p>
  1430.      <pre>
  1431. default arch.conf
  1432. timeout 3
  1433. </pre>
  1434.      <p>
  1435.      Check that <code>dev/sdc1</code> is mounted properly with <code>findmnt
  1436.      /boot</code>. Then make and edit <code>/boot/loader/entries/arch.conf</code>.
  1437.      </p>
  1438.      <pre>
  1439. title       Arch Linux
  1440. linux       /vmlinuz-linux
  1441. initrd      /initramfs-linux.img
  1442. options     cryptdevice=/dev/sda5:vgcrypt:allow-discards root=/dev/mapper/vgcrypt-root rw
  1443. </pre>
  1444.      <p>
  1445.      Note that there are <a
  1446.      href="https://wiki.archlinux.org/title/Dm-crypt/Specialties#Discard.2FTRIM_support_for_solid_state_drives_.28SSD.29">security
  1447.      implications</a> with enabling TRIM/discards.
  1448.      </p>
  1449.      <pre>
  1450. <span class="root-shell">bootctl install</span>
  1451. <span class="root-shell">pacman -S iw wpa_supplicant dialog</span>
  1452. <span class="root-shell">passwd</span>
  1453. </pre>
  1454.      <p>
  1455.      Shutdown, remove the installation media and reboot.
  1456.      </p>
  1457.      <h2 id="configuration"><a class="anchor"
  1458.      href="#configuration"></a>Configuration</h2>
  1459.      <p>
  1460.      Let’s make some swap space.
  1461.      </p>
  1462.      <pre>
  1463. <span class="root-shell">fallocate -l 8G /swapfile</span>
  1464. <span class="root-shell">chmod 600 /swapfile</span>
  1465. <span class="root-shell">mkswap swapfile</span>
  1466. <span class="root-shell">swapon /swapfile</span>
  1467. </pre>
  1468.      <p>
  1469.      Check that this worked with <code>free -h</code> or <code>swapon --show</code>
  1470.      and add
  1471.      </p>
  1472.      <pre>
  1473. /swapfile none swap defaults 0 0
  1474. </pre>
  1475.      <p>
  1476.      to the <code>fstab</code>.
  1477.      </p>
  1478.      <p>
  1479.      For user management, make a new user and add them to the admin group.
  1480.      </p>
  1481.      <pre>
  1482. <span class="root-shell">useradd -m -G wheel -s /bin/bash <em>fionn</em></span>
  1483. <span class="root-shell">passwd <em>fionn</em></span>
  1484. </pre>
  1485.      <p>
  1486.      Then run <code>visudo</code>, uncomment <code># %wheel ALL=(ALL) ALL</code>, log
  1487.      out and then back in again as a regular user.
  1488.      </p>
  1489.      <pre class="shell">
  1490. sudo pacman -Syu bash-completion pkgfile
  1491. </pre>
  1492.      <p>
  1493.      Now would be a good time to import <a
  1494.      href="https://github.com/fionn/.dotfiles">.dotfiles</a>.
  1495.      </p>
  1496.      <p>
  1497.      To get <code>netctl</code> to automatically connect to networks, install
  1498.      <code>wpa_actiond</code> and enable <code>netctl-auto@wlp3s0.service</code>.
  1499.      </p>
  1500.      <p>
  1501.      The console font is <small><em>very small</em></small>. Install
  1502.      <code>terminus-font</code> and add the line
  1503.      </p>
  1504.      <pre>
  1505. FONT=ter-124n
  1506. </pre>
  1507.      <p>
  1508.      to <code>/etc/vconsole.conf</code>.
  1509.      </p>
  1510.      <h2 id="x11"><a class="anchor" href="#x11"></a>X11</h2>
  1511.      <p>
  1512.      <code>xf86-video-intel</code> seems to be necessary to avoid screen tearing
  1513.      (<code>xf86-video-modesetting</code> doesn’t seem to help here). Edit
  1514.      <code>/etc/X11/xorg.conf.d/20-intel.conf</code>.
  1515.      </p>
  1516.      <pre>
  1517. Section "Device"
  1518.   Identifier  "Intel Graphics"
  1519.   Driver      "intel"
  1520.   Option      "TearFree" "true"
  1521. EndSection
  1522. </pre>
  1523.      <p>
  1524.      There’s a lot of talk about <a
  1525.      href="https://github.com/BlueDragonX/xf86-input-mtrack"><code>xf86-input-mtrack</code></a>,
  1526.      but I find synaptics to be just fine. Here’s my <code>/etc/X11/xorg.conf.d/<a
  1527.      href="50-synaptics.conf">50-synaptics.conf</a></code>. (<code>1</code>,
  1528.      <code>2</code> and <code>3</code> correspond to left, middle and right.)
  1529.      </p>
  1530.      <pre>
  1531. # Example xorg.conf.d snippet that assigns the touchpad driver
  1532. # to all touchpads. See xorg.conf.d(5) for more information on
  1533. # InputClass.
  1534. # DO NOT EDIT THIS FILE, your distribution will likely overwrite
  1535. # it when updating. Copy (and rename) this file into
  1536. # /etc/X11/xorg.conf.d first.
  1537. # Additional options may be added in the form of
  1538. #   Option "OptionName" "value"
  1539. #
  1540. Section "InputClass"
  1541.        Identifier "touchpad catchall"
  1542.        Driver "synaptics"
  1543.        MatchIsTouchpad "on"
  1544.        Option "TapButton1" "0"   # 1, 2, 3 for tapping
  1545.        Option "TapButton2" "0"
  1546.        Option "TapButton3" "0"
  1547. # Custom options
  1548.        Option "ClickFinger2" "2"
  1549.        Option "ClickFinger3" "3"
  1550.        Option "HorizTwoFingerScroll" "1"
  1551.        Option "VertEdgeScroll" "1"
  1552.        Option "PalmDetect" "1"
  1553.        Option "RBCornerButton" "3"
  1554. # This option is recommend on all Linux systems using evdev, but cannot be
  1555. # enabled by default. See the following link for details:
  1556. # https://who-t.blogspot.com/2010/11/how-to-ignore-configuration-errors.html
  1557.        MatchDevicePath "/dev/input/event*"
  1558. EndSection
  1559.  
  1560. Section "InputClass"
  1561.        Identifier "touchpad ignore duplicates"
  1562.        MatchIsTouchpad "on"
  1563.        MatchOS "Linux"
  1564.        MatchDevicePath "/dev/input/mouse*"
  1565.        Option "Ignore" "on"
  1566. EndSection
  1567.  
  1568. # This option enables the bottom right corner to be a right button on clickpads
  1569. # and the right and middle top areas to be right / middle buttons on clickpads
  1570. # with a top button area.
  1571. # This option is only interpreted by clickpads.
  1572. Section "InputClass"
  1573.        Identifier "Default clickpad buttons"
  1574.        MatchDriver "synaptics"
  1575.        Option "SoftButtonAreas" "50% 0 82% 0 0 0 0 0"
  1576.        Option "SecondarySoftButtonAreas" "58% 0 0 15% 42% 58% 0 15%"
  1577. EndSection
  1578.  
  1579. # This option disables software buttons on Apple touchpads.
  1580. # This option is only interpreted by clickpads.
  1581. Section "InputClass"
  1582.        Identifier "Disable clickpad buttons on Apple touchpads"
  1583.        MatchProduct "Apple|bcm5974"
  1584.        MatchDriver "synaptics"
  1585.        #Option "SoftButtonAreas" "0 0 0 0 0 0 0 0"
  1586. EndSection
  1587. </pre>
  1588.      <p>
  1589.      To swap the function and media keys, edit
  1590.      <code>/etc/modprobe.d/hid_apple.conf</code>.
  1591.      </p>
  1592.      <pre>
  1593. options hid_apple iso_layout=0   # for the key swap earlier
  1594. options hid_apple fnmode=2
  1595. </pre>
  1596.      <p>
  1597.      To map the media keys to the hardware, install <code>xorg-xbacklight</code>,
  1598.      <code>alsa-utils</code> and, from the AUR, <a
  1599.      href="https://aur.archlinux.org/packages/kbdlight/"><code>kbdlight</code></a>.
  1600.      Edit <code>/etc/modprobe.d/snd_hda_intel.conf</code>.
  1601.      </p>
  1602.      <pre>
  1603. options snd_hda_intel index=1,0
  1604. </pre>
  1605.      <p>
  1606.      Bind the keys in <code>~/.i3/config</code> with something like this.
  1607.      </p>
  1608.      <pre>
  1609. bindsym XF86KbdBrightnessUp exec --no-startup-id kbdlight up
  1610. </pre>
  1611.      <h2 id="lid"><a class="anchor" href="#lid"></a>Lid</h2>
  1612.      <p>
  1613.      Edit <code>/etc/systemd/logind.conf</code> and set
  1614.      <code>HandleLidSwitch=Ignore</code> to stop the laptop from suspending whenever
  1615.      the lid is closed.
  1616.      </p>
  1617.      <h2 id="mirrors"><a class="anchor" href="#mirrors"></a>Mirrors</h2>
  1618.      <p>
  1619.      Grab a new mirrorlist with
  1620.      </p>
  1621.      <pre>
  1622. <span class="shell">cd /etc/pacman.d</span>
  1623. <span class="shell">sudo mv mirrorlist mirrorlist.bkup</span>
  1624. <span class="shell">sudo wget <a href="https://www.archlinux.org/mirrorlist/?country=all">https://www.archlinux.org/mirrorlist/?country=all</a> -O mirrorlist</span>
  1625. </pre>
  1626.      <p>
  1627.      and uncomment a mirror.
  1628.      </p>
  1629.      <h2 id="trim"><a class="anchor" href="#trim"></a>TRIM</h2>
  1630.      <p>
  1631.      TRIM the filesystem.
  1632.      </p>
  1633.      <pre class="shell">
  1634. sudo fstrim -v /
  1635. /: 163.5 GiB (175549890560 bytes) trimmed
  1636. </pre>
  1637.      <p>
  1638.      Then enable <code>fstrim.timer</code> to periodically issue discards.
  1639.      </p>
  1640.      <h2 id="dpp"><a class="anchor" href="#dpp"></a>DPP</h2>
  1641.      <p>
  1642.      Put <code>xrandr --dpi 144</code> in <code>~/.xinitrc</code>.
  1643.      </p>
  1644.      <p>
  1645.      GTK3+ is supposed to pick up the system DPP settings, but it doesn’t for me. The
  1646.      solution is to set the font size to around 16 (using e.g.
  1647.      <code>lxappearance-gtk3</code>). For Firefox, set
  1648.      <code>layout.css.devPixelsPerPixel=1.4</code> in <code>about:config</code>.
  1649.      </p>
  1650.      <p>
  1651.      For QT to pick up on the GTK theme, install <code>adwaita-qt5</code> from the
  1652.      AUR. <em>Also export QT_STYLE_OVERRIDE=GTK+?</em>
  1653.      </p>
  1654.      ]]></content:encoded>
  1655.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  1656.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/macbook/</guid>
  1657.      <pubDate>Sun, 22 May 2016 00:00:00 +0000</pubDate>
  1658.    </item>
  1659.    <item>
  1660.      <title>A Raspberry Pi Tor Relay</title>
  1661.      <link>https://www.maths.tcd.ie/~fionn/misc/alarmpi_tor/</link>
  1662.      <description>Make an alarmpi directory, cd to it and follow the Arch Linux ARM installation instructions. But in step 5, instead of just wgetting the tarball, also do […]</description>
  1663.      <content:encoded><![CDATA[<p>
  1664.      Make an <code>alarmpi</code> directory, <code>cd</code> to it and follow the
  1665.      Arch Linux ARM <a
  1666.      href="https://archlinuxarm.org/platforms/armv7/broadcom/raspberry-pi-2">installation
  1667.      instructions</a>. But in step 5, instead of just <code>wget</code>ting the
  1668.      tarball, also do
  1669.      </p>
  1670.      <pre>
  1671. <span class="shell">wget <a href="https://archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz.md5">https://archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz.md5</a></span>
  1672. <span class="shell">wget <a href="https://archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz.sig">https://archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz.sig</a></span>
  1673. </pre>
  1674.      <p>
  1675.      (note that there’s some TLS-stripping redirection). Compare the <code>md5</code>
  1676.      hash (<code>md5sum -c</code>) and verify the signature by getting the Arch Linux
  1677.      ARM <a href="https://archlinuxarm.org/about/package-signing">package signing
  1678.      key</a> (<a
  1679.      href="https://pgp.circl.lu/pks/lookup?op=vindex&amp;fingerprint=on&amp;search=0x68B3537F39A313B3E574D06777193F152BDBE6A6"><code>0x77193F152BDBE6A6</code></a>).
  1680.      </p>
  1681.      <p>
  1682.      Once we’re in the Pi, the first thing to do is set up package signing by <a
  1683.      href="https://archlinuxarm.org/about/package-signing">following these
  1684.      instructions</a>.
  1685.      </p>
  1686.      <p>
  1687.      Then update and grab some useful packages.
  1688.      </p>
  1689.      <pre>
  1690. <span class="root-shell">pacman -Syu</span>
  1691. <span class="root-shell">pacman -S sudo vim bash-completion</span>
  1692. </pre>
  1693.      <p>
  1694.      Now it’s time for some user management. First enable root login over SSH
  1695.      (temporarily) by editing <code>/etc/ssh/sshd_config</code> and adding
  1696.      </p>
  1697.      <pre>
  1698. PermitRootLogin yes
  1699. </pre>
  1700.      <p>
  1701.      and then reloading the dæmon. Log out and then back in as root. This is so we
  1702.      can change the <code>alarm</code> username.
  1703.      </p>
  1704.      <pre>
  1705. <span class="root-shell">usermod -l <em>username</em> alarm</span>
  1706. <span class="root-shell">usermod -d /home/<em>username</em> -m <em>username</em></span>
  1707. </pre>
  1708.      <p>
  1709.      Disallow SSH root logins again and reload the dæmon.
  1710.      </p>
  1711.      <p>
  1712.      (This isn’t necessary if you have a keyboard and screen. We’re strictly headless
  1713.      here.)
  1714.      </p>
  1715.      <p>
  1716.      Run <code>visudo</code> and uncomment the line
  1717.      </p>
  1718.      <pre>
  1719. # %wheel ALL=(ALL) ALL
  1720. </pre>
  1721.      <p>
  1722.      to add the user to the sudoers file.
  1723.      </p>
  1724.      <p>
  1725.      Now would be a good time to change the passwords. Do
  1726.      </p>
  1727.      <pre>
  1728. <span class="root-shell">passwd root</span>
  1729. <span class="root-shell">passwd <em>username</em></span>
  1730. </pre>
  1731.      <p>
  1732.      and log back in as the user.
  1733.      </p>
  1734.      <p>
  1735.      Now that the system is taking shape, let’s do some customising before we get to
  1736.      Tor.
  1737.      </p>
  1738.      <p>
  1739.      To make things a bit friendlier, download your <a href="../vim/">Vim
  1740.      configuration</a>.
  1741.      </p>
  1742.      <p>
  1743.      Next up, set the <a href="https://wiki.archlinux.org/title/Locale">locale</a>
  1744.      and <a
  1745.      href="https://wiki.archlinux.org/title/System_time#Time_zone">timezone</a> stuff
  1746.      (see the <a
  1747.      href="https://wiki.archlinux.org/title/Installation_guide#Configure_the_system">installation
  1748.      guide</a>).
  1749.      </p>
  1750.      <pre class="root-shell">
  1751. localectl set-locale LANG=en_IE.UTF-8
  1752. </pre>
  1753.      <p>
  1754.      Change the hostname with
  1755.      </p>
  1756.      <pre class="root-shell">
  1757. hostnamectl set-hostname <em>hostname</em>
  1758. </pre>
  1759.      <p>
  1760.      and edit <code>/etc/hosts</code> and <a
  1761.      href="https://wiki.archlinux.org/title/Network_configuration#Set_the_hostname">add
  1762.      the hostname to the end</a>.
  1763.      </p>
  1764.      <p>
  1765.      OK, now let’s get Tor (and <code>arm</code>).
  1766.      </p>
  1767.      <pre class="shell">
  1768. sudo pacman -S tor arm
  1769. </pre>
  1770.      <p>
  1771.      Edit <code>/etc/tor/torrc</code> to make it a relay. There might be some
  1772.      port-forwarding to be done for the ORPort (9001) and DirPort (9030) as well as
  1773.      SocksPort (9050). Note that we don’t need to run Tor as a dæmon — systemd takes
  1774.      care of that.
  1775.      </p>
  1776.      <p>
  1777.      To get <code>arm</code> working we need to open up the control port, but it’s
  1778.      not safe to do so without some authentication. Run
  1779.      </p>
  1780.      <pre class="shell">
  1781. tor --hash-password <em>password</em>
  1782. </pre>
  1783.      <p>
  1784.      and paste the hash into the <code>HashedControlPassword</code> line. Then open
  1785.      up the control port on port 9051.
  1786.      </p>
  1787.      <p>
  1788.      Start Tor and check its status. If all seems well, enable it. Run
  1789.      </p>
  1790.      <pre class="shell">
  1791. sudo -u tor arm
  1792. </pre>
  1793.      <p>
  1794.      to see how things are going.
  1795.      </p>
  1796.      <p>
  1797.      <del>The last thing to do for Tor is sign up for the <a class="dead"
  1798.      title="https://weather.torproject.org/">weather reports</a>.</del>
  1799.      </p>
  1800.      <p>
  1801.      We’re done! But wait. Our relay is vulnerable. Let’s beef up the security by <a
  1802.      href="https://blog.bigdinosaur.org/securing-ssh-with-iptables/">securing SSH
  1803.      with iptables</a>. You can move old iptables around with
  1804.      <code>iptables-save</code> and <code>iptables-restore</code>, but don’t forget
  1805.      to <a
  1806.      href="https://wiki.archlinux.org/title/Iptables#Configuration_and_usage">make
  1807.      them persistent</a>.
  1808.      </p>
  1809.      <p>
  1810.      The only internet-facing services should be Tor and an SSH dæmon. There’s
  1811.      nothing else to do for Tor, but we can make SSH much more secure.
  1812.      </p>
  1813.      <p>
  1814.      First of all, copy the <a
  1815.      href="https://wiki.archlinux.org/title/SSH_keys">public key</a> over with
  1816.      </p>
  1817.      <pre class="shell">
  1818. ssh-copy-id -i ~/.ssh/id_ed25519.pub 192.168.0.<em>x</em>
  1819. </pre>
  1820.      <p>
  1821.      and check if it worked. Probably you’ll have to edit <code>.ssh/config</code> if
  1822.      you’re disallowing public key identification in general (<a
  1823.      href="https://words.filippo.io/ssh-whoami-filippo-io/">which you probably should
  1824.      be</a>).
  1825.      </p>
  1826.      <p>
  1827.      Now you can harden the server by enforcing public key authentication and <a
  1828.      href="https://stribika.github.io/2015/01/04/secure-secure-shell.html">choosing
  1829.      good algorithms</a>.
  1830.      </p>
  1831.      <p>
  1832.      Edit <code>/etc/motd</code> to get rid of the boilerplate. It could be nice to
  1833.      print the ED25519 fingerprint here.
  1834.      </p>
  1835.      <p>
  1836.      Finally, set up <a href="../ssh_hidden_service/">SSH as a hidden service</a> so
  1837.      you can SSH to it from anywhere and have a static onion URL and all that.
  1838.      </p>
  1839.      ]]></content:encoded>
  1840.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  1841.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/alarmpi_tor/</guid>
  1842.      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
  1843.    </item>
  1844.    <item>
  1845.      <title>Recovering Deleted Data</title>
  1846.      <link>https://www.maths.tcd.ie/~fionn/misc/recover_data/</link>
  1847.      <description>Here’s what I did. […]</description>
  1848.      <content:encoded><![CDATA[<p>
  1849.      Here’s what I did.
  1850.      </p>
  1851.      <br/>
  1852.      <pre class="shell">
  1853. cp <em>file</em> ..
  1854. </pre>
  1855.      <p>
  1856.      Well, I already had a file called <code><em>file</em></code> in the parent
  1857.      directory. Whoops!
  1858.      </p>
  1859.      <p>
  1860.      Here’s what I did to fix it.
  1861.      </p>
  1862.      <pre class="root-shell">
  1863. grep -a -b "<em>text in the deleted file</em>" /dev/sda3
  1864. 530159385076:<em>some text in the deleted file</em>
  1865.  
  1866. <span class="root-shell">dd if=/dev/sda3 count=8 skip=$(expr 530159385076 / 512 - 4)</span>
  1867. </pre>
  1868.      <p>
  1869.      <code>/dev/sda3</code> is my <code>/home</code> partition, so I’m grepping the
  1870.      hard drive directly. That’s what the <code>-a</code> flag is for — it looks at
  1871.      binary as if it’s text. The <code>-b</code> flag prints the byte offset, so we
  1872.      know where on the drive it found the match.
  1873.      </p>
  1874.      <p>
  1875.      Then we use <code>dd</code> to grab the data. <code>count=<em>n</em></code>
  1876.      takes <code><em>n</em></code> blocks (512 bytes by default, can be changed with
  1877.      <code>bs=<em>n</em></code>) and <code>skip=<em>n</em></code> skips
  1878.      <code><em>n</em></code> blocks in. Here I go back 4 blocks and take 8, which was
  1879.      enough in my case. When/if it works, add <code>of=file</code> to get the file
  1880.      back. It might need editing to remove some binary.
  1881.      </p>
  1882.      <p>
  1883.      An alternative is to give grep the <code>-C200</code> flag. This gives 200 lines
  1884.      before and after the string for context. Maybe you can avoid <code>dd</code>
  1885.      then.
  1886.      </p>
  1887.      <p>
  1888.      This should work in most cases, unless the filesystem has already allocated the
  1889.      space to another file. It obviously won’t work on encrypted discs, or if you
  1890.      used something like <code>shred</code>. It has worked for me one out of two
  1891.      times (the other time it borked my terminal), so YMMV.
  1892.      </p>
  1893.      <p>
  1894.      It can take a really long time.
  1895.      </p>
  1896.      ]]></content:encoded>
  1897.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  1898.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/recover_data/</guid>
  1899.      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
  1900.    </item>
  1901.    <item>
  1902.      <title>How to Set Up an SSH Server as a Hidden Service</title>
  1903.      <link>https://www.maths.tcd.ie/~fionn/misc/ssh_hidden_service/</link>
  1904.      <description>This article assumes you’ve got an SSH dæmon on your host machine running on the clearnet and you use Ed25519 keys. If you haven’t already, make your server secure: use iptables (or something equivalent) and choose good algorithms. […]</description>
  1905.      <content:encoded><![CDATA[<p>
  1906.      This article assumes you’ve got an SSH dæmon on your host machine running on the
  1907.      clearnet and you use <a href="https://ed25519.cr.yp.to/">Ed25519 keys</a>. If
  1908.      you haven’t already, make your server secure: use <a
  1909.      href="https://blog.bigdinosaur.org/securing-ssh-with-iptables/">iptables</a> (or
  1910.      something equivalent) and <a
  1911.      href="https://stribika.github.io/2015/01/04/secure-secure-shell.html">choose
  1912.      good algorithms</a>.
  1913.      </p>
  1914.      <h2>
  1915.      For the Host
  1916.      </h2>
  1917.      <p>
  1918.      Add the following to <code>/etc/tor/torrc</code>.
  1919.      </p>
  1920.      <pre>
  1921. HiddenServiceDir /var/lib/tor/ssh/
  1922. HiddenServicePort 22 127.0.0.1:22
  1923. HiddenServiceAuthorizeClient stealth <em>clientname</em>
  1924. </pre>
  1925.      <p>
  1926.      The first two lines are obvious. The last line isn’t strictly necessary, but
  1927.      adds a fair bit of security by only allowing specified clients to connect. Read
  1928.      the <a
  1929.      href="https://2019.www.torproject.org/docs/tor-manual.html#HiddenServiceAuthorizeClient">man
  1930.      page entry</a>.
  1931.      </p>
  1932.      <p>
  1933.      Reload Tor and open
  1934.      <code>/var/lib<wbr>/tor<wbr>/ssh<wbr>/hostname</wbr></wbr></wbr></code>. It
  1935.      should look like this.
  1936.      </p>
  1937.      <pre>
  1938. <em>hostaddress</em>.onion <em>authcookie</em> # client: <em>clientname</em>
  1939. </pre>
  1940.      <p>
  1941.      That’s it.
  1942.      </p>
  1943.      <h2>
  1944.      For the Client
  1945.      </h2>
  1946.      <p>
  1947.      Now add
  1948.      </p>
  1949.      <pre>
  1950. HidServAuth <em>hostaddress</em>.onion <em>authcookie</em>
  1951. </pre>
  1952.      <p>
  1953.      to your local <code>/etc/tor/torrc</code> file (i.e. the contents of the
  1954.      <code>hostname</code> file becomes the value of <code>HidServAuth</code>). This
  1955.      is only relevant if you used
  1956.      <code>HiddenService<wbr>AuthorizeClient</wbr></code>. Again, read the <a
  1957.      href="https://2019.www.torproject.org/docs/tor-manual.html#HidServAuth">man page
  1958.      entry</a>.
  1959.      </p>
  1960.      <p>
  1961.      We can now check if this all worked. But wait! SSH mitigates man-in-the-middle
  1962.      attacks by displaying a fingerprint of its host key for you to verify. Before
  1963.      you connect over Tor, you should get a copy of this fingerprint to compare.
  1964.      </p>
  1965.      <pre class="shell">
  1966. ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
  1967. </pre>
  1968.      <p>
  1969.      It’s important to do this before you log in over Tor, but you can check after
  1970.      the fact by looking for the public key in <code>~/.ssh/known_hosts</code> (if
  1971.      you don’t obfuscate that file). It should obviously be the same over Tor and the
  1972.      clearnet.
  1973.      </p>
  1974.      <p>
  1975.      OK, let’s connect. Run
  1976.      </p>
  1977.      <pre class="shell">
  1978. torify ssh -i ~/.ssh/id_ed25519 <em>username</em>@<em>hostaddress</em>.onion
  1979. </pre>
  1980.      <p>
  1981.      and make sure the fingerprint matches what you expect.
  1982.      </p>
  1983.      <p>
  1984.      If this worked, we just need to streamline the process. Let’s edit
  1985.      <code>~/.ssh/config</code>. First, we need to get netcat to proxy SSH traffic.
  1986.      I’m using <code>openbsd-netcat</code>, the syntax is slightly different for
  1987.      <code>gnu-netcat</code>.
  1988.      </p>
  1989.      <pre>
  1990. Host <em>hostname</em>
  1991.    HostName <em>hostaddress</em>.onion
  1992.    Port 22
  1993.    User <em>username</em>
  1994.    PubkeyAuthentication yes
  1995.    IdentityFile ~/.ssh/id_ed25519
  1996.    VerifyHostKeyDNS no
  1997.    ProxyCommand nc -X 5 -x localhost:9050 %h %p
  1998. </pre>
  1999.      <ul>
  2000.      <li><code>VerifyHostKeyDNS no</code> is there to avoid a DNS leak. This is the
  2001.      default anyway, but DNS leaking is bad and you should make sure.</li>
  2002.      <li><code>ProxyCommand nc -X 5 -x localhost:9050 %h %p</code> does the work of
  2003.      <code>torify</code>. <code>-X 5</code> tells netcat to use SOCKS v5,
  2004.      <code>-x</code> sets the proxy address and port. <code>%h</code> is replaced by
  2005.      the value of <code>HostName</code> and <code>%p</code> by the value of
  2006.      <code>Port</code> (or else is just set to 22). This assumes Tor is using port
  2007.      9050, but it sometimes uses 9150 (if you’re using the TBB) — try both or check
  2008.      the value of <code>TorPort</code> in <code>/etc/tor/torsocks.conf</code>.</li>
  2009.      <li>You could also put the Tor-specific options under <code>Host
  2010.      *.onion</code>.</li>
  2011.      </ul>
  2012.      <h2>
  2013.      Finished
  2014.      </h2>
  2015.      <p>
  2016.      Now you can just run
  2017.      </p>
  2018.      <pre class="shell">
  2019. ssh <em>hostname</em>
  2020. </pre>
  2021.      <p>
  2022.      to connect to your server over Tor.
  2023.      </p>
  2024.      <p>
  2025.      Some other things:
  2026.      </p>
  2027.      <ul>
  2028.      <li>You can have as many hidden services as you like on the same machine.</li>
  2029.      <li>Use <a href="https://github.com/katmagic/Shallot">Shallot</a>, <a
  2030.      href="https://github.com/lachesis/scallion">Scallion</a>, etc. to generate
  2031.      vanity <code>.onion</code> addresses, if you’re into that kind of thing.</li>
  2032.      <li>Change the port for a bit of extra security through obscurity. You could
  2033.      also try <a href="https://wiki.archlinux.org/index.php/Port_knocking">port
  2034.      knocking</a>.</li>
  2035.      <li>If you’re running your hidden service on a relay, this will <a
  2036.      href="https://trac.torproject.org/projects/tor/ticket/8742">compromise your
  2037.      anonymity</a>. The same holds if your hidden service is also serving something
  2038.      on the clearnet.</li>
  2039.      </ul>
  2040.      ]]></content:encoded>
  2041.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  2042.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/ssh_hidden_service/</guid>
  2043.      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
  2044.    </item>
  2045.    <item>
  2046.      <title>Mounting an Encrypted LUKS Volume</title>
  2047.      <link>https://www.maths.tcd.ie/~fionn/misc/mount_encrypted_volume/</link>
  2048.      <description>It’s really easy. Let’s assume sdb2 is the encrypted LUKS device (because it is for me). lsblk shows the tree as this. […]</description>
  2049.      <content:encoded><![CDATA[<p>
  2050.      It’s really easy. Let’s assume <code>sdb2</code> is the encrypted LUKS device
  2051.      (because it is for me). <code>lsblk</code> shows the tree as this.
  2052.      </p>
  2053.      <pre>
  2054. sdb               8:16   1    29G  0 disk
  2055. ├─sdb1            8:17   1   2.5G  0 part
  2056. └─sdb2            8:18   1  26.5G  0 part
  2057. </pre>
  2058.      <p>
  2059.      Open the LUKS container with
  2060.      </p>
  2061.      <pre class="root-shell">
  2062. cryptsetup open /dev/sdb2 <em>luks_volume</em>
  2063. </pre>
  2064.      <p>
  2065.      (where <code><em>luks_volume</em></code> is the unimaginative name of the
  2066.      container).
  2067.      </p>
  2068.      <p>
  2069.      Now <code>lsblk</code> should show something like
  2070.      </p>
  2071.      <pre>
  2072. sdb               8:16   1    29G  0 disk
  2073. ├─sdb1            8:17   1   2.5G  0 part
  2074. └─sdb2            8:18   1  26.5G  0 part
  2075.  └─<em>luks_volume</em> 254:0    0  26.5G  0 crypt
  2076. </pre>
  2077.      <p>
  2078.      and we just have to mount it.
  2079.      </p>
  2080.      <pre>
  2081. <span class="root-shell">mkdir /mnt/<em>secrets</em>/</span>
  2082. <span class="root-shell">mount /dev/mapper/<em>luks_volume</em> /mnt/<em>secrets</em>/</span>
  2083. </pre>
  2084.      <p>
  2085.      That’s it. When done,
  2086.      </p>
  2087.      <pre>
  2088. <span class="root-shell">umount /mnt/<em>secrets</em></span>
  2089. <span class="root-shell">cryptsetup close <em>luks_volume</em></span>
  2090. <span class="root-shell">rm -r /mnt/<em>secrets</em>/</span>
  2091. </pre>
  2092.      <p>
  2093.      to remove the mapping and mount point and clear the key from memory.
  2094.      </p>
  2095.      ]]></content:encoded>
  2096.      <author>fionn@this.domain (Fionn Fitzmaurice)</author>
  2097.      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/mount_encrypted_volume/</guid>
  2098.      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
  2099.    </item>
  2100.  </channel>
  2101. </rss>
  2102.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=https%3A//www.maths.tcd.ie/%257Efionn/misc/feed.xml

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda