From 55640eec873e7f274824c6ed904672ebd75a7691 Mon Sep 17 00:00:00 2001
From: Hypolite Petovan <hypolite@mrpetovan.com>
Date: Wed, 23 Nov 2022 13:45:58 -0500
Subject: [PATCH] [Composer] Upgrade to phpseclib version 3

- Create custom Key file format for Salmon Magic key
- Remove obsolete pemToME and MEtoPem Crypto methods
- Remove unused newECKeypair Crypto method
- Switch to constant-time Base64 encode/decode in Base64Url Strings methods
---
 composer.json                                 |   2 +-
 composer.lock                                 |  26 ++---
 src/Module/OStatus/Salmon.php                 |   9 +-
 src/Module/PublicRSAKey.php                   |  13 +--
 src/Network/Probe.php                         |   9 +-
 src/Protocol/Salmon.php                       |  18 ++-
 src/Protocol/Salmon/Format/Magic.php          |  77 +++++++++++++
 src/Util/Crypto.php                           |  89 +--------------
 src/Util/Strings.php                          |  31 ++----
 tests/datasets/crypto/rsa/salmon-public-magic |   1 +
 tests/datasets/crypto/rsa/salmon-public-pem   |   4 +
 tests/src/Protocol/SalmonTest.php             | 105 ++++++++++++++++++
 tests/src/Util/CryptoTest.php                 |  30 +----
 13 files changed, 241 insertions(+), 173 deletions(-)
 create mode 100644 src/Protocol/Salmon/Format/Magic.php
 create mode 100644 tests/datasets/crypto/rsa/salmon-public-magic
 create mode 100644 tests/datasets/crypto/rsa/salmon-public-pem
 create mode 100644 tests/src/Protocol/SalmonTest.php

diff --git a/composer.json b/composer.json
index 34c0f62582..d0fc5619b9 100644
--- a/composer.json
+++ b/composer.json
@@ -45,7 +45,7 @@
 		"paragonie/hidden-string": "^1.0",
 		"patrickschur/language-detection": "^5.0.0",
 		"pear/console_table": "^1.3",
-		"phpseclib/phpseclib": "^2.0",
+		"phpseclib/phpseclib": "^3.0",
 		"pragmarx/google2fa": "^5.0",
 		"pragmarx/recovery": "^0.2",
 		"psr/container": "^1.0",
