aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/generate.php4
-rw-r--r--composer.json3
-rw-r--r--composer.lock411
-rw-r--r--css/bootstrap-reboot.css331
-rw-r--r--css/screen.css140
-rw-r--r--css/simple.css408
-rw-r--r--img/eduVPN.pngbin0 -> 4855 bytes
-rw-r--r--img/fkooman.jpgbin25464 -> 0 bytes
-rw-r--r--pages/about.md12
-rw-r--r--pages/projects.md33
-rw-r--r--posts/openvpn_modern_crypto.md78
-rw-r--r--posts/openvpn_modern_crypto_part_ii.md72
-rw-r--r--posts/openvpn_modern_crypto_part_iii.md96
-rw-r--r--views/base.php37
-rw-r--r--views/index.php14
-rw-r--r--views/post.php4
16 files changed, 743 insertions, 900 deletions
diff --git a/bin/generate.php b/bin/generate.php
index 4c7400f..0c60ab0 100644
--- a/bin/generate.php
+++ b/bin/generate.php
@@ -6,8 +6,8 @@ $baseDir = dirname(__DIR__);
use fkooman\Template\Tpl;
use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment;
-use League\CommonMark\Ext\SmartPunct\SmartPunctExtension;
-use League\CommonMark\Ext\Table\TableExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Table\TableExtension;
$cgitRepoWebUrl = 'https://git.tuxed.net/fkooman/www.tuxed.net/';
$dateTime = new DateTime();
diff --git a/composer.json b/composer.json
index d8fc8ad..bb2ca6e 100644
--- a/composer.json
+++ b/composer.json
@@ -7,7 +7,6 @@
],
"require": {
"fkooman/tpl": "dev-master",
- "league/commonmark": "^1",
- "league/commonmark-extras": "^1"
+ "league/commonmark": "^1"
}
}
diff --git a/composer.lock b/composer.lock
index 8a0ec4e..81c8e6e 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "a68739cce0396fa57819b874db881b9a",
+ "content-hash": "c949322da362da62710cb8102e047ca7",
"packages": [
{
"name": "fkooman/tpl",
@@ -12,7 +12,7 @@
"source": {
"type": "git",
"url": "https://git.tuxed.net/fkooman/php-tpl",
- "reference": "f1b54e1577fde06bccac767aa4e884ee73258a1a"
+ "reference": "164daca4d080839cb81cb01c0b16a3d6df3dc756"
},
"require": {
"php": ">=5.4"
@@ -20,6 +20,7 @@
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5|^6|^7"
},
+ "default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
@@ -45,52 +46,46 @@
"email": "fkooman@tuxed.net",
"source": "https://git.tuxed.net/fkooman/php-tpl"
},
- "time": "2019-09-02T09:33:49+00:00"
+ "time": "2020-01-29T16:33:02+00:00"
},
{
"name": "league/commonmark",
- "version": "1.0.0",
+ "version": "1.5.7",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
- "reference": "7a40f2b0931602c504c2a9692d9f1e33635fd5ef"
+ "reference": "11df9b36fd4f1d2b727a73bf14931d81373b9a54"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/7a40f2b0931602c504c2a9692d9f1e33635fd5ef",
- "reference": "7a40f2b0931602c504c2a9692d9f1e33635fd5ef",
+ "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/11df9b36fd4f1d2b727a73bf14931d81373b9a54",
+ "reference": "11df9b36fd4f1d2b727a73bf14931d81373b9a54",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
- "php": "^7.1"
+ "php": "^7.1 || ^8.0"
},
- "replace": {
- "colinodell/commonmark-php": "*"
+ "conflict": {
+ "scrutinizer/ocular": "1.7.*"
},
"require-dev": {
"cebe/markdown": "~1.0",
- "commonmark/commonmark.js": "0.29.0",
+ "commonmark/commonmark.js": "0.29.2",
"erusev/parsedown": "~1.0",
+ "ext-json": "*",
+ "github/gfm": "0.29.0",
"michelf/php-markdown": "~1.4",
"mikehaertl/php-shellcommand": "^1.4",
- "phpstan/phpstan-shim": "^0.11.5",
- "phpunit/phpunit": "^7.5",
+ "phpstan/phpstan": "^0.12",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2",
"scrutinizer/ocular": "^1.5",
"symfony/finder": "^4.2"
},
- "suggest": {
- "league/commonmark-extras": "Library of useful extensions including smart punctuation"
- },
"bin": [
"bin/commonmark"
],
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.1-dev"
- }
- },
"autoload": {
"psr-4": {
"League\\CommonMark\\": "src"
@@ -108,370 +103,51 @@
"role": "Lead Developer"
}
],
- "description": "PHP Markdown parser based on the CommonMark spec",
+ "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)",
"homepage": "https://commonmark.thephpleague.com",
"keywords": [
"commonmark",
- "markdown",
- "parser"
- ],
- "time": "2019-06-29T11:19:01+00:00"
- },
- {
- "name": "league/commonmark-ext-autolink",
- "version": "v1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/commonmark-ext-autolink.git",
- "reference": "9f6da88485412b1c37a982c9fee8f4fbc2fa5ade"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark-ext-autolink/zipball/9f6da88485412b1c37a982c9fee8f4fbc2fa5ade",
- "reference": "9f6da88485412b1c37a982c9fee8f4fbc2fa5ade",
- "shasum": ""
- },
- "require": {
- "league/commonmark": "^1.0",
- "php": "^7.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^7.5"
- },
- "type": "commonmark-extension",
- "extra": {
- "branch-alias": {
- "dev-master": "1.1-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\CommonMark\\Ext\\Autolink\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Colin O'Dell",
- "email": "colinodell@gmail.com",
- "homepage": "https://www.colinodell.com",
- "role": "Lead Developer"
- }
- ],
- "description": "Extension for league/commonmark which autolinks URLs, emails, and @-mentions",
- "homepage": "https://github.com/thephpleague/commonmark-ext-autolink",
- "keywords": [
- "autolink",
- "commonmark",
- "extension",
+ "flavored",
"gfm",
"github",
+ "github-flavored",
"markdown",
- "twitter"
- ],
- "time": "2019-06-29T11:23:54+00:00"
- },
- {
- "name": "league/commonmark-ext-smartpunct",
- "version": "v1.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/commonmark-ext-smartpunct.git",
- "reference": "3746a86c91903fe200999a992de064f87b352019"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark-ext-smartpunct/zipball/3746a86c91903fe200999a992de064f87b352019",
- "reference": "3746a86c91903fe200999a992de064f87b352019",
- "shasum": ""
- },
- "require": {
- "league/commonmark": "^1.0",
- "php": "^7.1"
- },
- "require-dev": {
- "jgm/smartpunct": "0.29",
- "phpunit/phpunit": "^7.5"
- },
- "type": "commonmark-extension",
- "extra": {
- "branch-alias": {
- "dev-master": "1.2-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\CommonMark\\Ext\\SmartPunct\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Colin O'Dell",
- "email": "colinodell@gmail.com",
- "homepage": "https://www.colinodell.com",
- "role": "Lead Developer"
- }
- ],
- "description": "Intelligently converts ASCII quotes, dashes, and ellipses in Markdown to their Unicode equivalents",
- "homepage": "https://github.com/thephpleague/commonmark-ext-smartpunct",
- "keywords": [
- "commonmark",
- "extension",
- "markdown",
- "punctuation",
- "smartpunct"
+ "md",
+ "parser"
],
- "time": "2019-10-03T12:57:34+00:00"
- },
- {
- "name": "league/commonmark-ext-strikethrough",
- "version": "v1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/commonmark-ext-strikethrough.git",
- "reference": "99892ad549e101fe1fbe424ff71224efc32d2d68"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark-ext-strikethrough/zipball/99892ad549e101fe1fbe424ff71224efc32d2d68",
- "reference": "99892ad549e101fe1fbe424ff71224efc32d2d68",
- "shasum": ""
- },
- "require": {
- "ext-mbstring": "*",
- "league/commonmark": "^1.0",
- "php": "^7.1"
- },
- "replace": {
- "uafrica/commonmark-ext": ">=0.1.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^7.5"
- },
- "type": "commonmark-extension",
- "extra": {
- "branch-alias": {
- "dev-master": "1.1-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\CommonMark\\Ext\\Strikethrough\\": "src/"
- }
+ "support": {
+ "docs": "https://commonmark.thephpleague.com/",
+ "issues": "https://github.com/thephpleague/commonmark/issues",
+ "rss": "https://github.com/thephpleague/commonmark/releases.atom",
+ "source": "https://github.com/thephpleague/commonmark"
},
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
+ "funding": [
{
- "name": "Colin O'Dell",
- "email": "colinodell@gmail.com"
+ "url": "https://enjoy.gitstore.app/repositories/thephpleague/commonmark",
+ "type": "custom"
},
{
- "name": "Johan Meiring",
- "email": "johan@uafrica.com"
- }
- ],
- "description": "Strikethrough support for the PHP League's CommonMark Markdown parser",
- "homepage": "https://github.com/thephpleague/commonmark-ext-strikethrough",
- "keywords": [
- "commonmark",
- "extension",
- "markdown",
- "strikeout",
- "strikethrough"
- ],
- "time": "2019-06-29T11:34:00+00:00"
- },
- {
- "name": "league/commonmark-ext-table",
- "version": "v2.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/commonmark-ext-table.git",
- "reference": "3228888ea69636e855efcf6636ff8e6316933fe7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark-ext-table/zipball/3228888ea69636e855efcf6636ff8e6316933fe7",
- "reference": "3228888ea69636e855efcf6636ff8e6316933fe7",
- "shasum": ""
- },
- "require": {
- "league/commonmark": "~0.19.3|^1.0",
- "php": "^7.1"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^2.14",
- "phpstan/phpstan": "~0.11",
- "phpunit/phpunit": "^7.0|^8.0",
- "symfony/var-dumper": "^4.0",
- "vimeo/psalm": "^3.0"
- },
- "type": "commonmark-extension",
- "extra": {
- "branch-alias": {
- "dev-master": "2.2-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\CommonMark\\Ext\\Table\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Martin Hasoň",
- "email": "martin.hason@gmail.com"
+ "url": "https://www.colinodell.com/sponsor",
+ "type": "custom"
},
{
- "name": "Webuni s.r.o.",
- "homepage": "https://www.webuni.cz"
+ "url": "https://www.paypal.me/colinpodell/10.00",
+ "type": "custom"
},
{
- "name": "Colin O'Dell",
- "email": "colinodell@gmail.com",
- "homepage": "https://www.colinodell.com"
- }
- ],
- "description": "Table extension for league/commonmark",
- "homepage": "https://github.com/thephpleague/commonmark-ext-table",
- "keywords": [
- "commonmark",
- "extension",
- "markdown",
- "table"
- ],
- "time": "2019-09-26T13:28:33+00:00"
- },
- {
- "name": "league/commonmark-ext-task-list",
- "version": "v1.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/commonmark-ext-task-list.git",
- "reference": "9fe28f3527ab913b60d44bdc8d66829733cad7c6"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark-ext-task-list/zipball/9fe28f3527ab913b60d44bdc8d66829733cad7c6",
- "reference": "9fe28f3527ab913b60d44bdc8d66829733cad7c6",
- "shasum": ""
- },
- "require": {
- "league/commonmark": "^0.19|^1.0",
- "php": "^7.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^7.5"
- },
- "type": "commonmark-extension",
- "extra": {
- "branch-alias": {
- "dev-master": "1.1-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\CommonMark\\Ext\\TaskList\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
+ "url": "https://github.com/colinodell",
+ "type": "github"
+ },
{
- "name": "Colin O'Dell",
- "email": "colinodell@gmail.com",
- "homepage": "https://www.colinodell.com",
- "role": "Lead Developer"
- }
- ],
- "description": "Extension for league/commonmark which supports GFM-style task lists",
- "homepage": "https://github.com/thephpleague/commonmark-ext-task-list",
- "keywords": [
- "Lists",
- "commonmark",
- "extension",
- "gfm",
- "github",
- "markdown",
- "task"
- ],
- "time": "2019-07-11T00:35:13+00:00"
- },
- {
- "name": "league/commonmark-extras",
- "version": "1.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/commonmark-extras.git",
- "reference": "4947edfb292d6f38b309cd63c64d7b08558df315"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark-extras/zipball/4947edfb292d6f38b309cd63c64d7b08558df315",
- "reference": "4947edfb292d6f38b309cd63c64d7b08558df315",
- "shasum": ""
- },
- "require": {
- "league/commonmark": "^1.0",
- "league/commonmark-ext-autolink": "^1.0",
- "league/commonmark-ext-smartpunct": "^1.0",
- "league/commonmark-ext-strikethrough": "^1.0",
- "league/commonmark-ext-table": "^2.0",
- "league/commonmark-ext-task-list": "^1.0",
- "php": "^7.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^7.5"
- },
- "type": "commonmark-extension",
- "extra": {
- "branch-alias": {
- "dev-master": "1.2-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\CommonMark\\Extras\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
+ "url": "https://www.patreon.com/colinodell",
+ "type": "patreon"
+ },
{
- "name": "Colin O'Dell",
- "email": "colinodell@gmail.com",
- "homepage": "https://www.colinodell.com",
- "role": "Lead Developer"
+ "url": "https://tidelift.com/funding/github/packagist/league/commonmark",
+ "type": "tidelift"
}
],
- "description": "Useful extensions for customizing the league/commonmark Markdown parser",
- "homepage": "https://github.com/thephpleague/commonmark-extras",
- "keywords": [
- "Extras",
- "commonmark",
- "extensions",
- "gfm",
- "markdown"
- ],
- "time": "2019-07-13T11:56:05+00:00"
+ "time": "2020-10-31T13:49:32+00:00"
}
],
"packages-dev": [],
@@ -483,5 +159,6 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
- "platform-dev": []
+ "platform-dev": [],
+ "plugin-api-version": "2.0.0"
}
diff --git a/css/bootstrap-reboot.css b/css/bootstrap-reboot.css
deleted file mode 100644
index 09cf986..0000000
--- a/css/bootstrap-reboot.css
+++ /dev/null
@@ -1,331 +0,0 @@
-/*!
- * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
- * Copyright 2011-2019 The Bootstrap Authors
- * Copyright 2011-2019 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
- */
-*,
-*::before,
-*::after {
- box-sizing: border-box;
-}
-
-html {
- font-family: sans-serif;
- line-height: 1.15;
- -webkit-text-size-adjust: 100%;
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-}
-
-article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
- display: block;
-}
-
-body {
- margin: 0;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- font-size: 1rem;
- font-weight: 400;
- line-height: 1.5;
- color: #212529;
- text-align: left;
- background-color: #fff;
-}
-
-[tabindex="-1"]:focus {
- outline: 0 !important;
-}
-
-hr {
- box-sizing: content-box;
- height: 0;
- overflow: visible;
-}
-
-h1, h2, h3, h4, h5, h6 {
- margin-top: 0;
- margin-bottom: 0.5rem;
-}
-
-p {
- margin-top: 0;
- margin-bottom: 1rem;
-}
-
-abbr[title],
-abbr[data-original-title] {
- text-decoration: underline;
- -webkit-text-decoration: underline dotted;
- text-decoration: underline dotted;
- cursor: help;
- border-bottom: 0;
- -webkit-text-decoration-skip-ink: none;
- text-decoration-skip-ink: none;
-}
-
-address {
- margin-bottom: 1rem;
- font-style: normal;
- line-height: inherit;
-}
-
-ol,
-ul,
-dl {
- margin-top: 0;
- margin-bottom: 1rem;
-}
-
-ol ol,
-ul ul,
-ol ul,
-ul ol {
- margin-bottom: 0;
-}
-
-dt {
- font-weight: 700;
-}
-
-dd {
- margin-bottom: .5rem;
- margin-left: 0;
-}
-
-blockquote {
- margin: 0 0 1rem;
-}
-
-b,
-strong {
- font-weight: bolder;
-}
-
-small {
- font-size: 80%;
-}
-
-sub,
-sup {
- position: relative;
- font-size: 75%;
- line-height: 0;
- vertical-align: baseline;
-}
-
-sub {
- bottom: -.25em;
-}
-
-sup {
- top: -.5em;
-}
-
-a {
- color: #007bff;
- text-decoration: none;
- background-color: transparent;
-}
-
-a:hover {
- color: #0056b3;
- text-decoration: underline;
-}
-
-a:not([href]):not([tabindex]) {
- color: inherit;
- text-decoration: none;
-}
-
-a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
- color: inherit;
- text-decoration: none;
-}
-
-a:not([href]):not([tabindex]):focus {
- outline: 0;
-}
-
-pre,
-code,
-kbd,
-samp {
- font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
- font-size: 1em;
-}
-
-pre {
- margin-top: 0;
- margin-bottom: 1rem;
- overflow: auto;
-}
-
-figure {
- margin: 0 0 1rem;
-}
-
-img {
- vertical-align: middle;
- border-style: none;
-}
-
-svg {
- overflow: hidden;
- vertical-align: middle;
-}
-
-table {
- border-collapse: collapse;
-}
-
-caption {
- padding-top: 0.75rem;
- padding-bottom: 0.75rem;
- color: #6c757d;
- text-align: left;
- caption-side: bottom;
-}
-
-th {
- text-align: inherit;
-}
-
-label {
- display: inline-block;
- margin-bottom: 0.5rem;
-}
-
-button {
- border-radius: 0;
-}
-
-button:focus {
- outline: 1px dotted;
- outline: 5px auto -webkit-focus-ring-color;
-}
-
-input,
-button,
-select,
-optgroup,
-textarea {
- margin: 0;
- font-family: inherit;
- font-size: inherit;
- line-height: inherit;
-}
-
-button,
-input {
- overflow: visible;
-}
-
-button,
-select {
- text-transform: none;
-}
-
-select {
- word-wrap: normal;
-}
-
-button,
-[type="button"],
-[type="reset"],
-[type="submit"] {
- -webkit-appearance: button;
-}
-
-button:not(:disabled),
-[type="button"]:not(:disabled),
-[type="reset"]:not(:disabled),
-[type="submit"]:not(:disabled) {
- cursor: pointer;
-}
-
-button::-moz-focus-inner,
-[type="button"]::-moz-focus-inner,
-[type="reset"]::-moz-focus-inner,
-[type="submit"]::-moz-focus-inner {
- padding: 0;
- border-style: none;
-}
-
-input[type="radio"],
-input[type="checkbox"] {
- box-sizing: border-box;
- padding: 0;
-}
-
-input[type="date"],
-input[type="time"],
-input[type="datetime-local"],
-input[type="month"] {
- -webkit-appearance: listbox;
-}
-
-textarea {
- overflow: auto;
- resize: vertical;
-}
-
-fieldset {
- min-width: 0;
- padding: 0;
- margin: 0;
- border: 0;
-}
-
-legend {
- display: block;
- width: 100%;
- max-width: 100%;
- padding: 0;
- margin-bottom: .5rem;
- font-size: 1.5rem;
- line-height: inherit;
- color: inherit;
- white-space: normal;
-}
-
-progress {
- vertical-align: baseline;
-}
-
-[type="number"]::-webkit-inner-spin-button,
-[type="number"]::-webkit-outer-spin-button {
- height: auto;
-}
-
-[type="search"] {
- outline-offset: -2px;
- -webkit-appearance: none;
-}
-
-[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-::-webkit-file-upload-button {
- font: inherit;
- -webkit-appearance: button;
-}
-
-output {
- display: inline-block;
-}
-
-summary {
- display: list-item;
- cursor: pointer;
-}
-
-template {
- display: none;
-}
-
-[hidden] {
- display: none !important;
-}
-/*# sourceMappingURL=bootstrap-reboot.css.map */ \ No newline at end of file
diff --git a/css/screen.css b/css/screen.css
deleted file mode 100644
index 257bbee..0000000
--- a/css/screen.css
+++ /dev/null
@@ -1,140 +0,0 @@
-body {
- margin: 0 auto;
- background-color: #eeeeee;
- max-width: 850px;
-}
-
-@media (min-width: 850px) {
- div.header {
- padding-top: 1em;
- background: url(../img/train.jpg) no-repeat;
- width: 850px;
- height: 225px;
- }
-
- div.header h1, div.header h2 {
- text-align: center;
- color: #fff;
- }
-}
-
-div.content {
- text-align: justify;
- padding: 1em 1.5em;
- background-color: #fff;
-}
-
-ul.pages {
- padding: 0;
- margin-top: 5em;
- text-align: center;
-}
-
-ul.pages li {
- list-style: none;
- display: inline-block;
- padding: 1em;
-}
-
-ul.pages li.active a {
- background-color: #444;
- color: #fff;
-}
-
-ul.pages li a {
- background-color: #fff;
- color: #444;
- padding: 1em;
- text-decoration: none;
- font-weight: bold;
-}
-
-div.content a {
- text-decoration: underline;
- color: #b58422;
-}
-
-ul.index {
- padding: 0;
-}
-
-ul.index li {
- list-style: none;
- margin: 0.5em 0;
-}
-
-div.footer {
- margin: 1.5em 0;
- color: #888;
- font-size: 75%;
- text-align: center;
-}
-
-div.footer a {
- color: #888;
-}
-
-div.content img, div.content video, div.content audio {
- display: block;
- margin: 0 auto;
- max-width: 95%;
-}
-
-div.content a img {
- margin: 0;
-}
-
-code, pre {
- background-color: #eee;
-}
-
-blockquote {
- border-left: 2px solid #ddd;
- padding: 1em 0.5em 0.5em 1em;
- background-color: #eee;
-}
-
-code {
- padding: 0.1em;
-}
-
-pre {
- margin: 0;
- padding: 1em;
- border: 1px dotted #bbb;
-}
-
-pre {
- white-space: pre-wrap;
- font-size: 0.9em;
- margin-bottom: 1em;
-}
-
-table {
- border: 1px solid #ccc;
- width: 100%;
- border-collapse: collapse;
- margin: 1em 0;
-}
-
-thead tr {
- background-color: #eee;
- color: #555;
-}
-
-td, th {
- padding: 0.8em 0.5em;
-}
-
-tbody tr:nth-child(even) {
- background-color: #f4f4f4;
-}
-
-p.center {
- text-align: center;
-}
-
-small {
- color: gray;
- font-size: 80%;
-}
diff --git a/css/simple.css b/css/simple.css
new file mode 100644
index 0000000..3d3e8e9
--- /dev/null
+++ b/css/simple.css
@@ -0,0 +1,408 @@
+/* Set the global variables for everything. Change these to use your own fonts/colours. */
+:root {
+
+ /* Set sans-serif & mono fonts */
+ --sans-font: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir, "Nimbus Sans L", Roboto, Noto, "Segoe UI", Arial, Helvetica, "Helvetica Neue", sans-serif;
+ --mono-font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
+
+ /* Body font size. By default, effectively 18.4px, based on 16px as 'root em' */
+ --base-fontsize: 1.15rem;
+
+ /* Major third scale progression - see https://type-scale.com/ */
+ --header-scale: 1.25;
+
+ /* Line height is set to the "Golden ratio" for optimal legibility */
+ --line-height: 1.618;
+
+ /* Default (light) theme */
+ --bg: #FFF;
+ --accent-bg: #F5F7FF;
+ --text: #212121;
+ --text-light: #585858;
+ --border: #D8DAE1;
+ --accent: #0D47A1;
+ --accent-light: #90CAF9;
+ --code: #D81B60;
+ --preformatted: #444;
+ --marked: #FFDD33;
+}
+
+/* Dark theme */
+@media (prefers-color-scheme: dark) {
+ :root {
+ --bg: #212121;
+ --accent-bg: #2B2B2B;
+ --text: #DCDCDC;
+ --text-light: #ABABAB;
+ --border: #666;
+ --accent: #FFB300;
+ --accent-light: #FFECB3;
+ --code: #F06292;
+ --preformatted: #CCC;
+ }
+
+ img, video {
+ opacity: .6;
+ }
+}
+
+* {
+ /* Set the font globally */
+ font-family: var(--sans-font);
+}
+
+html {
+ font-size: 16px;
+}
+
+/* Make the body a nice central block */
+body {
+ color: var(--text);
+ background: var(--bg);
+ font-size: var(--base-fontsize);
+ line-height: var(--line-height);
+ margin: 0;
+}
+
+/* Make the main element a nice central block */
+main {
+ margin: 1rem auto 0;
+ max-width: 45rem;
+ padding: 0 .5rem;
+}
+
+/* Make the header bg full width, but the content inline with body */
+header {
+ background: var(--accent-bg);
+ border-bottom: 1px solid var(--border);
+ padding: 1.5rem 15rem;
+ margin-bottom: 3rem;
+}
+
+/* Reduces header padding on smaller screens */
+@media only screen and (max-width: 1200px) {
+ header {
+ padding: 1rem;
+ }
+
+ nav {
+ text-align: center;
+ }
+}
+
+/* Remove margins for header text */
+header h1,
+header p {
+ margin: 0;
+}
+
+/* Fix header line height when title wraps */
+header h1 {
+ line-height: 1.1;
+}
+
+/* Format navigation */
+nav {
+ font-size: 1rem;
+ line-height: 2;
+ padding: 1rem 0;
+}
+
+nav a {
+ margin: 1rem 1rem 0 0;
+ border: 1px solid var(--border);
+ border-radius: 5px;
+ color: var(--text) !important;
+ display: inline-block;
+ padding: .1rem 1rem;
+ text-decoration: none;
+ transition: .4s;
+}
+
+nav a:hover {
+ color: var(--accent) !important;
+ border-color: var(--accent);
+}
+
+nav a.current:hover {
+ text-decoration: none;
+}
+
+footer {
+ margin-top: 4rem;
+ padding: 2rem 1rem 1.5rem 1rem;
+ color: var(--text-light);
+ font-size: .9rem;
+ text-align: center;
+ border-top: 1px solid var(--border);
+}
+
+/* Format headers */
+h1 {
+ font-size: calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale) * var(--header-scale));
+ margin-top: calc(var(--line-height) * 1.5rem);
+}
+
+h2 {
+ font-size: calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale));
+ margin-top: calc(var(--line-height) * 1.5rem);
+}
+
+h3 {
+ font-size: calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale));
+ margin-top: calc(var(--line-height) * 1.5rem);
+}
+
+h4 {
+ font-size: calc(var(--base-fontsize) * var(--header-scale));
+ margin-top: calc(var(--line-height) * 1.5rem);
+}
+
+h5 {
+ font-size: var(--base-fontsize);
+ margin-top: calc(var(--line-height) * 1.5rem);
+}
+
+h6 {
+ font-size: calc(var(--base-fontsize) / var(--header-scale));
+ margin-top: calc(var(--line-height) * 1.5rem);
+}
+
+/* Format links & buttons */
+a,
+a:visited {
+ color: var(--accent);
+}
+
+a:hover {
+ text-decoration: none;
+}
+
+a button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+ border: none;
+ border-radius: 5px;
+ background: var(--accent);
+ font-size: 1rem;
+ color: var(--bg);
+ padding: .7rem .9rem;
+ margin: .5rem 0;
+ transition: .4s;
+}
+
+a button[disabled],
+button[disabled],
+input[type="submit"][disabled],
+input[type="reset"][disabled],
+input[type="button"][disabled] {
+ cursor: default;
+ opacity: .5;
+ cursor: not-allowed;
+}
+
+/* Set the cursor to '?' while hovering over an abbreviation */
+abbr {
+ cursor: help;
+}
+
+button:focus,
+button:enabled:hover,
+input[type="submit"]:focus,
+input[type="submit"]:enabled:hover,
+input[type="reset"]:focus,
+input[type="reset"]:enabled:hover,
+input[type="button"]:focus,
+input[type="button"]:enabled:hover {
+ opacity: .8;
+}
+
+/* Format the expanding box */
+details {
+ padding: .6rem 1rem;
+ background: var(--accent-bg);
+ border: 1px solid var(--border);
+ border-radius: 5px;
+ margin-bottom: 1rem;
+}
+
+summary {
+ cursor: pointer;
+ font-weight: bold;
+}
+
+details[open] {
+ padding-bottom: .75rem;
+}
+
+details[open] summary {
+ margin-bottom: .5rem;
+}
+
+details[open]>*:last-child {
+ margin-bottom: 0;
+}
+
+/* Format tables */
+table {
+ border-collapse: collapse;
+ width: 100%
+}
+
+td,
+th {
+ border: 1px solid var(--border);
+ text-align: left;
+ padding: .5rem;
+}
+
+th {
+ background: var(--accent-bg);
+ font-weight: bold;
+}
+
+tr:nth-child(even) {
+ /* Set every other cell slightly darker. Improves readability. */
+ background: var(--accent-bg);
+}
+
+table caption {
+ font-weight: bold;
+ margin-bottom: .5rem;
+}
+
+/* Lists */
+ol,
+ul {
+ padding-left: 3rem;
+}
+
+/* Format forms */
+textarea,
+select,
+input {
+ font-size: inherit;
+ font-family: inherit;
+ padding: .5rem;
+ margin-bottom: .5rem;
+ color: var(--text);
+ background: var(--bg);
+ border: 1px solid var(--border);
+ border-radius: 5px;
+ box-shadow: none;
+ box-sizing: border-box;
+ width: 60%;
+}
+
+/* Make the textarea wider than other inputs */
+textarea {
+ width: 80%
+}
+
+/* Makes input fields wider on smaller screens */
+@media only screen and (max-width: 720px) {
+ textarea,
+ select,
+ input {
+ width: 100%;
+ }
+}
+
+/* Ensures the checkbox and radio inputs do not have a set width like other input fields */
+input[type="checkbox"], input[type="radio"]{
+ width: auto;
+}
+
+/* do not show border around file selector button */
+input[type="file"] {
+ border: 0;
+}
+
+/* Without this any HTML using <fieldset> shows ugly borders and has additional padding/margin. (Issue #3) */
+fieldset {
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+/* Misc body elements */
+
+hr {
+ color: var(--border);
+ border-top: 1px;
+ margin: 1rem auto;
+}
+
+mark {
+ padding: 2px 5px;
+ border-radius: 4px;
+ background: var(--marked);
+}
+
+main img, main video {
+ max-width: 100%;
+ border-radius: 5px;
+}
+
+figure {
+ margin: 0;
+}
+
+figcaption {
+ font-size: .9rem;
+ color: var(--text-light);
+ text-align: center;
+ margin-bottom: 1rem;
+}
+
+blockquote {
+ margin: 2rem 0 2rem 2rem;
+ padding: .4rem .8rem;
+ border-left: .35rem solid var(--accent);
+ opacity: .8;
+ font-style: italic;
+}
+
+cite {
+ font-size: 0.9rem;
+ color: var(--text-light);
+ font-style: normal;
+}
+
+/* Use mono font for code like elements */
+code,
+pre,
+kbd,
+samp {
+ font-size: 1.075rem;
+ font-family: var(--mono-font);
+ color: var(--code);
+}
+
+kbd {
+ color: var(--preformatted);
+ border: 1px solid var(--preformatted);
+ border-bottom: 3px solid var(--preformatted);
+ border-radius: 5px;
+ padding: .1rem;
+}
+
+pre {
+ padding: 1rem 1.4rem;
+ max-width: 100%;
+ overflow: auto;
+ color: var(--preformatted);
+ background: var(--accent-bg);
+ border: 1px solid var(--border);
+ border-radius: 5px;
+}
+
+/* Fix embedded code within pre */
+pre code {
+ color: var(--preformatted);
+ background: none;
+ margin: 0;
+ padding: 0;
+}
diff --git a/img/eduVPN.png b/img/eduVPN.png
new file mode 100644
index 0000000..fc7cd49
--- /dev/null
+++ b/img/eduVPN.png
Binary files differ
diff --git a/img/fkooman.jpg b/img/fkooman.jpg
deleted file mode 100644
index 952d6d4..0000000
--- a/img/fkooman.jpg
+++ /dev/null
Binary files differ
diff --git a/pages/about.md b/pages/about.md
index bfff315..dbb4bfd 100644
--- a/pages/about.md
+++ b/pages/about.md
@@ -2,8 +2,6 @@
title: About
---
-![fkooman](img/fkooman.jpg)
-
I am François, software developer, living in Berlin. Working mostly on security
software related to VPNs, authentication and authorization (SAML, OIDC, OAuth).
Mostly working with [PHP](https://www.php.net/), but interested in, and
@@ -16,4 +14,12 @@ You can reach me by email at [fkooman@tuxed.net](mailto:fkooman@tuxed.net).
### "Social"
* [Twitter](https://twitter.com/fkooman)
-* [GitHub](https://github.com/fkooman)
+* [Lobsters](https://lobste.rs/u/fkooman)
+* [sr.ht](https://sr.ht/~fkooman)
+
+### Signing Keys
+
+I use the following keys to sign software releases:
+
+* [minisign](files/fkooman-20190721.minisign.pub)
+* [PGP](files/fkooman.pgp.txt)
diff --git a/pages/projects.md b/pages/projects.md
index 43cd4f4..a2d3879 100644
--- a/pages/projects.md
+++ b/pages/projects.md
@@ -2,28 +2,11 @@
title: Projects
---
-I'm working on [eduVPN](https://www.eduvpn.org/) and
-[Let's Connect!](https://www.letsconnect-vpn.org/). They are fully managed VPN
-solution, initially developed for education and research as eduVPN, but
-currently capable of handling many different VPN scenarios and able to replace
-many (commercial) VPN solutions to provide a fast, flexible, secure and not
-to mention, fully free software VPN service for any organization.
-
-Next, and as part of the work on eduVPN / Let's Connect! I wrote and maintain a
-number of libraries and applications written in PHP and Go. All of them are
-available both as Git repositories and as signed source archives.
-
-* [Git](https://git.tuxed.net/)
-* [Source Archives](https://src.tuxed.net/)
-
-The source archives are signed with [PGP](https://gnupg.org/) and
-[minisign](https://jedisct1.github.io/minisign/).
-
-You can download my public minisign key
-[here](files/fkooman-20190721.minisign.pub) and my public PGP key
-[here](files/fkooman.pgp.txt).
-
-**NOTE**: I do not offer (free) support for this software, nor commit to
-maintaining them indefinitely. Feel free to use them, according to the license,
-ask questions, offer suggestions, or talk to me about contributing changes, but
-at all times be ready to take over maintenance of your local copy.
+![eduVPN](img/eduVPN.png)
+
+I'm working on [eduVPN](https://www.eduvpn.org/). The eduVPN project provides a
+fully managed VPN solution, for education and research capable of handling many
+different VPN scenarios and able to replace most (commercial) VPN solutions to
+provide a fast, flexible, secure and not to mention, fully free software VPN
+service for any organization, scaling from a Raspberry Pi to multi server
+10 Gbit setups.
diff --git a/posts/openvpn_modern_crypto.md b/posts/openvpn_modern_crypto.md
new file mode 100644
index 0000000..62f7334
--- /dev/null
+++ b/posts/openvpn_modern_crypto.md
@@ -0,0 +1,78 @@
+---
+title: OpenVPN and Modern Crypto
+published: 2019-10-11
+modified: 2019-10-14
+---
+
+_This blog post is a copy of a blog post I wrote for the eduVPN blog..._
+
+We decided to investigate what it would take to modernize the cryptography used
+to establish the TLS control channel with OpenVPN. See our current
+[configuration](https://github.com/eduvpn/documentation/blob/v2/SECURITY.md)
+documentation as used by eduVPN. The reason for looking into this is to get
+[improved security and increased performance](https://www.ietf.org/blog/tls13/),
+when switching to TLSv1.3 and possibly switching key type. This is relevant for
+the connection setup when establishing a OpenVPN connection.
+
+What we tried to accomplish these two tasks specifically:
+
+1. Use TLSv1.3 instead of TLSv1.2;
+2. Use Ed25519 instead of RSA for the OpenVPN client and server keys.
+
+In order to test with TLSv1.3 and Ed25519, we used our own CA for issuing
+certificates, [vpn-ca](https://github.com/fkooman/vpn-ca) that also
+recently added [support](https://github.com/fkooman/vpn-ca/tree/ed25519) for
+Ed25519 keys and certificates and will in the near future replace
+[easy-rsa](https://github.com/OpenVPN/easy-rsa) in eduVPN.
+
+In order to modify the configuration, we can specify that the minimum version
+of TLS that can be used is 1.3.
+
+ tls-version-min 1.3
+
+We no longer need the `tls-cipher` configuration option, as all ciphers
+supported by TLSv1.3 are secure. The client can decide.
+
+It turns out, not many (existing) OpenVPN clients are capable of supporting
+TLSv1.3 and/or Ed25519 keys out of the box.
+
+Client | Works? | Notes
+------------------------------ | --------- | --------------------------------------
+[OpenVPN Community](https://openvpn.net/community-downloads/) (Windows) | No | OpenSSL 1.1.0j
+[TunnelKit](https://github.com/passepartoutvpn/tunnelkit) | No | OpenSSL-Apple (1.1.0l.4) **(1)**
+[Viscosity](https://www.sparklabs.com/viscosity/) (Windows, macOS) | No | OpenSSL 1.0.2t **(2)**
+[Tunnelblick](https://tunnelblick.net/) (macOS) | **Yes** | Requires Config Change **(3)**
+[OpenVPN for Android](https://github.com/schwabe/ics-openvpn) | **Yes** | has OpenSSL 1.1.1a
+OpenVPN Connect (iOS) | No | OpenSSL 1.0.2s, mbed TLS 2.7.12
+OpenVPN Connect (Android) | No | OpenSSL 1.0.2s, mbed TLS 2.7.12
+Linux | **Maybe** | when distribution has OpenSSL >= 1.1.1
+
+The eduVPN clients are based on some of the above, so whatever the above
+clients support is important for eduVPN as well!
+
+Clients depending on OpenSSL needs to use OpenSSL >= 1.1.1, otherwise there is
+no support for TLSv1.3 and Ed25519. When a client uses mbed TLS, there is no
+support for TLSv1.3 or Ed25519 at all.
+
+Interestingly, some clients use OpenSSL versions that are no longer
+supported upstream. Only 1.1.1 and 1.0.2 are still supported. See the OpenSSL
+[Release Strategy](https://www.openssl.org/policies/releasestrat.html).
+
+For eduVPN specifically, there may be some additional hurdles to take: the
+platform may not support Ed25519 keys in its platform native certificate store.
+More research is needed here, but having "Yes" in the "Works?" column above is
+a good first step, even when we are required to use RSA keys for a little while
+longer.
+
+### Notes
+
+**(1)** We opened an [issue](https://github.com/passepartoutvpn/tunnelkit/issues/123)
+upstream
+
+**(2)** We sent a mail on 2019-10-11 to `support@sparklabs.com` to ask for
+updating OpenSSL as used by Viscosity. Their response: "...we’ll likely be
+adopting 1.1.1 with an upcoming OpenVPN 2.4.x release..."
+
+**(3)** In Tunnelblick, the "OpenVPN version" needs to be changed to
+`2.4.7 - OpenSSL v1.1.1d` under "Configurations". We tested with
+Tunnelblick 3.8.2beta01 (build 5401)
diff --git a/posts/openvpn_modern_crypto_part_ii.md b/posts/openvpn_modern_crypto_part_ii.md
new file mode 100644
index 0000000..2da86f6
--- /dev/null
+++ b/posts/openvpn_modern_crypto_part_ii.md
@@ -0,0 +1,72 @@
+---
+title: OpenVPN and Modern Crypto (Part II)
+published: 2020-09-11
+---
+
+_This blog post is a copy of a blog post I wrote for the eduVPN blog..._
+
+Last year we decided to [investigate](openvpn_modern_crypto.html) the
+OpenVPN client support of TLSv1.3 and EdDSA (Ed25519). One reason for doing
+this is, to stay
+[current](https://latacora.micro.blog/2018/04/03/cryptographic-right-answers.html)
+with algorithm recommendations by experts and
+[move away from RSA](https://blog.trailofbits.com/2019/07/08/fuck-rsa/). As
+EdDSA is easier to implement [securely](https://safecurves.cr.yp.to/) and has
+built-in protections against attacks that other curves, most notably, the NIST
+curves, do not have, there are fewer things that can go wrong. This can make
+the VPN more secure.
+
+The other reason is performance. Generating RSA keys is slow, very slow. As we
+currently generate the keys on the server, this potentially results in high CPU
+load when many clients want to obtain a (new) certificate at around the same
+time, for example at the start of the work day. For a service with hundreds or
+thousands of users, this can create problems. Also, on a Raspberry Pi, yes
+eduVPN / Let's Connect!
+[supports](https://github.com/eduvpn/documentation/blob/v2/RASPBERRY_PI.md) the
+Raspberry Pi, it is slow to generate RSA keys, which can take many seconds. No
+fun!
+
+A simple
+[benchmark](https://github.com/letsconnectvpn/vpn-ca/blob/main/benchmark.sh)
+running on a laptop from 2012, and Raspberry Pi 3 Model B+ shows the clear
+difference. The benchmark generates a self signed CA then generates 50 keys and
+signs each of them using the CA. The time varies per execution, but they show a
+clear, very big difference. The time between brackets is key generation and
+signing per certificate, on average.
+
+Key Type | Laptop | Raspberry Pi
+-------- | ----------- | ------------
+RSA | 63s (1.26s) | 368s (7.36s)
+ECDSA | 1s | 4s
+EdDSA | 0s | 1s
+
+We decided to check the status of the clients again to investigate whether it
+is possible to upgrade to TLSv1.3 and EdDSA in the next version of eduVPN /
+Let's Connect!. Luckily, much has changed since last year and support for EdDSA
+and TLSv1.3 looks a lot better now!
+
+The eduVPN / Let's Connect! 2.x server meanwhile supports EdDSA (and ECDSA) out
+of the box, but will keep RSA as the default. However the server can easily be
+configured to use ECDSA or EdDSA.
+
+We'll again go over the list of clients that were tested last year. The updated
+results can be found in the table.
+
+Application | Works? | Version
+----------------------------------------------------------------------- | ------ | --------------------------------------
+[OpenVPN Community](https://openvpn.net/community-downloads/) (Windows) | Yes | 2.4.9 on Windows 10
+[Passepartout](https://passepartoutvpn.app/) | Yes | 1.12.0 (2390) on iOS
+[Viscosity](https://www.sparklabs.com/viscosity/) (Windows, macOS) | Yes | 1.8.6 (Windows, macOS)
+[Tunnelblick](https://tunnelblick.net/) (macOS) | Yes | 3.8.3a (build 5521)
+[OpenVPN for Android](https://github.com/schwabe/ics-openvpn) | Yes | 0.7.16
+OpenVPN Connect (iOS) | Yes | 3.2.0 (3253)
+OpenVPN Connect (Android) | Yes | 3.2.2 (5027)
+Linux | Yes | _Modern Distributions_
+
+This looks good! With modern Linux distributions we mean Fedora, Debian 10,
+Ubuntu 20.04, and any other distribution or OS with OpenSSL >= 1.1.1.
+
+It seems we should be able to update to TLSv1.3 and EdDSA in the next major
+version of eduVPN / Let's Connect!. The eduVPN / Let's Connect! apps are based
+on OpenVPN (Community) and the TunnelKit library used by Passepartout. We'll
+even keep supporting the standard OpenVPN clients!
diff --git a/posts/openvpn_modern_crypto_part_iii.md b/posts/openvpn_modern_crypto_part_iii.md
new file mode 100644
index 0000000..a138eb5
--- /dev/null
+++ b/posts/openvpn_modern_crypto_part_iii.md
@@ -0,0 +1,96 @@
+---
+title: OpenVPN and Modern Crypto (Part III)
+published: 2021-02-03
+---
+
+[Previously](openvpn_modern_crypto_part_ii.html), and
+[earlier](openvpn_modern_crypto.html), we looked at modernizing the TLS
+configuration of OpenVPN. However, TLS is not the only cryptography used by
+OpenVPN. There's also the data channel.
+
+There are a number of options when choosing a cipher for the data channel. The
+most obvious one, and until very recently, the best available in OpenVPN is
+`AES-256-GCM`. This algorithm has been used from the start by
+[eduVPN](https://www.eduvpn.org/).
+
+Recently
+OpenVPN [2.5](https://github.com/OpenVPN/openvpn/blob/release/2.5/Changes.rst)
+was released which supports a modern cipher that can be used for data channel
+encryption: ChaCha20-Poly1305 as described in
+[RFC 7539](https://www.rfc-editor.org/rfc/rfc7539.html).
+
+Most CPUs have
+[instructions](https://en.wikipedia.org/wiki/AES_instruction_set) to speed up
+AES (GCM) and implement AES-GCM in constant time, reducing the likelihood of a
+successful side channel attacks against the cipher. However, not _all_ hardware
+has it, for example the Raspberry Pi 3B+. We'll analyze the difference in
+performance of these algorithms both on a device with AES hardware support and
+one without, the (in)famous Raspberry Pi.
+
+There may also be other
+[reasons](https://soatok.blog/2020/05/13/why-aes-gcm-sucks/) _not_ to use AES,
+irrespective of hardware acceleration. And of course, one has to trust the CPU
+to properly implement AES-GCM _and_ adequately prevent side channel attacks.
+Trusting your CPU is not a given, as was demonstrated over the last years. Not
+all CPUs are entirely flawless, it turned out, starting with the
+[Meltdown](https://meltdownattack.com/) "revelations". It may be wise not to
+trust your hardware to prevent side channel attacks and instead opt for an
+algorithm that is side channel attack resistant by design, i.e.
+ChaCha20-Poly1305.
+
+We'll do some rudimentary performance analysis of the algorithms using the
+OpenSSL command line tool:
+
+```
+for ALG in aes-256-gcm chacha20-poly1305; do
+ openssl speed \
+ -evp ${ALG} \
+ -bytes 1500 \
+ 2> /dev/null | grep "^${ALG}"
+done
+```
+
+This should give us a rough indication what the difference in algorithms will
+do to the performance of OpenVPN. If you want to replicate this on your own
+hardware, you need a relatively recent version of OpenSSL, as old(er) versions
+do not have the `-bytes` option, and even older version do not even have
+ChaCha20-Poly1305 support...
+
+### Lenovo
+
+Our trusty Lenovo laptop has been out of support for a while now, and thus will
+not receive any firmware/microcode updates anymore to mitigate CPU bugs. Let's
+see how it performs. The OS is Fedora 33 (x86_64):
+
+| Algorithm | Speed (kB/s) | Speed (%) |
+| ------------------- | ------------ | --------- |
+| `aes-256-gcm` | 979,299 | 100 |
+| `chacha20-poly1305` | 701,373 | 71 |
+
+The result is quite clear: you can expect more performance from AES-GCM than
+ChaCha20-Poly1305 when accelerated AES is available.
+
+### Raspberry Pi 3B+
+
+Our Raspberry Pi 3B+ is also happily churning away with the official Fedora 33
+(aarch64):
+
+| Algorithm | Speed (kB/s) | Speed (%) |
+| ------------------- | ------------ | --------- |
+| `aes-256-gcm` | 25,586 | 100 |
+| `chacha20-poly1305` | 159,755 | 624 |
+
+The picture is completely different here. When hardware accelerated AES is
+*not* available, you can expect a 6 time improvement in throughput when using
+ChaCha20-Poly1305 on the Raspberry Pi. Ouch!
+
+In order to get the best performance in all cases, it _may_ make sense to allow
+the _client_ to pick the algorithm to use. For example on slower devices,
+mostly (older) mobile devices may be much better off with ChaCha20-Poly1305
+than AES-256-GCM and thus be faster and save battery. An exercise for the
+reader might be to run the OpenSSL performance tests on their mobile devices :)
+
+_Special thanks to Jan Just Keijser for help with interpreting the OpenSSL_
+_speed results and his_
+_[work](https://www.nikhef.nl/~janjust/presentations/OpenVPN-NL_20171109.pdf)_
+_on OpenVPN performance testing._
diff --git a/views/base.php b/views/base.php
index dc52cd7..9e9e392 100644
--- a/views/base.php
+++ b/views/base.php
@@ -6,35 +6,30 @@
<!-- Generated on <?php echo $this->e($generatedOn); ?> -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo $this->e($blogTitle); ?> - <?php echo $this->e($pageTitle); ?></title>
- <link rel="stylesheet" type="text/css" href="<?php echo $this->e($requestRoot); ?>css/bootstrap-reboot.css">
- <link rel="stylesheet" type="text/css" href="<?php echo $this->e($requestRoot); ?>css/screen.css">
+ <link rel="stylesheet" type="text/css" href="<?php echo $this->e($requestRoot); ?>css/simple.css">
</head>
<body>
- <div class="header">
+<header>
<h1><?php echo $this->e($blogTitle); ?></h1>
-<?php if ('' !== $blogDescription): ?>
+<?php if ('' !== $blogDescription) { ?>
<h2><?php echo $this->e($blogDescription); ?></h2>
-<?php endif; ?>
- <ul class="pages">
-<?php foreach ($pagesList as $p): ?>
-<?php if ($p['fileName'] === $activePage): ?>
- <li class="active">
+<?php } ?>
+<nav>
+<?php foreach ($pagesList as $p) { ?>
+<?php if ($p['fileName'] === $activePage) { ?>
<a href="<?php echo $this->e($requestRoot); ?><?php echo $this->e($p['fileName']); ?>"><?php echo $this->e($p['title']); ?></a>
- </li>
-<?php else: ?>
- <li>
+<?php } else { ?>
<a href="<?php echo $this->e($requestRoot); ?><?php echo $this->e($p['fileName']); ?>"><?php echo $this->e($p['title']); ?></a>
- </li>
-<?php endif; ?>
-<?php endforeach; ?>
- </ul>
- </div> <!-- /header -->
- <div class="content">
+<?php } ?>
+<?php } ?>
+</nav>
+</header>
+<main>
<?php echo $this->section('content'); ?>
- </div> <!-- /content -->
+</main>
- <div class="footer">
+<footer>
<p>&copy; <?php echo $this->e($currentYear); ?> <?php echo $this->e($blogAuthor); ?></p>
- </div> <!-- /footer -->
+</footer>
</body>
</html>
diff --git a/views/index.php b/views/index.php
index 319f617..f969f82 100644
--- a/views/index.php
+++ b/views/index.php
@@ -1,12 +1,12 @@
-<?php foreach ($postsYearList as $year => $postsList): ?>
-<h3><?=$this->e($year); ?></h3>
+<?php foreach ($postsYearList as $year => $postsList) { ?>
+<h3><?php echo $this->e($year); ?></h3>
<ul class="index">
-<?php foreach ($postsList as $post): ?>
-<?php if ($post['publish']): ?>
+<?php foreach ($postsList as $post) { ?>
+<?php if ($post['publish']) { ?>
<li>
<a href="blog/<?php echo $this->e($post['fileName']); ?>"><?php echo $this->e($post['title']); ?></a> <small><?php echo $this->e($post['published']); ?></small>
</li>
-<?php endif; ?>
-<?php endforeach; ?>
+<?php } ?>
+<?php } ?>
</ul>
-<?php endforeach; ?>
+<?php } ?>
diff --git a/views/post.php b/views/post.php
index 491dc07..50a70a0 100644
--- a/views/post.php
+++ b/views/post.php
@@ -8,8 +8,8 @@
</p>
<?php echo $post['htmlContent']; ?>
-<?php if ($post['modified']): ?>
+<?php if ($post['modified']) { ?>
<p class="center"><small>Last Modified on <?php echo $this->e($post['modified']); ?></small></p>
-<?php endif; ?>
+<?php } ?>
<p class="center"><small><a href="<?php echo $this->e($post['postHistory']); ?>">History</a></small></p>
<?php $this->stop('content'); ?>