This is a valid RSS feed.
This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.
<managingEditor>fionn@this.domain</managingEditor>
^
<webMaster>fionn@this.domain</webMaster>
^
line 247, column 9: (10 occurrences) [help]
]]></content:encoded>
^
<asciinema-player author="Fionn Fitzmaurice"
line 1843, column 46: (4 occurrences) [help]
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
^
<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">  <channel>    <title>misc</title>    <link>https://www.maths.tcd.ie/~fionn/misc/</link>    <description>Fionn has no mouth but he must scream</description>    <atom:link href="https://www.maths.tcd.ie/~fionn/misc/feed.xml" rel="self"/>    <docs>http://www.rssboard.org/rss-specification</docs>    <generator>fionn-feed</generator>    <image>      <url>https://www.maths.tcd.ie/~fionn/me.jpg</url>      <title>misc</title>      <link>https://www.maths.tcd.ie/~fionn/misc/</link>    </image>    <language>en</language>    <lastBuildDate>Fri, 23 Aug 2024 16:13:11 +0000</lastBuildDate>    <managingEditor>fionn@this.domain</managingEditor>    <webMaster>fionn@this.domain</webMaster>    <item>      <title>Biometric FIDO2/U2F SSH Keys</title>      <link>https://www.maths.tcd.ie/~fionn/misc/fido_ssh/</link>      <description>Smartcards have traditionally supported SSH public key authentication using two methods: PIV and PGP. […]</description>      <content:encoded><![CDATA[<p>      Smartcards have traditionally supported SSH public key authentication using two      methods: PIV and PGP.      </p>      <p>      In PIV mode, you end up hacking around with <code>opensc</code> to get      <code>ssh-agent</code> to use the certificate as a key.      This also doesn’t play well with <code>gpg-agent</code>, which tends to acquire      a lock on the smartcard.      </p>      <p>      In PGP mode, you have to ditch <code>ssh-agent</code> and use      <code>gpg-agent</code> instead, which is a significantly degraded experience.      </p>      <h3 id="openssh"><a class="anchor" href="#openssh"></a>OpenSSH</h3>      <p>      As of <a href="https://www.agwa.name/blog/post/ssh_signatures">OpenSSH version      8.0</a> you can use SSH keys to sign arbitrary data.      </p>      <p>      As of <a href="https://www.openssh.com/txt/release-8.2">OpenSSH version 8.2</a>      you can use SSH keys derived from the FIDO2 application on smartcards, using      either Ed25519 or ECDSA.      </p>      <h3 id="yubikeys"><a class="anchor" href="#yubikeys"></a>YubiKeys</h3>      <p>      Yubico manufacture a few different smartcards (YubiKeys, from here on out). The      <a href="https://www.yubico.com/products/yubikey-5-overview/">YubiKey 5      series</a> support all of the above modes, whereas the <a      href="https://www.yubico.com/products/security-key/">YubiKey Security Key</a>      only supports FIDO2 (since it’s designed just for 2FA on websites and so on).      The Security Key is also significantly cheaper.      </p>      <p>      There’s also the <a      href="https://www.yubico.com/products/yubikey-bio-series/">YubiKey Bio</a>,      which has the same support as the Security Key, but has a fingerprint reader and      comes in at a little over 3 times the price.      </p>      <p>      I held off on buying the Bio because I store my PGP key on my YubiKey and wanted      to retain this functionality. But I finally decided to try it out, for several      reasons:      </p>      <ul>      <li>I can use it for SSH,</li>      <li>I can use that SSH key for signing files and <a      href="https://calebhearth.com/sign-git-with-ssh">Git commits</a>,</li>      <li>I can secure the SSH key with a passphrase and a fingerprint,</li>      <li>I expensed it to my employer,</li>      <li>nobody sends me <a href="/~fionn/contact/#email">PGP-encrypted emails</a>      any more anyway 🙁.</li>      </ul>      <h2 id="fingerprint"><a class="anchor" href="#fingerprint"></a>Adding a      Fingerprint</h2>      <p>      Out of the box, when I plugged it in it was flashing orange. I don’t know why.      </p>      <pre class="shell">ykman infoDevice type: YubiKey C Bio - FIDO EditionSerial number: 17244581Firmware version: 5.5.6Form factor: Bio (USB-C)Enabled USB interfaces: FIDO ApplicationsFIDO2       	EnabledOTP         	Not availableFIDO U2F    	EnabledOATH        	Not availableYubiHSM Auth	Not availableOpenPGP     	Not availablePIV         	Not available</pre>      <p>      To add a fingerprint, we first have to set a PIN.      The PIN can be alphanumeric (extended ASCII) and relatively long (63      characters).      </p>      <pre class="shell">ykman fido access change-pinEnter your new PIN:Repeat for confirmation:</pre>      <p>      Then add a fingerprint.      </p>      <pre class="shell">ykman fido fingerprints add "right-index"Enter your PIN:Place your finger against the sensor now...4 more scans needed.Place your finger against the sensor now...3 more scans needed.Place your finger against the sensor now...2 more scans needed.Place your finger against the sensor now...1 more scans needed.Place your finger against the sensor now...Capture complete.</pre>      <p>      We can then list the fingerprints.      </p>      <pre class="shell">ykman fido fingerprints listEnter your PIN:ID: c83b (right-index)</pre>      <p>      I remain optimistic that revealing which finger I’ve enrolled doesn’t put me at      significantly greater risk of losing it. If your threat model includes this,      rest easy knowing that the list is protected by the PIN.      </p>      <h2 id="key-generation"><a class="anchor" href="#key-generation"></a>Generating      a Resident Ed25519 SSH Key</h2>      <p>      There are <a      href="https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html#_discoverable_vs_non_discoverable_credentials">two      types</a> of FIDO2 SSH keys: resident and non-resident.      </p>      <p>      I’m using a resident key because the PIN/fingerprint access control is good      enough for me and I value the ability to move the YubiKey between different      devices.      </p>      <p>      We generate the key with <code>ssh-keygen -t ed25519-sk</code>. This will fail      if your YubiKey’s firmware is <a      href="https://www.yubico.com/blog/whats-new-in-yubikey-firmware-5-2-3/">older      than 5.2.3</a>, before they supported Ed25519 curves.      If so, you can fall back to <code>ecdsa-sk</code>, or get a new YubiKey (<a      href="https://safecurves.cr.yp.to/">recommended</a>).      </p>      <p>      The below command makes a key that requires not just user presence (a touch) but      also verification. This means a PIN for normal non-biometric YubiKeys but,      despite the <a      href="https://man.archlinux.org/man/ssh-keygen.1#verify-required"><code>ssh-keygen</code>      documentation</a> insisting otherwise, the Bio will accept a fingerprint to      unlock the key.      </p>      <blockquote cite="https://man.archlinux.org/man/ssh-keygen.1#verify-required">      <strong><code>verify-required</code></strong>      <br/>          Require signatures made using this key indicate that the user was first      verified.          This option only makes sense for the FIDO authenticator algorithms      <code>ecdsa-sk</code> and <code>ed25519-sk</code>.          Currently PIN authentication is the only supported verification method, but      other methods may be supported in the future.      </blockquote>      <p>      I also increase the key derivation rounds and add a comment.      </p>      <pre class="shell">ssh-keygen -t ed25519-sk -O resident -O verify-required -a 128 -C 17244581Generating public/private ed25519-sk key pair.You may need to touch your authenticator to authorize key generation.Enter PIN for authenticator:Enter file in which to save the key (/home/fionn/.ssh/id_ed25519_sk):Enter passphrase (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /home/fionn/.ssh/id_ed25519_skYour public key has been saved in /home/fionn/.ssh/id_ed25519_sk.pubThe key fingerprint is:SHA256:2fl1x8+ACfUB2UA3eV5mXLJY5Wr04K93N7nH6iN4OoY 17244581The key's randomart image is:+[ED25519-SK 256]-+|           .==*++||           ..=o**||          . . ==o||         o o = =.||        S o o * =||           . o =o||         . ..  .=||        E + o .+*||         ..+ o+=*|+----[SHA256]-----+</pre>      <h2 id="connecting"><a class="anchor" href="#connecting"></a>Using the FIDO2 SSH      Key</h2>      <p>      Now test it out. I usually use GitHub for this. Upload      <code>~/.ssh/id_ed25519_sk.pub</code>, add      </p>      <p>      </p>      <pre>Host github.com    User git    PubkeyAuthentication yes    IdentityFile ~/.ssh/id_ed25519_sk</pre>      <p>      to <code>~/.ssh/config</code> and try to connect.      </p>      <pre class="shell">ssh -T github.comEnter passphrase for key '/home/fionn/.ssh/id_ed25519_sk':Confirm user presence for key ED25519-SK SHA256:2fl1x8+ACfUB2UA3eV5mXLJY5Wr04K93N7nH6iN4OoYUser presence confirmedHi <a href="https://github.com/fionn" rel="me">fionn</a>! You've successfully authenticated, but GitHub does not provide shell access.</pre>      <p>      Then try to connect again and notice that <code>ssh-agent</code> has cached the      passphrase.      </p>      <p>      To use it on another machine, plug it into the new machine and run      </p>      <pre class="shell">ssh-keygen -KEnter PIN for authenticator:You may need to touch your authenticator to authorize key download.Enter passphrase (empty for no passphrase):Enter same passphrase again:Saved ED25519-SK key to id_ed25519_sk_rk</pre>      <p>      to download the key handles to the working directory. Move them to      <code>~/.ssh/</code> and connect like usual.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/fido_ssh/</guid>      <pubDate>Wed, 21 Sep 2022 00:00:00 +0000</pubDate>    </item>    <item>      <title>RSS and Atom Feeds</title>      <link>https://www.maths.tcd.ie/~fionn/misc/feed/</link>      <description>I think decentralised syndication is a good thing so I made RSS and Atom feeds for this pseudo-blog</description>      <content:encoded><![CDATA[<p>                  I read <a      href="https://twobithistory.org/2018/09/16/the-rise-and-demise-of-rss.html">The      Rise and Demise of RSS</a> and was motivated to syndicate this <a      href="../">list of things I write here</a>.                  </p>      <p>                  One of the challenges is that typically people use some sort of      publishing platform which generates RSS feeds for you. Since this site is      entirely static (well, aside from some PHP to keep things tidy on the server      side), I have to generate the feed myself. Since it’s just XML, I could in      principle do it by hand. However, the pain-point that that would introduce every      time I (occasionally) add to this list would almost guarantee that I wouldn’t      update it.                  </p>      <p>                  To solve this, I wrote a pretty basic script that scrapes this page,      grabs all the articles and figures out how to turn them into feed entries. Then      it generates a feed with all the relevant metadata and adds each one. The      process is still manual, but reduced to a “one-click” deployment.                  </p>      <p>                  The code is <a href="https://github.com/fionn/feed">here</a>. This      page is publishing syndicated feeds; you should be able to see it if your      browser knows what to do with them. (Firefox looks to be deprecating its live      bookmarks functionality. Get <a      href="https://addons.mozilla.org/en-US/firefox/addon/awesome-rss/">Awesome      RSS</a> to add the RSS feed back in the address bar.)                  </p>      <p>                  Subscribe via <a href="../feed.xml">RSS</a> or <a      href="../feed.atom">Atom</a>. Or don’t. But do subscribe to other things. It’s      such a shame that this technology is going out of favour, but also no accident.      We have to fight for the internet we want.                  </p>      <p>                  (<em>Syndication feeds validate for <del>both</del> <a      href="https://www.feedvalidator.org/check.cgi?url=https%3A%2F%2Fwww.maths.tcd.ie%2F%257Efionn%2Fmisc%2Ffeed.xml">RSS</a>      <del>and <a      href="https://www.feedvalidator.org/check.cgi?url=https%3A%2F%2Fwww.maths.tcd.ie%2F%257Efionn%2Fmisc%2Ffeed.atom">Atom</a></del>.</em>)                  </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/feed/</guid>      <pubDate>Tue, 18 Sep 2018 00:00:00 +0000</pubDate>    </item>    <item>      <title>Encrypting a Volume</title>      <link>https://www.maths.tcd.ie/~fionn/misc/encrypt_volume/</link>      <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>      <content:encoded><![CDATA[<p>      It’s really easy. Let’s assume <code>sdc</code> is the drive (because it is for      me). Open up <code>gdisk</code>, make a new GPT and fill the disk with a      partition of type <code>FD00</code> (this is Linux RAID, which allegedly is      conventional).      </p>      <pre>Number  Start (sector)    End (sector)  Size       Code  Name   1            2048       124735454   59.5 GiB    FD00  Linux RAID</pre>      <p>      You can also rename the partition to LUKS or something.      </p>      <p>      <code>cryptsetup</code> <em>should</em> be compiled with sane defaults (you can      check with <code>--help</code>), so encryption is done with      </p>      <pre class="root-shell">cryptsetup -v --verify-passphrase luksFormat /dev/sdc1</pre>      <p>      (which can be elaborated on if the compiled defaults are not to your liking).      </p>      <p>      Open the LUKS container with      </p>      <pre class="root-shell">cryptsetup open /dev/sdc1 <em>luks_volume</em></pre>      <p>      (where <code><em>luks_volume</em></code> is the unimaginative name of the      container).      </p>      <pre>sdc                  8:32   1  59.5G  0 disk└─sdc1               8:33   1  59.5G  0 part  └─<em>luks_volume</em>     254:2   0  59.5G  0 crypt</pre>      <p>      This creates a handle in <code>/dev/mapper/<em>luks_volume</em></code>. It’s not      a filesystem yet, though.      </p>      <p>      </p>      <pre class="root-shell">mkfs.ext4 /dev/mapper/<em>luks_volume</em></pre>      <p>      Now we can mount it! See <a href="../mount_encrypted_volume/"><em>Mounting an      encrypted LUKS volume</em></a> for how to do that.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/encrypt_volume/</guid>      <pubDate>Thu, 24 May 2018 00:00:00 +0000</pubDate>    </item>    <item>      <title>WireGuard</title>      <link>https://www.maths.tcd.ie/~fionn/misc/wg/</link>      <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>      <content:encoded><![CDATA[<p>      This is the future of VPNs, etc. Read about it <a      href="https://www.wireguard.com/">here</a>. It really is amazing. There’s also      manual configuration steps there, which you should do first.      </p>      <p>      It’s super easy to set up configurations for use with <code>wg-quick</code>.      Here’s a simple server + client configuration for tunnelling all traffic      throught the VPN.      </p>      <p>      Note that “server” and “client” are artificial terms here; really both machines      are peers, we’re imposing the server + client relationship on them to align with      traditional VPNs.      </p>      <p>      Generate private keys with <code>umask 077 && wg genkey >      private.key</code>. Corresponding public keys are derived from private ones with      <code>wg pubkey < private.key > public.key</code>. The preshared key is      used for post-quantum resilience, generated with <code>wg genpsk >      preshared.key</code>.      </p>      <pre><code class="ini"># server wg0.conf[Interface]PrivateKey = [server private key]Address = 10.10.0.1/24, fd80::1/64ListenPort = 2307SaveConfig = truePostUp = iptables -A FORWARD -i wg0 -j ACCEPT && iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEPostDown = iptables -D FORWARD -i wg0 -j ACCEPT && iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer]PublicKey = [client public key]PresharedKey = [preshared.key]AllowedIPs = 10.10.0.2/32, fd80::2/128</code></pre>      <p>      Not a whole lot is happening here. IP addresses and ports are just examples—here      we’re allocating <code>10.10.0.1</code> to the server and <code>10.10.0.2</code>      to the client. The <code>SaveConfig</code> line allows WireGuard to override      this file with its current state, so you can make manual, persistent changes as      it runs.      </p>      <pre><code class="ini"># client wg0.conf[Interface]PrivateKey = [client private key]Address = 10.10.0.2/24, fd80::2/64ListenPort = 2307DNS = 10.10.0.1PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECTPreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT [Peer]PublicKey = [server public key]PresharedKey = [preshared.key]AllowedIPs = 0.0.0.0/0, ::/0Endpoint = [wireguard server]:2307</code></pre>      <p>      The ports match for NAT traversal, but it’s not strictly necessary. The client      allows its peer to send traffic from any IP, since it’s going to be proxying the      entire internet.      </p>      <p>      On both server and client, run <code>wg-quick up wg0</code>. This can also run      as a systemd service, with <code>systemctl start wg-quick@wg0.service</code>.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/wg/</guid>      <pubDate>Thu, 07 Dec 2017 00:00:00 +0000</pubDate>    </item>    <item>      <title>Vim Plugins, the Right Way</title>      <link>https://www.maths.tcd.ie/~fionn/misc/vim/</link>      <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>      <content:encoded><![CDATA[<p>      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).      </p>      <h2 id="why"><a class="anchor" href="#why"></a>Why Plugin Managers?</h2>      <p>      Vim’s directory hierarchy is traditionally something like this.      </p>      <pre>.vim/├── autoload/├── colors/├── doc/├── ftplugin/├── indent/├── plugin/├── spell/├── syntax/└── undo/</pre>      <p>      It looks quite sensible. Plugins follow this hierarchy, with their      <code>.vim</code> files going into <code>plugins/</code> (and sometimes      <code>autoload/</code>), help files in <code>doc/</code>, etc. This makes      uninstalling or updating plugins a real pain.      </p>      <p>Plugin managers solve this problem by abstracting this hierarchy, so you      don’t have to think about it.      </p>      <h2 id="howto"><a class="anchor" href="#howto"></a>How to Get Rid of Plugin      Managers?</h2>      <p>      Vim 8 introduced the notion of a <em>package</em> (see <a      href="https://vimhelp.org/repeat.txt.html#packages"><code>:h      packages</code></a>). Plugins (i.e. their entire directory hierarchy) can live      in <code>.vim/pack/plugins/start/<em>plugin_name</em>/</code> and Vim will add      this to its runtime path. (The <code>plugins/</code> directory can actually be      named however you like.)      </p>      <p>      This is pretty great, because now our plugins can be kept under version control.      Getting them is just a clone, they can be easily updated and they can be rolled      back.      </p>      <p>      However, the <code>.vim/</code> directory is probably already under version      control, along with the rest of the dotfiles.      </p>      <p>      To deal with this: instead of cloning, use <code><a      href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">git submodule</a> add      <var>repository</var>.git</code>. Then just keep it up to date by pulling it      every so often. To update all plugins, <code>git submodule foreach git      pull</code>.      </p>      <p>      When cloning the dotfile repository, use the <code>--recursive</code> flag to      get the submodules as well. Alternatively, clone as normal and then initialise      and update the submodules with <code>git submodule init && git submodule      update</code>.      </p>      <p>      Run <code>:helptags ALL</code> to generate helptags for all plugins.      </p>      <h2 id="right"><a class="anchor" href="#right"></a>Is This Really the Right      Way?</h2>      <p>      I think so. Some might disagree and argue for using <a      href="https://www.atlassian.com/git/tutorials/git-subtree"><code>git-subtree</code></a>      instead.      </p>      <h2 id="remove"><a class="anchor" href="#remove"></a>How to Remove a      Submodule?</h2>      <p>      There’s a lot of disinformation out there. Just <code>git rm      <var>path</var>/<var>to</var>/<var>submodule</var></code>, like the <a      href="https://git-scm.com/docs/gitsubmodules#_forms">docs say</a>.      </p>      <blockquote cite="https://git-scm.com/docs/gitsubmodules">      The deletion removes the superproject’s tracking data, which are both the      <code>gitlink</code> entry and the section in the <code>.gitmodules</code> file.      The submodule’s working directory is removed from the file system, but the Git      directory is kept around as <span class="sic">it</span> to make it possible to      checkout past commits without requiring fetching from another repository.      </blockquote>      <h2 id="dotfiles"><a class="anchor" href="#dotfiles"></a>Where Are Your      Dotfiles?</h2>      <p>      <code><a href="https://github.com/fionn/.dotfiles">.dotfiles</a>/vim/<a      href="https://github.com/fionn/.dotfiles/tree/master/vim/.vim">.vim</a>/<a      href="https://github.com/fionn/.dotfiles/tree/master/vim/.vim/vimrc">vimrc</a></code>.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/vim/</guid>      <pubDate>Sun, 17 Sep 2017 00:00:00 +0000</pubDate>    </item>    <item>      <title>Elliptic Curves and OpenVPN</title>      <link>https://www.maths.tcd.ie/~fionn/misc/ec_vpn/</link>      <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>      <content:encoded><![CDATA[<p>      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.      </p>      <p>      This was all done on OpenVPN 2.4.1. As far as I know, elliptic curve      cryptography support in OpenVPN is for 2.4.0+.      </p>      <h2>PKI</h2>      <p>      Get Easy-RSA and set up variables in the <code>vars</code> file.      </p>      <pre>set_var EASYRSA_ALGO     ecset_var EASYRSA_CURVE    secp521r1set_var EASYRSA_DIGEST   "sha512"</pre>      <p>      The choice of curve is a personal one. <code>secp521r1</code> is P-521. DJB <a      href="https://blog.cr.yp.to/20140323-ecdsa.html">considers it a nice prime</a>.      All supported curves are listed with <code>openvpn --show-curves</code> (<a      href="curves.txt">these are mine</a>).      </p>      <p>      There’s <a href="https://github.com/OpenVPN/easy-rsa/issues/111">a bug</a> in      Easy-RSA regarding sourcing this file. The workaround is to <code>export      EASYRSA_VARS_FILE=/etc/easy-rsa/vars</code> (or put it in <code>.bashrc</code>      or whatever).      </p>      <p>      Make the PKI and build the CA with <code>easyrsa init-pki</code>, <code>easyrsa      build-ca</code>.      </p>      <pre><span class="root-shell">easyrsa gen-req <em>servername</em> nopass</span><span class="root-shell">easyrsa sign-req server <em>servername</em></span><span class="root-shell">easyrsa gen-req <em>clientname</em> [nopass]</span><span class="root-shell">easyrsa sign-req client <em>clientname</em></span></pre>      <p>We now have all the server files      </p>      <pre>pki/ca.crtpki/issued/<em>servername</em>.crtpki/private/<em>servername</em>.key</pre>      <p>      and all the client files      </p>      <pre>pki/ca.crtpki/issued/<em>clientname</em>.crtpki/private/<em>clientname</em>.key</pre>      <p>      (there’s some nonsense about 3DES-encrypting the client key, which I’m      ignoring).      </p>      <p>      If you didn’t set the <code>nopass</code> option but now regret it, run      <code>openssl ec -in <em>clientname</em>.key -out      <em>clientname</em>_nopass.key</code>, enter your password and rename the keys.      </p>      <h2>VPN</h2>      <p>      Copy the server and client files to their respective OpenVPN directories.      </p>      <p>      Here’s an example server configuration.      </p>      <pre>port 1194proto udpdev tun ca ecc/ca.crtcert ecc/servername.crtkey ecc/servername.key dh none server 10.8.0.0 255.255.255.0ifconfig-pool-persist ipp.txtpush "redirect-gateway def1"push "dhcp-option DNS 1.2.3.4" keepalive 10 120 tls-crypt ecc/tc.keyauth SHA512keysize 256tls-servertls-version-min 1.2tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384cipher AES-256-GCMreneg-sec 360remote-cert-eku "TLS Web Client Authentication"script-security 2auth-user-pass-verify /etc/openvpn/server/auth/auth.py via-file user nobodygroup nobody persist-keypersist-tun status openvpn-status.logexplicit-exit-notify 1</pre>      <p>      And a client configuration.      </p>      <pre>clientdev tunproto udpremote serverurl 1194resolv-retry infinitenobind#user nobody#group nobodypersist-keypersist-tuntls-clientmute-replay-warningsca servername/ecc/ca.crtcert servername/ecc/clientname.crtkey servername/ecc/clientname.keyremote-cert-eku "TLS Web Server Authentication"verify-x509-name 'CN=servername' subjectremote-cert-tls servertls-crypt servername/ecc/tc.keycipher AES-256-GCMauth SHA512tls-version-min 1.2tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384reneg-sec 360#comp-lzoverb 3#mute 20 auth-user-pass servername/secret.passwordredirect-gateway def1script-security 2up /etc/openvpn/client/servername/update-resolv-conf.shdown /etc/openvpn/client/servername/update-resolv-conf.sh</pre>      <p>      For several devices/users, managing certs, etc., can be tedious to do by hand. I      wrote some code to <a href="https://github.com/fionn/vpn-auth">automate it</a>.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/ec_vpn/</guid>      <pubDate>Thu, 27 Apr 2017 00:00:00 +0000</pubDate>    </item>    <item>      <title>The Mersenne Twister</title>      <link>https://www.maths.tcd.ie/~fionn/misc/mt/</link>      <description>The Mersenne Twister is a 623-dimensionally equidistributed uniform pseudorandom number generator. This is how it works. […]</description>      <content:encoded><![CDATA[<p>      The Mersenne Twister is <a      href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf">a      623-dimensionally equidistributed uniform pseudorandom number generator</a>.      This is how it works.      </p>      <p>      The paper first defines a $k$-distribution as a very reasonable definition of      randomness. Read the paper first.      </p>      <h2 id="recurrence"><a class="anchor" href="#recurrence"></a>The Linear      Recurrence</h2>      <p>      Equation 2.1 in <em>M&N</em> 1998 is the linear recurrence      $$      \mathbf{x}_{k + n} := \mathbf{x}_{k + m} \oplus (\mathbf{x}_k^u |      \mathbf{x}^l_{k + 1}) A      $$      ($k = 0, 1, \ldots$). The paper says the following.      </p>      <blockquote      cite="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf#page=6">      We have several constants: an integer $n$, which is the degree of the      recurrence, an integer $r$ (hidden in the definition of $\mathbf{x}_k^u$), $0      \leq r \leq w - 1$, an integer $m$, $1 \leq m \leq n$, and a constant $w \times      w$ matrix $A$ with entries in $\mathbb{F}_2$.      </blockquote>      <p>      From the paper, $w$ is the “word length”, so $\mathbf{x}_i \, \in \,      \mathbb{F}_2^w$ are “word vectors” of length $w$.      </p>      <p>      On the right, we have this $\mathbf{x}_k^u | \mathbf{x}^l_{k + 1}$ term. This is      the concatonation of $\mathbf{x}_k^u$ with $\mathbf{x}^l_{k + 1}$.      $\mathbf{x}_k^u$ is the “upper $w - r$ bits” of $\mathbf{x}_k$ and      $\mathbf{x}^l_{k + 1}$ is the “lower $r$ bits” of $\mathbf{x}_{k + 1}$, i.e.      denoting      $$      \mathbf{x}_k = (x_{w - 1}, \ldots, x_{r}, x_{r - 1}, \ldots, x_0),      $$      then      $$      \mathbf{x}_k^u = (x_{w - 1}, \ldots, x_{r}), \qquad      \mathbf{x}_k^l = (x_{r - 1}, \ldots, x_0).      $$      </p>      <p>      Given $n$ initial seeds $\mathbf{x}_0, \ldots, \mathbf{x}_{n - 1}$, we can      generate      $$      \mathbf{x}_{n} := \mathbf{x}_{m} \oplus (\mathbf{x}_0^u | \mathbf{x}^l_{1}) A      $$      (where $k = 0$). The only constants here are $n$, $m$, $r$ and $A$.      </p>      <p>      $A$ is the sparse matrix      $$      A = \begin{pmatrix}      0 & 1 & 0 & \cdots & 0 \\      0 & 0 & 1 &        & 0 \\      \vdots & \vdots & & \ddots & \vdots \\      0 & 0 & & & 1 \\      a_{w - 1} & a_{w - 2} & a_{w - 3} & \cdots & a_0      \end{pmatrix}      $$      where we denote the bottom row as $\mathbf{a} = (a_{w - 1}, \ldots, a_0)$.      </p>      <p>      For $\mathbf{x} = (x_{w - 1}, \ldots, x_0)$,      $$      \mathbf{x}A = (x_0 a_{w - 1}, x_{w - 1} + x_0 a_{w - 2}, \ldots, x_1 + x_0 a_0).      $$      </p>      <p>      Notice that if $x_0 = 0$, this simplifies to      $$      \mathbf{x}A = (0, x_{w - 1}, \ldots, x_1)      $$      which amounts to a right bitshift, i.e. $\mathbf{x}A = \mathbf{x} \gg 1$.      If $x_0 = 1$ instead, then      $$      \mathbf{x}A = (a_{w - 1}, x_{w - 1} + a_{w - 2}, \ldots, x_1 + a_0)      $$      and this reduces to an addition of $\mathbf{a}$, i.e. $\mathbf{x}A = (\mathbf{x}      \gg 1) \oplus \mathbf{a}$. (Recall that this is an xor, since we are working in      $\mathbb{F}_2$.)      </p>      <p>      For MT19937, the parameters are $w = 32$, $n = 624$, $m = 397$, $r = 31$ and      $\mathbf{a} = \mathtt{0x9908B0DF}$ (<em>M&N</em> 1998, Table II).      </p>      <h2 id="initialisation"><a class="anchor"      href="#initialisation"></a>Initialisation</h2>      <p>      There is an undocumented parameter $f$ which is used to initialise the internal      state as      $$      \mathbf{x}_i = f \cdot (\mathbf{x}_{i - 1} \oplus (\mathbf{x}_{i - 1} \gg (w -      2))) + i.      $$      This is <a href="https://eprint.iacr.org/2005/165.pdf#page=4">given the      value</a> $f = 1812433253$.      </p>      <h2 id="tempering"><a class="anchor" href="#tempering"></a>Tempering</h2>      <p>      The linear operator $T$ is a $w \times w$ invertible matrix. We define      “tempering” to be the operation      $$      \mathbf{x} \mapsto \mathbf{z} = \mathbf{x} T.      $$      $T$ consists of the following bitwise operations.      $$\begin{aligned}      \mathbf{y} &:= \mathbf{x} \oplus (\mathbf{x} \gg u), \\      \mathbf{y} &:= \mathbf{y} \oplus \bigl((\mathbf{y} \ll s) \otimes      \mathbf{b}\bigr), \\      \mathbf{y} &:= \mathbf{y} \oplus \bigl((\mathbf{y} \ll t) \otimes      \mathbf{c}\bigr), \\      \mathbf{z} &:= \mathbf{y} \oplus (\mathbf{y} \gg l)      \end{aligned}$$      (equations 2.2 to 2.5). These parameters are $u = 11$, $s = 7$, $\mathbf{b} =      \mathtt{0x9D2C5680}$, $t = 15$, $\mathbf{c} = \mathtt{0xEFC60000}$ and $l = 18$      (<em>M&N</em> 1998, Table II).      </p>      <h2 id="implementation"><a class="anchor" href="#implementation"></a>An      Implementation</h2>      <p>      This is the Mersenne Twister in Python. The linear recurrence occurs in      <code>_twist</code> and the tempering in <code>temper</code>.      </p>      <pre><code class="language-python">#!/usr/bin/env python3"""The Mersenne Twister""" class MT19937:    u = 11    s, b = 7, 0x9d2c5680    t, c = 15, 0xefc60000    l = 18     def __init__(self, seed: int) -> None:        self.index = 624        self.state = [0] * 624        self.state[0] = seed & 0xffffffff        for i in range(1, 624):            self.state[i] = 0x6c078965 \                            * (self.state[i - 1] ^ self.state[i - 1] >> 30) \                            + i & 0xffffffff     @staticmethod    def temper(y: int) -> int:        y ^= y >> MT19937.u        y ^= y << MT19937.s & MT19937.b        y ^= y << MT19937.t & MT19937.c        y ^= y >> MT19937.l        return y     def random(self) -> int:        if self.index >= 624:            self._twist()        y = self.temper(self.state[self.index])        self.index += 1        return y     def _twist(self) -> None:        for i in range(624):            y = (self.state[i] & 0x80000000) \                + (self.state[(i + 1) % 624] & 0x7fffffff)            self.state[i] = self.state[(i + 397) % 624] ^ y >> 1            if y % 2 != 0:                self.state[i] ^= 0x9908b0df        self.index = 0 def main() -> None:    x = MT19937(5489)      # Seed from mt19937ar.c    for _ in range(1000):        print(x.random()) if __name__ == "__main__":    main()</code></pre>      <h2 id="untempering"><a class="anchor" href="#untempering"></a>Untempering</h2>      <p>      The Mersenne Twister is not cryptographically secure since the transformation      $T$ is bijective. Due to the existence of $T^{-1}$, we can create an      “untempering” function. If we can record $n$ consecutive outputs of the Mersenne      Twister and untemper them, this will give us the internal state of the random      number generator and allow us to predict all future values.      </p>      <pre><code class="language-python">#!/usr/bin/env python3"""Clone an MT19937 RNG from its output""" from mt import MT19937 def untemper(y: int) -> int:    y ^= y >> MT19937.l    y ^= y << MT19937.t & MT19937.c    for _ in range(7):        y ^= y << MT19937.s & MT19937.b    for _ in range(3):        y ^= y >> MT19937.u    return y def clone_mt(mt: MT19937) -> MT19937:    mt_clone = MT19937(0)    for i in range(624):        mt_clone.state[i] = untemper(mt.random())    return mt_clone def main() -> None:    mt = MT19937(5489)    mt_clone = clone_mt(mt)     for _ in range(2000):        assert mt_clone.random() == mt.random()     print(mt_clone) if __name__ == "__main__":    main()</code></pre>      <p>      See <code><a      href="https://github.com/fionn/cryptopals/blob/master/m21.py">m21.py</a></code>      and <code><a      href="https://github.com/fionn/cryptopals/blob/master/m23.py">m23.py</a></code>      on <a href="https://github.com/fionn">my GitHub account</a>.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/mt/</guid>      <pubDate>Tue, 23 May 2017 00:00:00 +0000</pubDate>    </item>    <item>      <title>Symmetry in Particle Physics</title>      <link>https://www.maths.tcd.ie/~fionn/misc/symmetry/</link>      <description>A while ago, I wrote an article for non-physicists about symmetry and the Standard Model. […]</description>      <content:encoded><![CDATA[<p>                  A while ago, I wrote an article for non-physicists about symmetry      and the Standard Model.                  </p>      <br/>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/symmetry/</guid>      <pubDate>Mon, 26 Sep 2016 00:00:00 +0000</pubDate>    </item>    <item>      <title>The Padding Oracle Attack</title>      <link>https://www.maths.tcd.ie/~fionn/misc/padding_oracle/</link>      <description>There are a bunch of writeups on this attack, such asRobert Heaton's blog post,SkullSecurity(and their follow-up),GDS,mpgn,Grymoire,this crypto.SX postand the paper by Serge Vaudenay.Dan Boneh has a lecture on itand this video is good too.Here’s my digestion of it. […]</description>      <content:encoded><![CDATA[<p>      There are a bunch of writeups on this attack, such as      <a href="https://robertheaton.com/2013/07/29/padding-oracle-attack/">Robert      Heaton's blog post</a>,      <a      href="https://blog.skullsecurity.org/2013/padding-oracle-attacks-in-depth">SkullSecurity</a>      (and their <a      href="https://blog.skullsecurity.org/2013/a-padding-oracle-example#">follow-up</a>),      <a      href="https://blog.gdssecurity.com/labs/2010/9/14/automated-padding-oracle-attacks-with-padbuster.html">GDS</a>,      <a href="https://github.com/mpgn/Padding-oracle-attack">mpgn</a>,      <a      href="https://grymoire.wordpress.com/2014/12/05/cbc-padding-oracle-attacks-simplified-key-concepts-and-pitfalls/">Grymoire</a>,      this <a href="https://crypto.stackexchange.com/a/3772">crypto.SX post</a>      and the <a      href="https://www.iacr.org/archive/eurocrypt2002/23320530/cbc02_e02d.pdf">paper      by Serge Vaudenay</a>.      Dan Boneh has a <a      href="https://www.youtube.com/watch?v=evrgQkULQ5U">lecture</a> on it      and <a class="dead" title="https://www.youtube.com/watch?v=D-4mmc7frR4">this      video</a> is good too.      Here’s my digestion of it.</p>      <p>Let there be $n$ blocks of plaintext, each of blocksize $k$. For $i \in [1,      n]$,      $$\begin{aligned}      c_i &= E(p_i \oplus  c_{i-1}), \\      p_i &= D(c_i) \oplus c_{i-1}      \end{aligned}$$      where $c_i$ is the $i$<sup>th</sup> cyphertext block, $p_i$ the $i$<sup>th</sup>      plaintext block and $c_0$ the initialisation vector.      </p>      <p>      Construct some block, which we will call $c'$. If we concatenate it with the      last cyphertext block $c_n$, the corresponding plaintext of $c'|c_n$ would be      $p_1'|p_2'$,      $$\begin{aligned}      p'_1 = D(c') \oplus c_0, \quad p'_2 &= D(c_n) \oplus c' \\      &= D(E(p_n \oplus c_{n-1})) \oplus c' \\      &= p_n \oplus c_{n-1} \oplus c',      \end{aligned}$$      giving      $$      p_n = p_2' \oplus c' \oplus c_{n-1}.      $$      </p>      <p>      As $p_2'$ is at the end of our plaintext block it must have valid padding. This      puts a constraint on $c'$. If only there was some way to tell if the plaintext      had valid padding...      </p>      <h2>The Padding Oracle</h2>      <p>      For $p$ the plaintext corresponding to cyphertext $c$, define the padding oracle      $\mathcal{O}$ as      $$ \mathcal{O}(c) =      \begin{cases}      1 & \text{if } p \text{ has valid padding}, \\      0 & \text{otherwise}.      \end{cases}      $$      We can now construct $c'$ such that $p_2' = D(c_n) \oplus c'$ has valid padding,      by submitting $c'|c_n$ to the oracle. If $\mathcal{O}(c'|c_n) = 1$, the padding      in $p_2'$ is valid.      </p>      <h2>The Last Byte</h2>      <p>      Borrowing some programming notation, if we consider the last byte in $p_2'$ to      be $p_2'[k] = \mathtt{\backslash x01}$, $p_2'$ will (trivially) have valid      padding. If we can construct a $c'$ such that this is the case, we will know      that the last byte of $p_2'$ is one.      </p>      <p>      For such a $c'$, $c'_k$, say,      $$\begin{aligned}      p_n[k] &= p_2'[k] \oplus c'_k[k] \oplus c_{n-1}[k] \\             &= 1 \oplus c'_k[k] \oplus c_{n-1}[k].      \end{aligned}$$      (Here $1 = \mathtt{\backslash x01}$. We’ll use this shorthand throughout.)      </p>      <p>      To construct $c'_k$, it is enough to notice that since $p'_2 = D(c_n) \oplus      c'_k$ and we are only interested in $p'_2[k] = D(c_n)[k] \oplus c'_k[k]$, we can      let      $$      c'_k = (\mathtt{\backslash x00}, \mathtt{\backslash x00}, \ldots,      \mathtt{\backslash x00}, b)$$      (i.e. 15 bytes of zero, or whatever, and the final byte $c'_k[k] = b$).      Iterating over all possible values of $b$ and submitting the cyphertext to the      oracle will give us the value of $b$ that produces valid padding. Thus, we’ve      found the last byte of the plaintext.      </p>      <h2>The Second-Last Byte</h2>      <p>      Another valid plaintext would be $p_2'[k] = p_2'[k-1] = \mathtt{\backslash      x02}$.      </p>      <p>      To construct $c'_{k-1}$, notice that $c'_{k-1}[k]$ will simply be the previous      $c'_k[k]$ xored appropriately.      $$\begin{aligned}      p_2'[k] \oplus c'_k[k] &= 1, \\      p_2'[k] \oplus c'_k[k] &\oplus 1 \oplus 2 = 2,      \end{aligned}$$      but      $$      p_2'[k] \oplus c'_{k-1}[k] = 2      $$      by definition of $c'_{k-1}$, so equating these we get      $$      p_2'[k] \oplus c'_{k-1}[k] = p_2'[k] \oplus c'_k[k] \oplus 1 \oplus 2,      $$      giving      $$      c'_{k-1}[k] = c'_k[k] \oplus 1 \oplus 2.      $$      </p>      <p>$c'_{k-1}[k-1]$ is found by testing all possible values until      $\mathcal{O}(c'_{k-1}|c_n) = 1$. Then the second-last byte is      $$      p_n[k-1] = 2 \oplus c'_{k-1}[k-1] \oplus c_{n-1}[k-1].      $$      </p>      <h2>All the Bytes</h2>      <p>      In general, we get each byte of the plaintext block via      $$      p_n[k - i] = (i + 1) \oplus c_{k-i}'[k-i] \oplus c_{n-1}[k-i],      $$      for $i \in [0, k)$, where $c_i'$ is $c'$ constructed for the $i$<sup>th</sup>      byte via      $$      c'_{k-i}[k - j] = c'_{k - i + 1}[k - j] \oplus i \oplus (i + 1)      $$      where $j \leq i$.      </p>      <h2>All the Blocks</h2>      <p>      This is repeated for each block, excluding the first (because we don’t know the      initialisation vector).      </p>      <h2>Caveats</h2>      <p>      Notice that for finding the last byte $p_n[k]$ we iterated over all possible      values of $c'[k] = b$ until $\mathcal{O}(c'|c_n) = 1$ and concluded then that      $p_2'[k] = \mathtt{\backslash x01}$. However, there is a small probability      ($\frac{1}{256}$) that $p_2'[k-1] = \mathtt{\backslash x02}$ and our oracle is      satisfied because we’ve inadvertently found the cyphertext byte that corresponds      to $p_2'[k] = \mathtt{\backslash x02}$.      </p>      <p>      This could similarly happen if $p_2'[k-2] = p_2'[k-1] = \mathtt{\backslash      x03}$, where we would get a positive result if $p_2' = \mathtt{\backslash x03}      \neq \mathtt{\backslash x01}$, and so on. This becomes increasingly unlikely,      but is easy to mitigate by instead approaching the problem from the left.      </p>      <p>      Take $c_{n-1}|c_n$, which will obviously satisfy the oracle (and give $p_2' =      p_n$). Then vary the bytes in $c_{n-1}$ from left to right and query the oracle      each time. If the oracle returns false on the $i$<sup>th</sup> byte, then the      remaining $k - i$ bytes are all equal to $k-i$. We also gain a substantial      speedup on the last block as we get all the plaintext at once.      </p>      <p>      Alternatively, we can check that when we determine the last byte it really is      $\mathtt{\backslash x01}$. Then all the other bytes must be correct, too. To do      this, vary the second last byte. If the padding is invalid, we know that we were      wrong about the last byte so we try again. This only needs to be checked once      per block. We lose the speedup advantage above, but it is simpler.      </p>      <h2>Code</h2>      <p>      I wrote a <a      href="https://github.com/fionn/cryptopals/blob/master/m17.py">program</a> that      does this.      </p>      <p>      Here it is in action.      </p>      <noscript><p>      You must enable JavaScript to see this :(      </p></noscript>      <asciinema-player author="Fionn Fitzmaurice"      author-img-url="https://www.maths.tcd.ie/~fionn/me.jpg"      author-url="https://www.maths.tcd.ie/~fionn/" cols="97" font-size="0.79em"      poster="npt:1" rows="34" src="tyger.json" title="Padding Oracle Attack">      </asciinema-player>      <hr size="1"/>      <p>      Update: I gave a talk on this, the slides are <a      href="padding_oracle.pdf">here</a>.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/padding_oracle/</guid>      <pubDate>Sat, 06 Aug 2016 00:00:00 +0000</pubDate>    </item>    <item>      <title>Arch on a MacBook</title>      <link>https://www.maths.tcd.ie/~fionn/misc/macbook/</link>      <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>      <content:encoded><![CDATA[<p>      This is what I did to put Arch Linux on my MacBook Pro <a      href="https://support.apple.com/kb/sp715" title="Technical      specifications">12,1</a> (A1502, 2015) with dm-crypt (LVM on LUKS). Much of the      start is taken from <a      href="https://loicpefferkorn.net/2015/01/arch-linux-on-macbook-pro-retina-2014-with-dm-crypt-lvm-and-suspend-to-disk/">this      blog post</a>, but it’s reproduced here because of fear of link-rot.      </p>      <p>      Here’s my hardware (from <code>lspci</code>).      </p>      <pre>00:00.0 Host bridge: Intel Corporation Broadwell-U Host Bridge -OPI (rev 09)00:02.0 VGA compatible controller: Intel Corporation Broadwell-U Integrated Graphics (rev 09)00:03.0 Audio device: Intel Corporation Broadwell-U Audio Controller (rev 09)00:14.0 USB controller: Intel Corporation Wildcat Point-LP USB xHCI Controller (rev 03)00:15.0 DMA controller: Intel Corporation Wildcat Point-LP Serial IO DMA Controller (rev 03)00:15.4 Serial bus controller [0c80]: Intel Corporation Wildcat Point-LP Serial IO GSPI Controller #1 (rev 03)00:16.0 Communication controller: Intel Corporation Wildcat Point-LP MEI Controller #1 (rev 03)00:1b.0 Audio device: Intel Corporation Wildcat Point-LP High Definition Audio Controller (rev 03)00:1c.0 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #1 (rev e3)00:1c.1 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #2 (rev e3)00:1c.2 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #3 (rev e3)00:1c.4 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #5 (rev e3)00:1c.5 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #6 (rev e3)00:1f.0 ISA bridge: Intel Corporation Wildcat Point-LP LPC Controller (rev 03)00:1f.3 SMBus: Intel Corporation Wildcat Point-LP SMBus Controller (rev 03)00:1f.6 Signal processing controller: Intel Corporation Wildcat Point-LP Thermal Management Controller (rev 03)02:00.0 Multimedia controller: Broadcom Corporation 720p FaceTime HD Camera03:00.0 Network controller: Broadcom Corporation BCM43602 802.11ac Wireless LAN SoC (rev 01)04:00.0 SATA controller: Samsung Electronics Co Ltd Device a801 (rev 01)05:00.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]06:00.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]06:03.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]06:04.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]06:05.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]06:06.0 PCI bridge: Intel Corporation DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]07:00.0 System peripheral: Intel Corporation DSL5520 Thunderbolt 2 NHI [Falcon Ridge 4C 2013]</pre>      <p>      This is the partition scheme we’ll end up with (45 GiB for OS X, 10 GiB for a      shared HFS+ partition and the rest (~177.8 GiB) for a LVM container).      </p>      <pre class="shell">sudo gdisk -l /dev/sdaGPT fdisk (gdisk) version 1.0.1 Partition table scan:  MBR: hybrid  BSD: not present  APM: not present  GPT: present Found valid GPT with hybrid MBR; using GPT.Disk /dev/sda: 490234752 sectors, 233.8 GiBLogical sector size: 512 bytesDisk identifier (GUID): XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXPartition table holds up to 128 entriesFirst usable sector is 34, last usable sector is 490234718Partitions will be aligned on 8-sector boundariesTotal free space is 262150 sectors (128.0 MiB) Number  Start (sector)    End (sector)  Size       Code  Name   1              40          409639   200.0 MiB   EF00  EFI System Partition   2          409640        94865191   45.0 GiB    AF05  Customer   3        94865192        96134727   619.9 MiB   AB00  Recovery HD   4        96396872       117368391   10.0 GiB    AF00  hfs   5       117368392       490234718   177.8 GiB   8E00  archlinux</pre>      <p>      It’s probably a good idea to make a backup first. I didn’t because I like to      live on the edge. You can boot into recovery mode later if you need to with      <kbd>⌘</kbd> + <kbd>R</kbd>.      </p>      <h2 id="osx"><a class="anchor" href="#osx"></a>OS X</h2>      <p>      Get an <a href="https://archlinux.org/download/">Arch image</a>, verify it and      burn it to a USB key with something like      </p>      <pre class="root-shell">dd if=archlinux-2016.05.01-dual.iso of=/dev/rdisk2 bs=4M && sync</pre>      <p>      where we use <code><b>r</b>disk2</code> to write to the raw disk and skip some      buffering. Use <code>diskutil</code> to figure out which disk to use.      </p>      <p>      Then resize the OS X partition and encrypt it with FileVault.      </p>      <h2 id="archlinux"><a class="anchor" href="#archlinux"></a>Arch Linux</h2>      <p>      Boot into Arch by holding the right <kbd>alt</kbd> key. To make the console font      larger, use <code>setfont sun12x22</code> (the biggest one on the system).      </p>      <p>      I had to set      </p>      <pre class="root-shell">echo 0 > /sys/module/hid_apple/parameters/iso_layout</pre>      <p>      to fix the keyboard layout, swapping <kbd>`</kbd> and <kbd>~</kbd> with      <kbd><</kbd> and <kbd>></kbd>. (See <a      href="https://wiki.archlinux.org/title/Apple_Keyboard#%3C_and_%3E_have_changed_place_with_^_and_%C2%B0_(or_@_and_#,_or_%60_and_~)">aw:      Apple Keyboard</a>.)      </p>      <p>      Then run <code>timedatectl set-ntp true</code>, connect to the internet and      update.      </p>      <h2 id="partitioning"><a class="anchor"      href="#partitioning"></a>Partitioning</h2>      <p>      Apple <a      href="https://developer.apple.com/library/archive/technotes/tn2166/_index.html">recommend</a>      leaving a 128 MiB gap between partitions.      </p>      <blockquote      cite="https://developer.apple.com/library/archive/technotes/tn2166/_index.html">      We leave free space after each partition to make it easier for future system      software to manipulate the partition map in ways that we can’t anticipate      currently.      </blockquote>      <p>      It’s debatable whether this is worthwhile.      </p>      <p>      With <code>cgdisk</code>:      </p>      <ul>      <li>delete the empty Apple partition;</li>      <li>make a small future HFS/HFS+ (<code>af00</code>) partition starting with      <code>+128M</code>;</li>      <li>make a large LVM (<code>8e00</code>) partition for the rest of the      disk;</li>      <li>write.</li>      </ul>      <p>      It should look like this in the end.      </p>      <pre>Part. #     Size        Partition Type            Partition Name----------------------------------------------------------------            3.0 KiB     free space   1        200.0 MiB   EFI System                EFI System Partition   2        45.0 GiB    Apple Core Storage        Customer   3        619.9 MiB   Recovery HD               Recovery HD            128.0 MiB   free space   4        10.0 GiB    Apple HFS/HFS+            hfs   5        177.8 GiB   Linux LVM                 archlinux</pre>      <h2 id="encrypting"><a class="anchor" href="#encrypting"></a>Encrypting</h2>      <p>      We’re going to encrypt <code>/dev/sdc5</code> with <a      href="https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#LVM_on_LUKS">LVM      on LUKS</a>. These are approximately the results I got from <code>cryptsetup      benchmark</code>.      </p>      <pre class="root-shell">cryptsetup benchmark# Tests are approximate using memory only (no storage IO).PBKDF2-sha1      1213629 iterations per second for 256-bit keyPBKDF2-sha256    1354749 iterations per second for 256-bit keyPBKDF2-sha512    1100289 iterations per second for 256-bit keyPBKDF2-ripemd160  897753 iterations per second for 256-bit keyPBKDF2-whirlpool  666185 iterations per second for 256-bit key#  Algorithm | Key |  Encryption |  Decryption     aes-cbc   128b   601.2 MiB/s  2589.5 MiB/s serpent-cbc   128b    78.5 MiB/s   511.4 MiB/s twofish-cbc   128b   178.7 MiB/s   328.4 MiB/s     aes-cbc   256b   443.6 MiB/s  1964.6 MiB/s serpent-cbc   256b    79.6 MiB/s   511.2 MiB/s twofish-cbc   256b   180.1 MiB/s   328.4 MiB/s     aes-xts   256b  2194.5 MiB/s  2182.6 MiB/s serpent-xts   256b   492.9 MiB/s   496.6 MiB/s twofish-xts   256b   319.2 MiB/s   324.4 MiB/s     aes-xts   512b  1703.8 MiB/s  1689.3 MiB/s serpent-xts   512b   513.7 MiB/s   496.8 MiB/s twofish-xts   512b   285.3 MiB/s   324.8 MiB/s</pre>      <p>      First we must <a      href="https://gitlab.com/cryptsetup/cryptsetup/-/wiki_pages/FrequentlyAskedQuestions#5-security-aspects">fill      the partition</a> with random-looking data. There is a clever way to do this      with dm-crypt.      </p>      <pre><span class="root-shell">cryptsetup open --type plain /dev/sdc5 container --key-file /dev/random</span><span class="root-shell">dd if=/dev/zero of=/dev/mapper/container bs=1M status=progress</span><span class="root-shell">cryptsetup close container</span></pre>      <p>      This took about 700 seconds. Next, encrypt the partition and put a logical      volume on it.      </p>      <pre><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><span class="root-shell">cryptsetup luksOpen /dev/sdc5 lvm</span><span class="root-shell">pvcreate /dev/mapper/lvm</span><span class="root-shell">vgcreate vgcrypt /dev/mapper/lvm</span><span class="root-shell">lvcreate --extents 100%FREE -n root vgcrypt</span><span class="root-shell">mkfs.ext4 /dev/mapper/vgcrypt-root</span></pre>      <p>      Now we can mount the volume with      </p>      <pre><span class="root-shell">mount /dev/mapper/vgcrypt-root /mnt</span><span class="root-shell">mkdir /mnt/boot</span><span class="root-shell">mount /dev/sdc1 /mnt/boot</span></pre>      <p>      where <code>/dev/sdc1</code> is the EFI system partition.      </p>      <h2 id="chrooting"><a class="anchor" href="#chrooting"></a>Chrooting</h2>      <p>      The rest follows the <a      href="https://wiki.archlinux.org/title/Installation_guide">wiki</a> quite      closely.      </p>      <pre><span class="root-shell">pacstrap -i /mnt base base-devel</span><span class="root-shell">genfstab -U /mnt >> /mnt/etc/fstab</span></pre>      <p>      The <code>-U</code> flag tells <code>genfstab</code> to use UUIDs. Now would be      a good time to edit the <code>fstab</code> to add the <em>discard</em> option      for TRIM, but let’s hold off on that.      </p>      <pre><span class="root-shell">arch-chroot /mnt /bin/bash</span><span class="root-shell">echo <em>xyza</em> > /etc/hostname</span></pre>      <p>      Edit <code>/etc/locale.gen</code> and uncomment <code>#en_IE.UTF-8</code>.      </p>      <pre><span class="root-shell">locale-gen</span><span class="root-shell">echo "LANG=en_IE.UTF-8" > /etc/locale.conf</span><span class="root-shell">ln -s /usr/share/zoneinfo/Europe/Dublin /etc/localtime</span></pre>      <p>      Edit the <code>/etc/mkinitcpio.conf</code> <code>MODULES</code> and      <code>HOOKS</code>      </p>      <pre>MODULES="i915"    # for a smoother boot screen⋮HOOKS="base udev consolefont autodetect modconf block keymap keyboard encrypt lvm2 filesystems fsck"</pre>      <p>      and build the initial ramdisk with <code>mkinitcpio -p linux</code>.      </p>      <p>      Now set up the bootloader.      </p>      <pre><span class="root-shell">mkdir -p /boot/loader/entries</span><span class="root-shell">vi /boot/loader/loader.conf</span></pre>      <p>      and add      </p>      <pre>default arch.conftimeout 3</pre>      <p>      Check that <code>dev/sdc1</code> is mounted properly with <code>findmnt      /boot</code>. Then make and edit <code>/boot/loader/entries/arch.conf</code>.      </p>      <pre>title       Arch Linuxlinux       /vmlinuz-linuxinitrd      /initramfs-linux.imgoptions     cryptdevice=/dev/sda5:vgcrypt:allow-discards root=/dev/mapper/vgcrypt-root rw</pre>      <p>      Note that there are <a      href="https://wiki.archlinux.org/title/Dm-crypt/Specialties#Discard.2FTRIM_support_for_solid_state_drives_.28SSD.29">security      implications</a> with enabling TRIM/discards.      </p>      <pre><span class="root-shell">bootctl install</span><span class="root-shell">pacman -S iw wpa_supplicant dialog</span><span class="root-shell">passwd</span></pre>      <p>      Shutdown, remove the installation media and reboot.      </p>      <h2 id="configuration"><a class="anchor"      href="#configuration"></a>Configuration</h2>      <p>      Let’s make some swap space.      </p>      <pre><span class="root-shell">fallocate -l 8G /swapfile</span><span class="root-shell">chmod 600 /swapfile</span><span class="root-shell">mkswap swapfile</span><span class="root-shell">swapon /swapfile</span></pre>      <p>      Check that this worked with <code>free -h</code> or <code>swapon --show</code>      and add      </p>      <pre>/swapfile none swap defaults 0 0</pre>      <p>      to the <code>fstab</code>.      </p>      <p>      For user management, make a new user and add them to the admin group.      </p>      <pre><span class="root-shell">useradd -m -G wheel -s /bin/bash <em>fionn</em></span><span class="root-shell">passwd <em>fionn</em></span></pre>      <p>      Then run <code>visudo</code>, uncomment <code># %wheel ALL=(ALL) ALL</code>, log      out and then back in again as a regular user.      </p>      <pre class="shell">sudo pacman -Syu bash-completion pkgfile</pre>      <p>      Now would be a good time to import <a      href="https://github.com/fionn/.dotfiles">.dotfiles</a>.      </p>      <p>      To get <code>netctl</code> to automatically connect to networks, install      <code>wpa_actiond</code> and enable <code>netctl-auto@wlp3s0.service</code>.      </p>      <p>      The console font is <small><em>very small</em></small>. Install      <code>terminus-font</code> and add the line      </p>      <pre>FONT=ter-124n</pre>      <p>      to <code>/etc/vconsole.conf</code>.      </p>      <h2 id="x11"><a class="anchor" href="#x11"></a>X11</h2>      <p>      <code>xf86-video-intel</code> seems to be necessary to avoid screen tearing      (<code>xf86-video-modesetting</code> doesn’t seem to help here). Edit      <code>/etc/X11/xorg.conf.d/20-intel.conf</code>.      </p>      <pre>Section "Device"   Identifier  "Intel Graphics"   Driver      "intel"   Option      "TearFree" "true"EndSection</pre>      <p>      There’s a lot of talk about <a      href="https://github.com/BlueDragonX/xf86-input-mtrack"><code>xf86-input-mtrack</code></a>,      but I find synaptics to be just fine. Here’s my <code>/etc/X11/xorg.conf.d/<a      href="50-synaptics.conf">50-synaptics.conf</a></code>. (<code>1</code>,      <code>2</code> and <code>3</code> correspond to left, middle and right.)      </p>      <pre># Example xorg.conf.d snippet that assigns the touchpad driver# to all touchpads. See xorg.conf.d(5) for more information on# InputClass.# DO NOT EDIT THIS FILE, your distribution will likely overwrite# it when updating. Copy (and rename) this file into# /etc/X11/xorg.conf.d first.# Additional options may be added in the form of#   Option "OptionName" "value"#Section "InputClass"        Identifier "touchpad catchall"        Driver "synaptics"        MatchIsTouchpad "on"        Option "TapButton1" "0"   # 1, 2, 3 for tapping        Option "TapButton2" "0"        Option "TapButton3" "0"# Custom options        Option "ClickFinger2" "2"        Option "ClickFinger3" "3"        Option "HorizTwoFingerScroll" "1"        Option "VertEdgeScroll" "1"        Option "PalmDetect" "1"        Option "RBCornerButton" "3"# This option is recommend on all Linux systems using evdev, but cannot be# enabled by default. See the following link for details:# https://who-t.blogspot.com/2010/11/how-to-ignore-configuration-errors.html        MatchDevicePath "/dev/input/event*"EndSection Section "InputClass"        Identifier "touchpad ignore duplicates"        MatchIsTouchpad "on"        MatchOS "Linux"        MatchDevicePath "/dev/input/mouse*"        Option "Ignore" "on"EndSection # This option enables the bottom right corner to be a right button on clickpads# and the right and middle top areas to be right / middle buttons on clickpads# with a top button area.# This option is only interpreted by clickpads.Section "InputClass"        Identifier "Default clickpad buttons"        MatchDriver "synaptics"        Option "SoftButtonAreas" "50% 0 82% 0 0 0 0 0"        Option "SecondarySoftButtonAreas" "58% 0 0 15% 42% 58% 0 15%"EndSection # This option disables software buttons on Apple touchpads.# This option is only interpreted by clickpads.Section "InputClass"        Identifier "Disable clickpad buttons on Apple touchpads"        MatchProduct "Apple|bcm5974"        MatchDriver "synaptics"        #Option "SoftButtonAreas" "0 0 0 0 0 0 0 0"EndSection</pre>      <p>      To swap the function and media keys, edit      <code>/etc/modprobe.d/hid_apple.conf</code>.      </p>      <pre>options hid_apple iso_layout=0   # for the key swap earlieroptions hid_apple fnmode=2</pre>      <p>      To map the media keys to the hardware, install <code>xorg-xbacklight</code>,      <code>alsa-utils</code> and, from the AUR, <a      href="https://aur.archlinux.org/packages/kbdlight/"><code>kbdlight</code></a>.      Edit <code>/etc/modprobe.d/snd_hda_intel.conf</code>.      </p>      <pre>options snd_hda_intel index=1,0</pre>      <p>      Bind the keys in <code>~/.i3/config</code> with something like this.      </p>      <pre>bindsym XF86KbdBrightnessUp exec --no-startup-id kbdlight up</pre>      <h2 id="lid"><a class="anchor" href="#lid"></a>Lid</h2>      <p>      Edit <code>/etc/systemd/logind.conf</code> and set      <code>HandleLidSwitch=Ignore</code> to stop the laptop from suspending whenever      the lid is closed.      </p>      <h2 id="mirrors"><a class="anchor" href="#mirrors"></a>Mirrors</h2>      <p>      Grab a new mirrorlist with      </p>      <pre><span class="shell">cd /etc/pacman.d</span><span class="shell">sudo mv mirrorlist mirrorlist.bkup</span><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></pre>      <p>      and uncomment a mirror.      </p>      <h2 id="trim"><a class="anchor" href="#trim"></a>TRIM</h2>      <p>      TRIM the filesystem.      </p>      <pre class="shell">sudo fstrim -v //: 163.5 GiB (175549890560 bytes) trimmed</pre>      <p>      Then enable <code>fstrim.timer</code> to periodically issue discards.      </p>      <h2 id="dpp"><a class="anchor" href="#dpp"></a>DPP</h2>      <p>      Put <code>xrandr --dpi 144</code> in <code>~/.xinitrc</code>.      </p>      <p>      GTK3+ is supposed to pick up the system DPP settings, but it doesn’t for me. The      solution is to set the font size to around 16 (using e.g.      <code>lxappearance-gtk3</code>). For Firefox, set      <code>layout.css.devPixelsPerPixel=1.4</code> in <code>about:config</code>.      </p>      <p>      For QT to pick up on the GTK theme, install <code>adwaita-qt5</code> from the      AUR. <em>Also export QT_STYLE_OVERRIDE=GTK+?</em>      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/macbook/</guid>      <pubDate>Sun, 22 May 2016 00:00:00 +0000</pubDate>    </item>    <item>      <title>A Raspberry Pi Tor Relay</title>      <link>https://www.maths.tcd.ie/~fionn/misc/alarmpi_tor/</link>      <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>      <content:encoded><![CDATA[<p>      Make an <code>alarmpi</code> directory, <code>cd</code> to it and follow the      Arch Linux ARM <a      href="https://archlinuxarm.org/platforms/armv7/broadcom/raspberry-pi-2">installation      instructions</a>. But in step 5, instead of just <code>wget</code>ting the      tarball, also do      </p>      <pre><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><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></pre>      <p>      (note that there’s some TLS-stripping redirection). Compare the <code>md5</code>      hash (<code>md5sum -c</code>) and verify the signature by getting the Arch Linux      ARM <a href="https://archlinuxarm.org/about/package-signing">package signing      key</a> (<a      href="https://pgp.circl.lu/pks/lookup?op=vindex&fingerprint=on&search=0x68B3537F39A313B3E574D06777193F152BDBE6A6"><code>0x77193F152BDBE6A6</code></a>).      </p>      <p>      Once we’re in the Pi, the first thing to do is set up package signing by <a      href="https://archlinuxarm.org/about/package-signing">following these      instructions</a>.      </p>      <p>      Then update and grab some useful packages.      </p>      <pre><span class="root-shell">pacman -Syu</span><span class="root-shell">pacman -S sudo vim bash-completion</span></pre>      <p>      Now it’s time for some user management. First enable root login over SSH      (temporarily) by editing <code>/etc/ssh/sshd_config</code> and adding      </p>      <pre>PermitRootLogin yes</pre>      <p>      and then reloading the dæmon. Log out and then back in as root. This is so we      can change the <code>alarm</code> username.      </p>      <pre><span class="root-shell">usermod -l <em>username</em> alarm</span><span class="root-shell">usermod -d /home/<em>username</em> -m <em>username</em></span></pre>      <p>      Disallow SSH root logins again and reload the dæmon.      </p>      <p>      (This isn’t necessary if you have a keyboard and screen. We’re strictly headless      here.)      </p>      <p>      Run <code>visudo</code> and uncomment the line      </p>      <pre># %wheel ALL=(ALL) ALL</pre>      <p>      to add the user to the sudoers file.      </p>      <p>      Now would be a good time to change the passwords. Do      </p>      <pre><span class="root-shell">passwd root</span><span class="root-shell">passwd <em>username</em></span></pre>      <p>      and log back in as the user.      </p>      <p>      Now that the system is taking shape, let’s do some customising before we get to      Tor.      </p>      <p>      To make things a bit friendlier, download your <a href="../vim/">Vim      configuration</a>.      </p>      <p>      Next up, set the <a href="https://wiki.archlinux.org/title/Locale">locale</a>      and <a      href="https://wiki.archlinux.org/title/System_time#Time_zone">timezone</a> stuff      (see the <a      href="https://wiki.archlinux.org/title/Installation_guide#Configure_the_system">installation      guide</a>).      </p>      <pre class="root-shell">localectl set-locale LANG=en_IE.UTF-8</pre>      <p>      Change the hostname with      </p>      <pre class="root-shell">hostnamectl set-hostname <em>hostname</em></pre>      <p>      and edit <code>/etc/hosts</code> and <a      href="https://wiki.archlinux.org/title/Network_configuration#Set_the_hostname">add      the hostname to the end</a>.      </p>      <p>      OK, now let’s get Tor (and <code>arm</code>).      </p>      <pre class="shell">sudo pacman -S tor arm</pre>      <p>      Edit <code>/etc/tor/torrc</code> to make it a relay. There might be some      port-forwarding to be done for the ORPort (9001) and DirPort (9030) as well as      SocksPort (9050). Note that we don’t need to run Tor as a dæmon — systemd takes      care of that.      </p>      <p>      To get <code>arm</code> working we need to open up the control port, but it’s      not safe to do so without some authentication. Run      </p>      <pre class="shell">tor --hash-password <em>password</em></pre>      <p>      and paste the hash into the <code>HashedControlPassword</code> line. Then open      up the control port on port 9051.      </p>      <p>      Start Tor and check its status. If all seems well, enable it. Run      </p>      <pre class="shell">sudo -u tor arm</pre>      <p>      to see how things are going.      </p>      <p>      <del>The last thing to do for Tor is sign up for the <a class="dead"      title="https://weather.torproject.org/">weather reports</a>.</del>      </p>      <p>      We’re done! But wait. Our relay is vulnerable. Let’s beef up the security by <a      href="https://blog.bigdinosaur.org/securing-ssh-with-iptables/">securing SSH      with iptables</a>. You can move old iptables around with      <code>iptables-save</code> and <code>iptables-restore</code>, but don’t forget      to <a      href="https://wiki.archlinux.org/title/Iptables#Configuration_and_usage">make      them persistent</a>.      </p>      <p>      The only internet-facing services should be Tor and an SSH dæmon. There’s      nothing else to do for Tor, but we can make SSH much more secure.      </p>      <p>      First of all, copy the <a      href="https://wiki.archlinux.org/title/SSH_keys">public key</a> over with      </p>      <pre class="shell">ssh-copy-id -i ~/.ssh/id_ed25519.pub 192.168.0.<em>x</em></pre>      <p>      and check if it worked. Probably you’ll have to edit <code>.ssh/config</code> if      you’re disallowing public key identification in general (<a      href="https://words.filippo.io/ssh-whoami-filippo-io/">which you probably should      be</a>).      </p>      <p>      Now you can harden the server by enforcing public key authentication and <a      href="https://stribika.github.io/2015/01/04/secure-secure-shell.html">choosing      good algorithms</a>.      </p>      <p>      Edit <code>/etc/motd</code> to get rid of the boilerplate. It could be nice to      print the ED25519 fingerprint here.      </p>      <p>      Finally, set up <a href="../ssh_hidden_service/">SSH as a hidden service</a> so      you can SSH to it from anywhere and have a static onion URL and all that.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/alarmpi_tor/</guid>      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>    </item>    <item>      <title>Recovering Deleted Data</title>      <link>https://www.maths.tcd.ie/~fionn/misc/recover_data/</link>      <description>Here’s what I did. […]</description>      <content:encoded><![CDATA[<p>      Here’s what I did.      </p>      <br/>      <pre class="shell">cp <em>file</em> ..</pre>      <p>      Well, I already had a file called <code><em>file</em></code> in the parent      directory. Whoops!      </p>      <p>      Here’s what I did to fix it.      </p>      <pre class="root-shell">grep -a -b "<em>text in the deleted file</em>" /dev/sda3530159385076:<em>some text in the deleted file</em> <span class="root-shell">dd if=/dev/sda3 count=8 skip=$(expr 530159385076 / 512 - 4)</span></pre>      <p>      <code>/dev/sda3</code> is my <code>/home</code> partition, so I’m grepping the      hard drive directly. That’s what the <code>-a</code> flag is for — it looks at      binary as if it’s text. The <code>-b</code> flag prints the byte offset, so we      know where on the drive it found the match.      </p>      <p>      Then we use <code>dd</code> to grab the data. <code>count=<em>n</em></code>      takes <code><em>n</em></code> blocks (512 bytes by default, can be changed with      <code>bs=<em>n</em></code>) and <code>skip=<em>n</em></code> skips      <code><em>n</em></code> blocks in. Here I go back 4 blocks and take 8, which was      enough in my case. When/if it works, add <code>of=file</code> to get the file      back. It might need editing to remove some binary.      </p>      <p>      An alternative is to give grep the <code>-C200</code> flag. This gives 200 lines      before and after the string for context. Maybe you can avoid <code>dd</code>      then.      </p>      <p>      This should work in most cases, unless the filesystem has already allocated the      space to another file. It obviously won’t work on encrypted discs, or if you      used something like <code>shred</code>. It has worked for me one out of two      times (the other time it borked my terminal), so YMMV.      </p>      <p>      It can take a really long time.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/recover_data/</guid>      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>    </item>    <item>      <title>How to Set Up an SSH Server as a Hidden Service</title>      <link>https://www.maths.tcd.ie/~fionn/misc/ssh_hidden_service/</link>      <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>      <content:encoded><![CDATA[<p>      This article assumes you’ve got an SSH dæmon on your host machine running on the      clearnet and you use <a href="https://ed25519.cr.yp.to/">Ed25519 keys</a>. If      you haven’t already, make your server secure: use <a      href="https://blog.bigdinosaur.org/securing-ssh-with-iptables/">iptables</a> (or      something equivalent) and <a      href="https://stribika.github.io/2015/01/04/secure-secure-shell.html">choose      good algorithms</a>.      </p>      <h2>      For the Host      </h2>      <p>      Add the following to <code>/etc/tor/torrc</code>.      </p>      <pre>HiddenServiceDir /var/lib/tor/ssh/HiddenServicePort 22 127.0.0.1:22HiddenServiceAuthorizeClient stealth <em>clientname</em></pre>      <p>      The first two lines are obvious. The last line isn’t strictly necessary, but      adds a fair bit of security by only allowing specified clients to connect. Read      the <a      href="https://2019.www.torproject.org/docs/tor-manual.html#HiddenServiceAuthorizeClient">man      page entry</a>.      </p>      <p>      Reload Tor and open      <code>/var/lib<wbr>/tor<wbr>/ssh<wbr>/hostname</wbr></wbr></wbr></code>. It      should look like this.      </p>      <pre><em>hostaddress</em>.onion <em>authcookie</em> # client: <em>clientname</em></pre>      <p>      That’s it.      </p>      <h2>      For the Client      </h2>      <p>      Now add      </p>      <pre>HidServAuth <em>hostaddress</em>.onion <em>authcookie</em></pre>      <p>      to your local <code>/etc/tor/torrc</code> file (i.e. the contents of the      <code>hostname</code> file becomes the value of <code>HidServAuth</code>). This      is only relevant if you used      <code>HiddenService<wbr>AuthorizeClient</wbr></code>. Again, read the <a      href="https://2019.www.torproject.org/docs/tor-manual.html#HidServAuth">man page      entry</a>.      </p>      <p>      We can now check if this all worked. But wait! SSH mitigates man-in-the-middle      attacks by displaying a fingerprint of its host key for you to verify. Before      you connect over Tor, you should get a copy of this fingerprint to compare.      </p>      <pre class="shell">ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub</pre>      <p>      It’s important to do this before you log in over Tor, but you can check after      the fact by looking for the public key in <code>~/.ssh/known_hosts</code> (if      you don’t obfuscate that file). It should obviously be the same over Tor and the      clearnet.      </p>      <p>      OK, let’s connect. Run      </p>      <pre class="shell">torify ssh -i ~/.ssh/id_ed25519 <em>username</em>@<em>hostaddress</em>.onion</pre>      <p>      and make sure the fingerprint matches what you expect.      </p>      <p>      If this worked, we just need to streamline the process. Let’s edit      <code>~/.ssh/config</code>. First, we need to get netcat to proxy SSH traffic.      I’m using <code>openbsd-netcat</code>, the syntax is slightly different for      <code>gnu-netcat</code>.      </p>      <pre>Host <em>hostname</em>    HostName <em>hostaddress</em>.onion    Port 22    User <em>username</em>    PubkeyAuthentication yes    IdentityFile ~/.ssh/id_ed25519    VerifyHostKeyDNS no    ProxyCommand nc -X 5 -x localhost:9050 %h %p</pre>      <ul>      <li><code>VerifyHostKeyDNS no</code> is there to avoid a DNS leak. This is the      default anyway, but DNS leaking is bad and you should make sure.</li>      <li><code>ProxyCommand nc -X 5 -x localhost:9050 %h %p</code> does the work of      <code>torify</code>. <code>-X 5</code> tells netcat to use SOCKS v5,      <code>-x</code> sets the proxy address and port. <code>%h</code> is replaced by      the value of <code>HostName</code> and <code>%p</code> by the value of      <code>Port</code> (or else is just set to 22). This assumes Tor is using port      9050, but it sometimes uses 9150 (if you’re using the TBB) — try both or check      the value of <code>TorPort</code> in <code>/etc/tor/torsocks.conf</code>.</li>      <li>You could also put the Tor-specific options under <code>Host      *.onion</code>.</li>      </ul>      <h2>      Finished      </h2>      <p>      Now you can just run      </p>      <pre class="shell">ssh <em>hostname</em></pre>      <p>      to connect to your server over Tor.      </p>      <p>      Some other things:      </p>      <ul>      <li>You can have as many hidden services as you like on the same machine.</li>      <li>Use <a href="https://github.com/katmagic/Shallot">Shallot</a>, <a      href="https://github.com/lachesis/scallion">Scallion</a>, etc. to generate      vanity <code>.onion</code> addresses, if you’re into that kind of thing.</li>      <li>Change the port for a bit of extra security through obscurity. You could      also try <a href="https://wiki.archlinux.org/index.php/Port_knocking">port      knocking</a>.</li>      <li>If you’re running your hidden service on a relay, this will <a      href="https://trac.torproject.org/projects/tor/ticket/8742">compromise your      anonymity</a>. The same holds if your hidden service is also serving something      on the clearnet.</li>      </ul>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/ssh_hidden_service/</guid>      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>    </item>    <item>      <title>Mounting an Encrypted LUKS Volume</title>      <link>https://www.maths.tcd.ie/~fionn/misc/mount_encrypted_volume/</link>      <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>      <content:encoded><![CDATA[<p>      It’s really easy. Let’s assume <code>sdb2</code> is the encrypted LUKS device      (because it is for me). <code>lsblk</code> shows the tree as this.      </p>      <pre>sdb               8:16   1    29G  0 disk├─sdb1            8:17   1   2.5G  0 part└─sdb2            8:18   1  26.5G  0 part</pre>      <p>      Open the LUKS container with      </p>      <pre class="root-shell">cryptsetup open /dev/sdb2 <em>luks_volume</em></pre>      <p>      (where <code><em>luks_volume</em></code> is the unimaginative name of the      container).      </p>      <p>      Now <code>lsblk</code> should show something like      </p>      <pre>sdb               8:16   1    29G  0 disk├─sdb1            8:17   1   2.5G  0 part└─sdb2            8:18   1  26.5G  0 part  └─<em>luks_volume</em> 254:0    0  26.5G  0 crypt</pre>      <p>      and we just have to mount it.      </p>      <pre><span class="root-shell">mkdir /mnt/<em>secrets</em>/</span><span class="root-shell">mount /dev/mapper/<em>luks_volume</em> /mnt/<em>secrets</em>/</span></pre>      <p>      That’s it. When done,      </p>      <pre><span class="root-shell">umount /mnt/<em>secrets</em></span><span class="root-shell">cryptsetup close <em>luks_volume</em></span><span class="root-shell">rm -r /mnt/<em>secrets</em>/</span></pre>      <p>      to remove the mapping and mount point and clear the key from memory.      </p>      ]]></content:encoded>      <author>fionn@this.domain (Fionn Fitzmaurice)</author>      <guid isPermaLink="true">https://www.maths.tcd.ie/~fionn/misc/mount_encrypted_volume/</guid>      <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>    </item>  </channel></rss> If you would like to create a banner that links to this page (i.e. this validation result), do the following:
Download the "valid RSS" banner.
Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)
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