diff --git a/composer.lock b/composer.lock
index 786880fab8..1805c9d21a 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": "e8626dc6957dff9cc783daad10cfc26f",
+    "content-hash": "2e082bac083ca61cc0c22f7055d690bf",
     "packages": [
         {
             "name": "asika/simple-console",
@@ -2952,32 +2952,32 @@
         },
         {
             "name": "phpseclib/phpseclib",
-            "version": "2.0.38",
+            "version": "3.0.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpseclib/phpseclib.git",
-                "reference": "b03536539f43a4f9aa33c4f0b2f3a1c752088fcd"
+                "reference": "dbc2307d5c69aeb22db136c52e91130d7f2ca761"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/b03536539f43a4f9aa33c4f0b2f3a1c752088fcd",
-                "reference": "b03536539f43a4f9aa33c4f0b2f3a1c752088fcd",
+                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/dbc2307d5c69aeb22db136c52e91130d7f2ca761",
+                "reference": "dbc2307d5c69aeb22db136c52e91130d7f2ca761",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
+                "paragonie/constant_time_encoding": "^1|^2",
+                "paragonie/random_compat": "^1.4|^2.0|^9.99.99",
+                "php": ">=5.6.1"
             },
             "require-dev": {
-                "phing/phing": "~2.7",
-                "phpunit/phpunit": "^4.8.35|^5.7|^6.0|^9.4",
-                "squizlabs/php_codesniffer": "~2.0"
+                "phpunit/phpunit": "*"
             },
             "suggest": {
+                "ext-dom": "Install the DOM extension to load XML formatted public keys.",
                 "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
                 "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
                 "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
-                "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.",
-                "ext-xml": "Install the XML extension to load XML formatted public keys."
+                "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
             },
             "type": "library",
             "autoload": {
@@ -2985,7 +2985,7 @@
                     "phpseclib/bootstrap.php"
                 ],
                 "psr-4": {
-                    "phpseclib\\": "phpseclib/"
+                    "phpseclib3\\": "phpseclib/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -3054,7 +3054,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-09-02T17:04:26+00:00"
+            "time": "2022-10-24T10:51:50+00:00"
         },
         {
             "name": "pragmarx/google2fa",
diff --git a/src/Module/OStatus/Salmon.php b/src/Module/OStatus/Salmon.php
index f674f9300b..0d393afcce 100644
--- a/src/Module/OStatus/Salmon.php
+++ b/src/Module/OStatus/Salmon.php
@@ -142,14 +142,9 @@ class Salmon extends \Friendica\BaseModule
 			throw new HTTPException\BadRequestException();
 		}
 
-		$key_info = explode('.', $key);
+		$this->logger->info('Key details', ['info' => $key]);
 
-		$m = Strings::base64UrlDecode($key_info[1]);
-		$e = Strings::base64UrlDecode($key_info[2]);
-
-		$this->logger->info('Key details', ['info' => $key_info]);
-
-		$pubkey = Crypto::meToPem($m, $e);
+		$pubkey = SalmonProtocol::magicKeyToPem($key);
 
 		// We should have everything we need now. Let's see if it verifies.
 
diff --git a/src/Module/PublicRSAKey.php b/src/Module/PublicRSAKey.php
index 523ab174fb..fb1eeeb278 100644
--- a/src/Module/PublicRSAKey.php
+++ b/src/Module/PublicRSAKey.php
@@ -23,11 +23,9 @@ namespace Friendica\Module;
 
 use Friendica\BaseModule;
 use Friendica\Core\System;
-use Friendica\DI;
 use Friendica\Model\User;
 use Friendica\Network\HTTPException\BadRequestException;
-use Friendica\Util\Crypto;
-use Friendica\Util\Strings;
+use Friendica\Protocol\Salmon;
 
 /**
  * prints the public RSA key of a user
@@ -47,9 +45,10 @@ class PublicRSAKey extends BaseModule
 			throw new BadRequestException();
 		}
 
-		Crypto::pemToMe($user['spubkey'], $modulus, $exponent);
-
-		$content = 'RSA' . '.' . Strings::base64UrlEncode($modulus, true) . '.' . Strings::base64UrlEncode($exponent, true);
-		System::httpExit($content, Response::TYPE_BLANK, 'application/magic-public-key');
+		System::httpExit(
+			Salmon::salmonKey($user['spubkey']),
+			Response::TYPE_BLANK,
+			'application/magic-public-key'
+		);
 	}
 }
diff --git a/src/Network/Probe.php b/src/Network/Probe.php
index fc7113dbda..5c188f2522 100644
--- a/src/Network/Probe.php
+++ b/src/Network/Probe.php
@@ -40,6 +40,7 @@ use Friendica\Protocol\ActivityNamespace;
 use Friendica\Protocol\ActivityPub;
 use Friendica\Protocol\Email;
 use Friendica\Protocol\Feed;
+use Friendica\Protocol\Salmon;
 use Friendica\Util\Crypto;
 use Friendica\Util\DateTimeFormat;
 use Friendica\Util\Network;
@@ -1512,12 +1513,10 @@ class Probe
 						$pubkey = $curlResult->getBody();
 					}
 
-					$key = explode('.', $pubkey);
+					try {
+						$data['pubkey'] = Salmon::magicKeyToPem($pubkey);
+					} catch (\Throwable $e) {
 
-					if (sizeof($key) >= 3) {
-						$m = Strings::base64UrlDecode($key[1]);
-						$e = Strings::base64UrlDecode($key[2]);
-						$data['pubkey'] = Crypto::meToPem($m, $e);
 					}
 				}
 			}
diff --git a/src/Protocol/Salmon.php b/src/Protocol/Salmon.php
index b1bdb67e1d..7e91b0e3e0 100644
--- a/src/Protocol/Salmon.php
+++ b/src/Protocol/Salmon.php
@@ -25,9 +25,11 @@ use Friendica\Core\Logger;
 use Friendica\DI;
 use Friendica\Network\HTTPClient\Client\HttpClientAccept;
 use Friendica\Network\Probe;
+use Friendica\Protocol\Salmon\Format\Magic;
 use Friendica\Util\Crypto;
 use Friendica\Util\Strings;
 use Friendica\Util\XML;
+use phpseclib3\Crypt\PublicKeyLoader;
 
 /**
  * Salmon Protocol class
@@ -243,7 +245,19 @@ class Salmon
 	 */
 	public static function salmonKey(string $pubkey): string
 	{
-		Crypto::pemToMe($pubkey, $modulus, $exponent);
-		return 'RSA' . '.' . Strings::base64UrlEncode($modulus, true) . '.' . Strings::base64UrlEncode($exponent, true);
+		\phpseclib3\Crypt\RSA::addFileFormat(Magic::class);
+
+		return PublicKeyLoader::load($pubkey)->toString('Magic');
+	}
+
+	/**
+	 * @param string $magic Magic key format starting with "RSA."
+	 * @return string
+	 */
+	public static function magicKeyToPem(string $magic): string
+	{
+		\phpseclib3\Crypt\RSA::addFileFormat(Magic::class);
+
+		return (string) PublicKeyLoader::load($magic);
 	}
 }
