This feed does not validate.
In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.
<link href="https://www.maths.tcd.ie/~fionn/misc/feed.xml" rel="self"/>
^
line 252, column 9: (14 occurrences) [help]
]]></content>
^
line 1704, column 38: (4 occurrences) [help]
<updated>1970-01-01T00:00:00+00:00</updated>
^
line 1888, column 40: (4 occurrences) [help]
<published>1970-01-01T00:00:00+00:00</published>
^
line 1893, column 38: (3 occurrences) [help]
<updated>1970-01-01T00:00:00+00:00</updated>
^
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<id>https://www.maths.tcd.ie/~fionn/misc/feed.atom</id>
<title>misc</title>
<updated>2024-08-23T16:13:11.630615+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<link href="https://www.maths.tcd.ie/~fionn/misc/feed.xml" rel="self"/>
<link href="https://www.maths.tcd.ie/~fionn/misc/" rel="alternate"/>
<contributor>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</contributor>
<generator version="0.1">fionn-feed</generator>
<icon>https://www.maths.tcd.ie/favicon.ico</icon>
<logo>https://www.maths.tcd.ie/~fionn/me.jpg</logo>
<subtitle>Fionn has no mouth but he must scream</subtitle>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/fido_ssh/</id>
<title>Biometric FIDO2/U2F SSH Keys</title>
<updated>2022-09-21T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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 info
Device type: YubiKey C Bio - FIDO Edition
Serial number: 17244581
Firmware version: 5.5.6
Form factor: Bio (USB-C)
Enabled USB interfaces: FIDO
Applications
FIDO2 Enabled
OTP Not available
FIDO U2F Enabled
OATH Not available
YubiHSM Auth Not available
OpenPGP Not available
PIV 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-pin
Enter 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 list
Enter 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 17244581
Generating 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_sk
Your public key has been saved in /home/fionn/.ssh/id_ed25519_sk.pub
The key fingerprint is:
SHA256:2fl1x8+ACfUB2UA3eV5mXLJY5Wr04K93N7nH6iN4OoY 17244581
The 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.com
Enter passphrase for key '/home/fionn/.ssh/id_ed25519_sk':
Confirm user presence for key ED25519-SK SHA256:2fl1x8+ACfUB2UA3eV5mXLJY5Wr04K93N7nH6iN4OoY
User presence confirmed
Hi <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 -K
Enter 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>
<link href="https://www.maths.tcd.ie/~fionn/misc/fido_ssh/"/>
<summary>Smartcards have traditionally supported SSH public key authentication using two methods: PIV and PGP. […]</summary>
<published>2022-09-21T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/feed/</id>
<title>RSS and Atom Feeds</title>
<updated>2018-09-18T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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>
<link href="https://www.maths.tcd.ie/~fionn/misc/feed/"/>
<summary>I think decentralised syndication is a good thing so I made RSS and Atom feeds for this pseudo-blog</summary>
<published>2018-09-18T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/encrypt_volume/</id>
<title>Encrypting a Volume</title>
<updated>2018-05-24T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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>
<link href="https://www.maths.tcd.ie/~fionn/misc/encrypt_volume/"/>
<summary>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). […]</summary>
<published>2018-05-24T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/wg/</id>
<title>WireGuard</title>
<updated>2017-12-07T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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/64
ListenPort = 2307
SaveConfig = true
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT && iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = 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/64
ListenPort = 2307
DNS = 10.10.0.1
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = 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, ::/0
Endpoint = [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>
<link href="https://www.maths.tcd.ie/~fionn/misc/wg/"/>
<summary>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. […]</summary>
<published>2017-12-07T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/vim/</id>
<title>Vim Plugins, the Right Way</title>
<updated>2017-09-17T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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>
<link href="https://www.maths.tcd.ie/~fionn/misc/vim/"/>
<summary>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). […]</summary>
<published>2017-09-17T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/ec_vpn/</id>
<title>Elliptic Curves and OpenVPN</title>
<updated>2017-04-27T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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 ec
set_var EASYRSA_CURVE secp521r1
set_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.crt
pki/issued/<em>servername</em>.crt
pki/private/<em>servername</em>.key
</pre>
<p>
and all the client files
</p>
<pre>
pki/ca.crt
pki/issued/<em>clientname</em>.crt
pki/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 1194
proto udp
dev tun
ca ecc/ca.crt
cert ecc/servername.crt
key ecc/servername.key
dh none
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1"
push "dhcp-option DNS 1.2.3.4"
keepalive 10 120
tls-crypt ecc/tc.key
auth SHA512
keysize 256
tls-server
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
cipher AES-256-GCM
reneg-sec 360
remote-cert-eku "TLS Web Client Authentication"
script-security 2
auth-user-pass-verify /etc/openvpn/server/auth/auth.py via-file
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
explicit-exit-notify 1
</pre>
<p>
And a client configuration.
</p>
<pre>
client
dev tun
proto udp
remote serverurl 1194
resolv-retry infinite
nobind
#user nobody
#group nobody
persist-key
persist-tun
tls-client
mute-replay-warnings
ca servername/ecc/ca.crt
cert servername/ecc/clientname.crt
key servername/ecc/clientname.key
remote-cert-eku "TLS Web Server Authentication"
verify-x509-name 'CN=servername' subject
remote-cert-tls server
tls-crypt servername/ecc/tc.key
cipher AES-256-GCM
auth SHA512
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
reneg-sec 360
#comp-lzo
verb 3
#mute 20
auth-user-pass servername/secret.password
redirect-gateway def1
script-security 2
up /etc/openvpn/client/servername/update-resolv-conf.sh
down /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>
<link href="https://www.maths.tcd.ie/~fionn/misc/ec_vpn/"/>
<summary>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. […]</summary>
<published>2017-04-27T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/mt/</id>
<title>The Mersenne Twister</title>
<updated>2017-05-23T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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>
<link href="https://www.maths.tcd.ie/~fionn/misc/mt/"/>
<summary>The Mersenne Twister is a 623-dimensionally equidistributed uniform pseudorandom number generator. This is how it works. […]</summary>
<published>2017-05-23T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/symmetry/</id>
<title>Symmetry in Particle Physics</title>
<updated>2016-09-26T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![CDATA[<p>
A while ago, I wrote an article for non-physicists about symmetry
and the Standard Model.
</p>
<br/>
]]></content>
<link href="https://www.maths.tcd.ie/~fionn/misc/symmetry/"/>
<summary>A while ago, I wrote an article for non-physicists about symmetry and the Standard Model. […]</summary>
<published>2016-09-26T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/padding_oracle/</id>
<title>The Padding Oracle Attack</title>
<updated>2016-08-06T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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>
<link href="https://www.maths.tcd.ie/~fionn/misc/padding_oracle/"/>
<summary>There are a bunch of writeups on this attack, such as
Robert Heaton's blog post,
SkullSecurity
(and their follow-up),
GDS,
mpgn,
Grymoire,
this crypto.SX post
and the paper by Serge Vaudenay.
Dan Boneh has a lecture on it
and this video is good too.
Here’s my digestion of it. […]</summary>
<published>2016-08-06T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/macbook/</id>
<title>Arch on a MacBook</title>
<updated>2016-05-22T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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 Camera
03: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/sda
GPT 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 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 490234718
Partitions will be aligned on 8-sector boundaries
Total 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 key
PBKDF2-sha256 1354749 iterations per second for 256-bit key
PBKDF2-sha512 1100289 iterations per second for 256-bit key
PBKDF2-ripemd160 897753 iterations per second for 256-bit key
PBKDF2-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.conf
timeout 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 Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options 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 earlier
options 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>
<link href="https://www.maths.tcd.ie/~fionn/misc/macbook/"/>
<summary>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. […]</summary>
<published>2016-05-22T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/alarmpi_tor/</id>
<title>A Raspberry Pi Tor Relay</title>
<updated>1970-01-01T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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>
<link href="https://www.maths.tcd.ie/~fionn/misc/alarmpi_tor/"/>
<summary>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 […]</summary>
<published>1970-01-01T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/recover_data/</id>
<title>Recovering Deleted Data</title>
<updated>1970-01-01T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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/sda3
530159385076:<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>
<link href="https://www.maths.tcd.ie/~fionn/misc/recover_data/"/>
<summary>Here’s what I did. […]</summary>
<published>1970-01-01T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/ssh_hidden_service/</id>
<title>How to Set Up an SSH Server as a Hidden Service</title>
<updated>1970-01-01T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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:22
HiddenServiceAuthorizeClient 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>
<link href="https://www.maths.tcd.ie/~fionn/misc/ssh_hidden_service/"/>
<summary>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. […]</summary>
<published>1970-01-01T00:00:00+00:00</published>
</entry>
<entry>
<id>https://www.maths.tcd.ie/~fionn/misc/mount_encrypted_volume/</id>
<title>Mounting an Encrypted LUKS Volume</title>
<updated>1970-01-01T00:00:00+00:00</updated>
<author>
<name>Fionn Fitzmaurice</name>
<email>fionn@this.domain</email>
</author>
<content type="CDATA"><![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>
<link href="https://www.maths.tcd.ie/~fionn/misc/mount_encrypted_volume/"/>
<summary>It’s really easy. Let’s assume sdb2 is the encrypted LUKS device (because it is for me). lsblk shows the tree as this. […]</summary>
<published>1970-01-01T00:00:00+00:00</published>
</entry>
</feed>