From b792fd461d3aec198d92518ba35379e295caf2f1 Mon Sep 17 00:00:00 2001 From: the-djmaze <3752035+the-djmaze@users.noreply.github.com> Date: Wed, 28 Oct 2026 02:51:22 +0100 Subject: [PATCH] Added Base32 for handling GnuPG WKD key finder --- .../0.0.0/app/libraries/snappymail/base32.php | 84 +++++++++++++++++++ .../app/libraries/snappymail/gpg/pgp.php | 5 ++ .../libraries/snappymail/pgp/keyservers.php | 17 +++- 3 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 snappymail/v/0.0.0/app/libraries/snappymail/base32.php diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/base32.php b/snappymail/v/0.0.0/app/libraries/snappymail/base32.php new file mode 100644 index 000000000..d65e4c389 --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/snappymail/base32.php @@ -0,0 +1,84 @@ +chars = $chars; + } + + public function random(int $length): string + { + $secret = ''; + while (0 < $length--) { + $secret .= $this->chars[\random_int(0,31)]; + } + return $secret; + } + + public function encode(string $data, bool $padding = false, int $chunklen = 0, string $end = "\r\n"): string + { + $sl = \is_string($data) ? \strlen($data) : 0; + + $base32 = ''; + $remainder = 0; + $remainderSize = 0; + + for ($i = 0; $i < $sl; ++$i) { + $remainder = ($remainder << 8) | \ord($data[$i]); + $remainderSize += 8; + while ($remainderSize > 4) { + $remainderSize -= 5; + $base32 .= $this->chars[($remainder & (31 << $remainderSize)) >> $remainderSize]; + } + } + + if ($remainderSize > 0) { + // remainderSize < 5: + $base32 .= $this->chars[($remainder << (5 - $remainderSize)) & 31]; + } + + if ($padding) { + $base32 .= \str_repeat('=', (8 - \ceil(($sl % 5) * 8 / 5)) % 8); + } + + return 0 < $chunklen + ? \chunk_split($base32, $chunklen, $end) + : $base32; + } + + public function decode(string $data, bool $strict = false): ?string + { + $data = \strtoupper(\rtrim($data, "=\x20\t\n\r\0\x0B")); + $dataSize = \strlen($data); + $buf = 0; + $bufSize = 0; + $res = ''; + $charMap = \array_flip(\str_split($this->chars)); + for ($i = 0; $i < $dataSize; ++$i) { + $c = $data[$i]; + if (isset($charMap[$c])) { + $buf = ($buf << 5) | $charMap[$c]; + $bufSize += 5; + if ($bufSize > 7) { + $bufSize -= 8; + $res .= \chr(($buf & (0xff << $bufSize)) >> $bufSize); + } + } else if ($strict && false === \strpos(" \r\n\t", $c)) { + \trigger_error('Base32 string contains unexpected char #'.\ord($c)." at offset {$i}"); + return null; + } + } + return $res; + } + + public function verify(string $data): bool + { + return (bool) \preg_match('/^['.\preg_quote($this->chars).' \\r\\n\\t]+=*$/D', $data); + } + +} diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/gpg/pgp.php b/snappymail/v/0.0.0/app/libraries/snappymail/gpg/pgp.php index 650cc4b40..c48b4cda2 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/gpg/pgp.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/gpg/pgp.php @@ -398,6 +398,11 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface } } + /** + * Import remote key from WKD + gpg --auto-key-locate clear,wkd --locate-keys releases@snappymail.eu + */ + public function deleteKey(string $keyId, bool $private): bool { $key = $this->keyInfo($keyId, $private); diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/keyservers.php b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/keyservers.php index c503a3aa7..938aee764 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/keyservers.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/keyservers.php @@ -28,6 +28,7 @@ abstract class Keyservers 'https://pool.sks-keyservers.net', 'https://keys.mailvelope.com', 'https://keyserver.ubuntu.com', + 'hkps://openpgpkeyserver.com', */ ]; @@ -196,10 +197,18 @@ abstract class Keyservers */ } - /** https://wiki.gnupg.org/WKD */ - public static function wkd(string $host, string $keyid) + /** + * https://wiki.gnupg.org/WKD + * gpg --with-wkd-hash --fingerprint releases@snappymail.eu + * gpg --no-armor --export releases@snappymail.eu > i4cdqgcarfjdjnba6y4jnf498asg8c6p + */ + public static function wkd(string $host, string $emailAddress) { /* + $localPart = \explode('@', $emailAddress)[0]; + $b32 = new \SnappyMail\Base32('ybndrfg8ejkmcpqxot1uwisza345h769'); + $keyid = $b32->encode(\sha1($localPart, true)); + "https://{$host}/.well-known/openpgpkey/hu/{$keyid}"; /** https://wiki.gnupg.org/WKD DNS: @@ -208,8 +217,8 @@ abstract class Keyservers https://openpgpkey.example.com/.well-known/openpgpkey/example.com/hu/ else https://example.com/.well-known/openpgpkey/hu/ - An example: https://example.com/.well-known/openpgpkey/hu/it5sewh54rxz33fwmr8u6dy4bbz8itz4 - is the direct method URL for "bernhard.reiter@example.com" + An example: https://snappymail.eu/.well-known/openpgpkey/hu/i4cdqgcarfjdjnba6y4jnf498asg8c6p + is the direct method URL for "releases@snappymail.eu" */ }