diff --git a/src/Protocol/Salmon/Format/Magic.php b/src/Protocol/Salmon/Format/Magic.php
new file mode 100644
index 0000000000..a94ae6bd61
--- /dev/null
+++ b/src/Protocol/Salmon/Format/Magic.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Protocol\Salmon\Format;
+
+use Friendica\Util\Strings;
+use phpseclib3\Math\BigInteger;
+
+/**
+ * This custom public RSA key format class is meant to be used with the \phpseclib3\Crypto\RSA::addFileFormat method.
+ *
+ * It handles Salmon's specific magic key string starting with "RSA." and which MIME type is application/magic-key or
+ * application/magic-public-key
+ *
+ * @see https://web.archive.org/web/20160506073138/http://salmon-protocol.googlecode.com:80/svn/trunk/draft-panzer-magicsig-01.html#anchor13
+ */
+class Magic
+{
+	public static function load($key, $password = ''): array
+	{
+		if (!is_string($key)) {
+			throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
+		}
+
+		$key_info = explode('.', $key);
+
+		if (count($key_info) !== 3) {
+			throw new \UnexpectedValueException('Key should have three components separated by periods');
+		}
+
+		if ($key_info[0] !== 'RSA') {
+			throw new \UnexpectedValueException('Key first component should be "RSA"');
+		}
+
+		if (preg_match('#[+/]#', $key_info[1])
+			|| preg_match('#[+/]#', $key_info[1])
+		) {
+			throw new \UnexpectedValueException('Wrong encoding, expecting Base64URLencoding');
+		}
+
+		$m = Strings::base64UrlDecode($key_info[1]);
+		$e = Strings::base64UrlDecode($key_info[2]);
+
+		if (!$m || !$e) {
+			throw new \UnexpectedValueException('Base64 decoding produced an error');
+		}
+
+		return [
+			'modulus'        => new BigInteger($m, 256),
+			'publicExponent' => new BigInteger($e, 256),
+			'isPublicKey'    => true,
+		];
+	}
+
+	public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = []): string
+	{
+		return 'RSA.' . Strings::base64UrlEncode($n->toBytes(), true) . '.' . Strings::base64UrlEncode($e->toBytes(), true);
+	}
+}
diff --git a/src/Util/Crypto.php b/src/Util/Crypto.php
index d983202c0c..a5ca5e517b 100644
--- a/src/Util/Crypto.php
+++ b/src/Util/Crypto.php
@@ -21,14 +21,11 @@
 
 namespace Friendica\Util;
 
-use Exception;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Core\System;
 use Friendica\DI;
-use ParagonIE\ConstantTime\Base64UrlSafe;
-use phpseclib\Crypt\RSA;
-use phpseclib\Math\BigInteger;
+use phpseclib3\Crypt\PublicKeyLoader;
 
 /**
  * Crypto class
@@ -66,22 +63,6 @@ class Crypto
 		return openssl_verify($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
 	}
 
-	/**
-	/**
-	 * @param string $m modulo
-	 * @param string $e exponent
-	 * @return string
-	 */
-	public static function meToPem($m, $e)
-	{
-		$rsa = new RSA();
-		$rsa->loadKey([
-			'e' => new BigInteger($e, 256),
-			'n' => new BigInteger($m, 256)
-		]);
-		return $rsa->getPublicKey();
-	}
-
 	/**
 	 * Transform RSA public keys to standard PEM output
 	 *
@@ -91,29 +72,7 @@ class Crypto
 	 */
 	public static function rsaToPem(string $key)
 	{
-		$rsa = new RSA();
-		$rsa->setPublicKey($key);
-
-		return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8);
-	}
-
-	/**
-	 * Extracts the modulo and exponent reference from a public PEM key
-	 *
-	 * @param string $key      public PEM key
-	 * @param string $modulus  (ref) modulo reference
-	 * @param string $exponent (ref) exponent reference
-	 *
-	 * @return void
-	 */
-	public static function pemToMe(string $key, &$modulus, &$exponent)
-	{
-		$rsa = new RSA();
-		$rsa->loadKey($key);
-		$rsa->setPublicKey();
-
-		$modulus  = $rsa->modulus->toBytes();
-		$exponent = $rsa->exponent->toBytes();
+		return (string)PublicKeyLoader::load($key);
 	}
 
 	/**
@@ -152,50 +111,6 @@ class Crypto
 		return $response;
 	}
 
-	/**
-	 * Create a new elliptic curve key pair
-	 *
-	 * @return array with the elements "prvkey", "pubkey", "vapid-public" and "vapid-private"
-	 */
-	public static function newECKeypair()
-	{
-		$openssl_options = [
-			'curve_name'       => 'prime256v1',
-			'private_key_type' => OPENSSL_KEYTYPE_EC
-		];
-
-		$conf = DI::config()->get('system', 'openssl_conf_file');
-		if ($conf) {
-			$openssl_options['config'] = $conf;
-		}
-		$result = openssl_pkey_new($openssl_options);
-
-		if (empty($result)) {
-			throw new Exception('Key creation failed');
-		}
-
-		$response = ['prvkey' => '', 'pubkey' => ''];
-
-		// Get private key
-		openssl_pkey_export($result, $response['prvkey']);
-
-		// Get public key
-		$pkey = openssl_pkey_get_details($result);
-		$response['pubkey'] = $pkey['key'];
-
-		// Create VAPID keys
-		// @see https://github.com/web-push-libs/web-push-php/blob/256a18b2a2411469c94943725fb6eccb9681bd75/src/Utils.php#L60-L62
-		$hexString = '04';
-		$hexString .= str_pad(bin2hex($pkey['ec']['x']), 64, '0', STR_PAD_LEFT);
-		$hexString .= str_pad(bin2hex($pkey['ec']['y']), 64, '0', STR_PAD_LEFT);
-		$response['vapid-public'] = Base64UrlSafe::encode(hex2bin($hexString));
-
-		// @see https://github.com/web-push-libs/web-push-php/blob/256a18b2a2411469c94943725fb6eccb9681bd75/src/VAPID.php
-		$response['vapid-private'] = Base64UrlSafe::encode(hex2bin(str_pad(bin2hex($pkey['ec']['d']), 64, '0', STR_PAD_LEFT)));
-
-		return $response;
-	}
-
 	/**
 	 * Encrypt a string with 'aes-256-cbc' cipher method.
 	 *
diff --git a/src/Util/Strings.php b/src/Util/Strings.php
index 84a8b6727a..565c9bbb03 100644
--- a/src/Util/Strings.php
+++ b/src/Util/Strings.php
@@ -23,6 +23,7 @@ namespace Friendica\Util;
 
 use Friendica\Content\ContactSelector;
 use Friendica\Core\Logger;
+use ParagonIE\ConstantTime\Base64;
 
 /**
  * This class handles string functions
@@ -245,16 +246,17 @@ class Strings
 	 * @param string $s					URL to encode
 	 * @param boolean $strip_padding	Optional. Default false
 	 * @return string	Encoded URL
+	 * @see https://web.archive.org/web/20160506073138/http://salmon-protocol.googlecode.com:80/svn/trunk/draft-panzer-magicsig-01.html#params
 	 */
 	public static function base64UrlEncode(string $s, bool $strip_padding = false): string
 	{
-		$s = strtr(base64_encode($s), '+/', '-_');
-
 		if ($strip_padding) {
-			$s = str_replace('=', '', $s);
+			$s = Base64::encodeUnpadded($s);
+		} else {
+			$s = Base64::encode($s);
 		}
 
-		return $s;
+		return strtr($s, '+/', '-_');
 	}
 
 	/**
@@ -263,26 +265,11 @@ class Strings
 	 * @param string $s URL to decode
 	 * @return string	Decoded URL
 	 * @throws \Exception
+	 * @see https://web.archive.org/web/20160506073138/http://salmon-protocol.googlecode.com:80/svn/trunk/draft-panzer-magicsig-01.html#params
 	 */
 	public static function base64UrlDecode(string $s): string
 	{
-		/*
-		*  // Placeholder for new rev of salmon which strips base64 padding.
-		*  // PHP base64_decode handles the un-padded input without requiring this step
-		*  // Uncomment if you find you need it.
-		*
-		*	$l = strlen($s);
-		*	if (!strpos($s,'=')) {
-		*		$m = $l % 4;
-		*		if ($m == 2)
-		*			$s .= '==';
-		*		if ($m == 3)
-		*			$s .= '=';
-		*	}
-		*
-		*/
-
-		return base64_decode(strtr($s, '-_', '+/'));
+		return Base64::decode(strtr($s, '-_', '+/'));
 	}
 
 	/**
@@ -515,4 +502,4 @@ class Strings
 
 		return $text;
 	}
-}
+}
\ No newline at end of file
diff --git a/tests/datasets/crypto/rsa/salmon-public-magic b/tests/datasets/crypto/rsa/salmon-public-magic
new file mode 100644
index 0000000000..2e38237049
--- /dev/null
+++ b/tests/datasets/crypto/rsa/salmon-public-magic
@@ -0,0 +1 @@
+RSA.tvsoBZbLUvqWs-0d8C5hVQLjLCjjxyZb17Rm8_9FDqBYUigBSFDcJCzG27FM-zuddwpgJB0vDuPKQnt59kKRsw.AQAB
\ No newline at end of file
diff --git a/tests/datasets/crypto/rsa/salmon-public-pem b/tests/datasets/crypto/rsa/salmon-public-pem
new file mode 100644
index 0000000000..1163959859
--- /dev/null
+++ b/tests/datasets/crypto/rsa/salmon-public-pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALb7KAWWy1L6lrPtHfAuYVUC4ywo48cm
+W9e0ZvP/RQ6gWFIoAUhQ3CQsxtuxTPs7nXcKYCQdLw7jykJ7efZCkbMCAwEAAQ==
+-----END PUBLIC KEY-----
\ No newline at end of file
diff --git a/tests/src/Protocol/SalmonTest.php b/tests/src/Protocol/SalmonTest.php
new file mode 100644
index 0000000000..f0c16ca8c3
--- /dev/null
+++ b/tests/src/Protocol/SalmonTest.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Protocol;
+
+use Friendica\Protocol\Salmon;
+
+class SalmonTest extends \PHPUnit\Framework\TestCase
+{
+	public function dataMagic(): array
+	{
+		return [
+			'salmon' => [
+				'magic' => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/salmon-public-magic'),
+				'pem'   => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/salmon-public-pem'),
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider dataMagic
+	 *
+	 * @param $magic
+	 * @param $pem
+	 * @return void
+	 * @throws \Exception
+	 */
+	public function testSalmonKey($magic, $pem)
+	{
+		$this->assertEquals($magic, Salmon::salmonKey($pem));
+	}
+
+	/**
+	 * @dataProvider dataMagic
+	 *
+	 * @param $magic
+	 * @param $pem
+	 * @return void
+	 */
+	public function testMagicKeyToPem($magic, $pem)
+	{
+		$this->assertEquals($pem, Salmon::magicKeyToPem($magic));
+	}
+
+	public function dataMagicFailure(): array
+	{
+		return [
+			'empty string' => [
+				'magic' => '',
+			],
+			'Missing algo' => [
+				'magic' => 'tvsoBZbLUvqWs-0d8C5hVQLjLCjjxyZb17Rm8_9FDqBYUigBSFDcJCzG27FM-zuddwpgJB0vDuPKQnt59kKRsw.AQAB',
+			],
+			'Missing modulus' => [
+				'magic' => 'RSA.AQAB',
+			],
+			'Missing exponent' => [
+				'magic' => 'RSA.tvsoBZbLUvqWs-0d8C5hVQLjLCjjxyZb17Rm8_9FDqBYUigBSFDcJCzG27FM-zuddwpgJB0vDuPKQnt59kKRsw',
+			],
+			'Missing key parts' => [
+				'magic' => 'RSA.',
+			],
+			'Too many parts' => [
+				'magic' => 'RSA.tvsoBZbLUvqWs-0d8C5hVQLjLCjjxyZb17Rm8_9FDqBYUigBSFDcJCzG27FM-zuddwpgJB0vDuPKQnt59kKRsw.AQAB.AQAB',
+			],
+			'Wrong encoding' => [
+				'magic' => 'RSA.tvsoBZbLUvqWs-0d8C5hVQLjLCjjxyZb17Rm8/9FDqBYUigBSFDcJCzG27FM+zuddwpgJB0vDuPKQnt59kKRsw.AQAB',
+			],
+			'Wrong algo' => [
+				'magic' => 'ECDSA.tvsoBZbLUvqWs-0d8C5hVQLjLCjjxyZb17Rm8_9FDqBYUigBSFDcJCzG27FM-zuddwpgJB0vDuPKQnt59kKRsw.AQAB',
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider dataMagicFailure
+	 *
+	 * @param $magic
+	 * @return void
+	 */
+	public function testMagicKeyToPemFailure($magic)
+	{
+		$this->expectException(\Throwable::class);
+
+		Salmon::magicKeyToPem($magic);
+	}
+}
diff --git a/tests/src/Util/CryptoTest.php b/tests/src/Util/CryptoTest.php
index 8be5bbcc87..142a1af6e3 100644
--- a/tests/src/Util/CryptoTest.php
+++ b/tests/src/Util/CryptoTest.php
@@ -65,7 +65,7 @@ class CryptoTest extends TestCase
 		self::assertEquals(11111111, $test);
 	}
 
-	public function dataRsa()
+	public function dataRsa(): array
 	{
 		return [
 			'diaspora' => [
@@ -92,34 +92,6 @@ class CryptoTest extends TestCase
 			],
 		];
 	}
-
-	/**
-	 * @dataProvider dataPEM
-	 */
-	public function testPemToMe(string $key)
-	{
-		Crypto::pemToMe($key, $m, $e);
-
-		$expectedRSA = new RSA();
-		$expectedRSA->loadKey([
-			'e' => new BigInteger($e, 256),
-			'n' => new BigInteger($m, 256)
-		]);
-
-		self::assertEquals($expectedRSA->getPublicKey(), $key);
-	}
-
-	/**
-	 * @dataProvider dataPEM
-	 */
-	public function testMeToPem(string $key)
-	{
-		Crypto::pemToMe($key, $m, $e);
-
-		$checkKey = Crypto::meToPem($m, $e);
-
-		self::assertEquals($key, $checkKey);
-	}
 }
 
 /**
-- 
2.39.5