Replace library/asn1.php with phpseclib
authorPhilipp <admin@philipp.info>
Sat, 12 Sep 2020 09:57:37 +0000 (11:57 +0200)
committerPhilipp <admin@philipp.info>
Sat, 12 Sep 2020 18:44:36 +0000 (20:44 +0200)
composer.json
composer.lock
library/asn1.php [deleted file]
src/Module/PublicRSAKey.php
src/Protocol/Salmon.php
src/Util/Crypto.php
tests/datasets/crypto/rsa/diaspora-public-pem [new file with mode: 0644]
tests/datasets/crypto/rsa/diaspora-public-rsa-base64 [new file with mode: 0644]
tests/src/Util/CryptoTest.php

index 2d6b465..fad962e 100644 (file)
@@ -63,7 +63,8 @@
                "npm-asset/moment": "^2.24",
                "npm-asset/perfect-scrollbar": "0.6.16",
                "npm-asset/textcomplete": "^0.18.2",
-               "npm-asset/typeahead.js": "^0.11.1"
+               "npm-asset/typeahead.js": "^0.11.1",
+               "phpseclib/phpseclib": "^2.0"
        },
        "repositories": [
                {
index 9f6f78d..ebd434e 100644 (file)
@@ -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": "7d1fe40c28d815b56d0b5cb323860b26",
+    "content-hash": "ffe94190e166cebf80601fc3d6d26be0",
     "packages": [
         {
             "name": "asika/simple-console",
             "homepage": "http://pear.php.net/package/Text_LanguageDetect",
             "time": "2020-05-17T12:19:40+00:00"
         },
+        {
+            "name": "phpseclib/phpseclib",
+            "version": "2.0.29",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpseclib/phpseclib.git",
+                "reference": "497856a8d997f640b4a516062f84228a772a48a8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/497856a8d997f640b4a516062f84228a772a48a8",
+                "reference": "497856a8d997f640b4a516062f84228a772a48a8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phing/phing": "~2.7",
+                "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
+                "squizlabs/php_codesniffer": "~2.0"
+            },
+            "suggest": {
+                "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."
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "phpseclib/bootstrap.php"
+                ],
+                "psr-4": {
+                    "phpseclib\\": "phpseclib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jim Wigginton",
+                    "email": "terrafrost@php.net",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Patrick Monnerat",
+                    "email": "pm@datasphere.ch",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Andreas Fischer",
+                    "email": "bantu@phpbb.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Hans-Jürgen Petrich",
+                    "email": "petrich@tronic-media.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
+            "homepage": "http://phpseclib.sourceforge.net",
+            "keywords": [
+                "BigInteger",
+                "aes",
+                "asn.1",
+                "asn1",
+                "blowfish",
+                "crypto",
+                "cryptography",
+                "encryption",
+                "rsa",
+                "security",
+                "sftp",
+                "signature",
+                "signing",
+                "ssh",
+                "twofish",
+                "x.509",
+                "x509"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/terrafrost",
+                    "type": "github"
+                },
+                {
+                    "url": "https://www.patreon.com/phpseclib",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-09-08T04:24:43+00:00"
+        },
         {
             "name": "pragmarx/google2fa",
             "version": "v5.0.0",
diff --git a/library/asn1.php b/library/asn1.php
deleted file mode 100644 (file)
index cda96b6..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-<?php
-
-// ASN.1 parsing library
-// Attribution: http://www.krisbailey.com
-// license: unknown
-// modified: Mike Macgrivin mike@macgirvin.com 6-oct-2010 to support Salmon auto-discovery
-// modified: Tobias Diekershoff 28-jul-2016 adding an intval in line 162 to make PHP7 happy
-// from openssl public keys
-
-
-class ASN_BASE {
-       public $asnData = null;
-       private $cursor = 0;
-       private $parent = null;
-       
-       public static $ASN_MARKERS = array(
-               'ASN_UNIVERSAL'         => 0x00,
-               'ASN_APPLICATION'       => 0x40,
-               'ASN_CONTEXT'           => 0x80,
-               'ASN_PRIVATE'           => 0xC0,
-
-               'ASN_PRIMITIVE'         => 0x00,
-               'ASN_CONSTRUCTOR'       => 0x20,
-
-               'ASN_LONG_LEN'          => 0x80,
-               'ASN_EXTENSION_ID'      => 0x1F,
-               'ASN_BIT'               => 0x80,
-       );
-       
-       public static $ASN_TYPES = array(
-               1       => 'ASN_BOOLEAN',
-               2       => 'ASN_INTEGER',
-               3       => 'ASN_BIT_STR',
-               4       => 'ASN_OCTET_STR',
-               5       => 'ASN_NULL',
-               6       => 'ASN_OBJECT_ID',
-               9       => 'ASN_REAL',
-               10      => 'ASN_ENUMERATED',
-               13      => 'ASN_RELATIVE_OID',
-               48      => 'ASN_SEQUENCE',
-               49      => 'ASN_SET',
-               19      => 'ASN_PRINT_STR',
-               22      => 'ASN_IA5_STR',
-               23      => 'ASN_UTC_TIME',
-               24      => 'ASN_GENERAL_TIME',
-       );
-
-       function __construct($v = false)
-       {
-               if (false !== $v) {
-                       $this->asnData = $v;
-                       if (is_array($this->asnData)) {
-                               foreach ($this->asnData as $key => $value) {
-                                       if (is_object($value)) {
-                                               $this->asnData[$key]->setParent($this);
-                                       }
-                               }
-                       } else {
-                               if (is_object($this->asnData)) {
-                                       $this->asnData->setParent($this);
-                               }
-                       }
-               }
-       }
-       
-       public function setParent($parent)
-       {
-               if (false !== $parent) {
-                       $this->parent = $parent;
-               }
-       }
-       
-       /**
-        * This function will take the markers and types arrays and
-        * dynamically generate classes that extend this class for each one,
-        * and also define constants for them.
-        */
-       public static function generateSubclasses()
-       {
-               define('ASN_BASE', 0);
-               foreach (self::$ASN_MARKERS as $name => $bit)
-                       self::makeSubclass($name, $bit);
-               foreach (self::$ASN_TYPES as $bit => $name)
-                       self::makeSubclass($name, $bit);
-       }
-       
-       /**
-        * Helper function for generateSubclasses()
-        */
-       public static function makeSubclass($name, $bit)
-       {
-               define($name, $bit);
-               eval("class ".$name." extends ASN_BASE {}");
-       }
-       
-       /**
-        * This function reset's the internal cursor used for value iteration.
-        */
-       public function reset()
-       {
-               $this->cursor = 0;
-       }
-       
-       /**
-        * This function catches calls to get the value for the type, typeName, value, values, and data
-        * from the object.  For type calls we just return the class name or the value of the constant that
-        * is named the same as the class.
-        */
-       public function __get($name)
-       {
-               if ('type' == $name) {
-                       // int flag of the data type
-                       return constant(get_class($this));
-               } elseif ('typeName' == $name) {
-                       // name of the data type
-                       return get_class($this);
-               } elseif ('value' == $name) {
-                       // will always return one value and can be iterated over with:
-                       // while ($v = $obj->value) { ...
-                       // because $this->asnData["invalid key"] will return false
-                       return is_array($this->asnData) ? $this->asnData[$this->cursor++] : $this->asnData;
-               } elseif ('values' == $name) {
-                       // will always return an array
-                       return is_array($this->asnData) ? $this->asnData : array($this->asnData);
-               } elseif ('data' == $name) {
-                       // will always return the raw data
-                       return $this->asnData;
-               }
-       }
-
-       /**
-        * Parse an ASN.1 binary string.
-        * 
-        * This function takes a binary ASN.1 string and parses it into it's respective
-        * pieces and returns it.  It can optionally stop at any depth.
-        *
-        * @param       string  $string         The binary ASN.1 String
-        * @param       int     $level          The current parsing depth level
-        * @param       int     $maxLevel       The max parsing depth level
-        * @return      ASN_BASE        The array representation of the ASN.1 data contained in $string
-        */
-       public static function parseASNString($string=false, $level=1, $maxLevels=false){
-               if (!class_exists('ASN_UNIVERSAL'))
-                       self::generateSubclasses();
-               if ($level>$maxLevels && $maxLevels)
-                       return array(new ASN_BASE($string));
-               $parsed = array();
-               $endLength = strlen($string);
-               $bigLength = $length = $type = $dtype = $p = 0;
-               while ($p<$endLength){
-                       $type = ord($string[$p++]);
-                       $dtype = ($type & 192) >> 6;
-                       if ($type==0){ // if we are type 0, just continue
-                       } else {
-                               $length = ord($string[$p++]);
-                               if (($length & ASN_LONG_LEN)==ASN_LONG_LEN){
-                                       $tempLength = 0;
-                                       for ($x=0; $x<($length & (ASN_LONG_LEN-1)); $x++){
-                                               $tempLength = @ord($string[$p++]) + ($tempLength * 256);
-                                       }
-                                       $length = $tempLength;
-                               }
-                               $data = substr($string, $p, intval($length));
-                               $parsed[] = self::parseASNData($type, $data, $level, $maxLevels);
-                               $p = $p + $length;
-                       }
-               }
-               return $parsed;
-       }
-
-       /**
-        * Parse an ASN.1 field value.
-        * 
-        * This function takes a binary ASN.1 value and parses it according to it's specified type
-        *
-        * @param       int     $type           The type of data being provided
-        * @param       string  $data           The raw binary data string
-        * @param       int     $level          The current parsing depth
-        * @param       int     $maxLevels      The max parsing depth
-        * @return      mixed   The data that was parsed from the raw binary data string
-        */
-       public static function parseASNData($type, $data, $level, $maxLevels){
-               $type = $type%50; // strip out context
-               switch ($type){
-                       default:
-                               return new ASN_BASE($data);
-                       case ASN_BOOLEAN:
-                               return new ASN_BOOLEAN((bool)$data);
-                       case ASN_INTEGER:
-                               return new ASN_INTEGER(strtr(base64_encode($data),'+/','-_'));
-                       case ASN_BIT_STR:
-                               return new ASN_BIT_STR(self::parseASNString($data, $level+1, $maxLevels));
-                       case ASN_OCTET_STR:
-                               return new ASN_OCTET_STR($data);
-                       case ASN_NULL:
-                               return new ASN_NULL(null);
-                       case ASN_REAL:
-                               return new ASN_REAL($data);
-                       case ASN_ENUMERATED:
-                               return new ASN_ENUMERATED(self::parseASNString($data, $level+1, $maxLevels));
-                       case ASN_RELATIVE_OID: // I don't really know how this works and don't have an example :-)
-                                               // so, lets just return it ...
-                               return new ASN_RELATIVE_OID($data);
-                       case ASN_SEQUENCE:
-                               return new ASN_SEQUENCE(self::parseASNString($data, $level+1, $maxLevels));
-                       case ASN_SET:
-                               return new ASN_SET(self::parseASNString($data, $level+1, $maxLevels));
-                       case ASN_PRINT_STR:
-                               return new ASN_PRINT_STR($data);
-                       case ASN_IA5_STR:
-                               return new ASN_IA5_STR($data);
-                       case ASN_UTC_TIME:
-                               return new ASN_UTC_TIME($data);
-                       case ASN_GENERAL_TIME:
-                               return new ASN_GENERAL_TIME($data);
-                       case ASN_OBJECT_ID:
-                               return new ASN_OBJECT_ID(self::parseOID($data));
-               }
-       }
-
-       /**
-        * Parse an ASN.1 OID value.
-        * 
-        * This takes the raw binary string that represents an OID value and parses it into its
-        * dot notation form.  example - 1.2.840.113549.1.1.5
-        * look up OID's here: http://www.oid-info.com/
-        * (the multi-byte OID section can be done in a more efficient way, I will fix it later)
-        *
-        * @param       string  $data           The raw binary data string
-        * @return      string  The OID contained in $data
-        */
-       public static function parseOID($string){
-               $ret = floor(ord($string[0])/40).".";
-               $ret .= (ord($string[0]) % 40);
-               $build = array();
-               $cs = 0;        
-               
-               for ($i=1; $i<strlen($string); $i++){
-                       $v = ord($string[$i]);
-                       if ($v>127){
-                               $build[] = ord($string[$i])-ASN_BIT;
-                       } elseif ($build){
-                               // do the build here for multibyte values
-                               $build[] = ord($string[$i])-ASN_BIT;
-                               // you know, it seems there should be a better way to do this...
-                               $build = array_reverse($build);
-                               $num = 0;
-                               for ($x=0; $x<count($build); $x++){
-                                       $mult = $x==0?1:pow(256, $x);
-                                       if ($x+1==count($build)){
-                                               $value = ((($build[$x] & (ASN_BIT-1)) >> $x)) * $mult;
-                                       } else {
-                                               $value = ((($build[$x] & (ASN_BIT-1)) >> $x) ^ ($build[$x+1] << (7 - $x) & 255)) * $mult;
-                                       }
-                                       $num += $value;
-                               }
-                               $ret .= ".".$num;
-                               $build = array(); // start over
-                       } else {
-                               $ret .= ".".$v;
-                               $build = array();
-                       }
-               }
-               return $ret;
-       }
-       
-       public static function printASN($x, $indent=''){
-               if (is_object($x)) {
-                       echo $indent.$x->typeName."\n";
-                       if (ASN_NULL == $x->type) return;
-                       if (is_array($x->data)) {
-                               while ($d = $x->value) {
-                                       echo self::printASN($d, $indent.'.  ');
-                               }
-                               $x->reset();
-                       } else {
-                               echo self::printASN($x->data, $indent.'.  ');
-                       }
-               } elseif (is_array($x)) {
-                       foreach ($x as $d) {
-                               echo self::printASN($d, $indent);
-                       }
-               } else {
-                       if (preg_match('/[^[:print:]]/', $x))   // if we have non-printable characters that would
-                               $x = base64_encode($x);         // mess up the console, then print the base64 of them...
-                       echo $indent.$x."\n";
-               }
-       }
-
-       
-}
-
index 3d04236..7c46b63 100644 (file)
 
 namespace Friendica\Module;
 
-use ASN_BASE;
 use Friendica\BaseModule;
 use Friendica\DI;
 use Friendica\Model\User;
 use Friendica\Network\HTTPException\BadRequestException;
+use Friendica\Util\Crypto;
+use Friendica\Util\Strings;
+use phpseclib\File\ASN1;
 
 /**
  * prints the public RSA key of a user
@@ -49,18 +51,10 @@ class PublicRSAKey extends BaseModule
                        throw new BadRequestException();
                }
 
-               $lines = explode("\n", $user['spubkey']);
-               unset($lines[0]);
-               unset($lines[count($lines)]);
-
-               $asnString = base64_decode(implode('', $lines));
-               $asnBase = ASN_BASE::parseASNString($asnString);
-
-               $m = $asnBase[0]->asnData[1]->asnData[0]->asnData[0]->asnData;
-               $e = $asnBase[0]->asnData[1]->asnData[0]->asnData[1]->asnData;
+               Crypto::pemToMe($user['spubkey'], $modulus, $exponent);
 
                header('Content-type: application/magic-public-key');
-               echo 'RSA' . '.' . $m . '.' . $e;
+               echo 'RSA' . '.' . Strings::base64UrlEncode($modulus, true) . '.' . Strings::base64UrlEncode($exponent, true);
 
                exit();
        }
index 88c342a..169a4d0 100644 (file)
@@ -229,7 +229,7 @@ class Salmon
         */
        public static function salmonKey($pubkey)
        {
-               Crypto::pemToMe($pubkey, $m, $e);
-               return 'RSA' . '.' . Strings::base64UrlEncode($m, true) . '.' . Strings::base64UrlEncode($e, true);
+               Crypto::pemToMe($pubkey, $modulus, $exponent);
+               return 'RSA' . '.' . Strings::base64UrlEncode($modulus, true) . '.' . Strings::base64UrlEncode($exponent, true);
        }
 }
index 8adacf7..ab66982 100644 (file)
 
 namespace Friendica\Util;
 
-use ASN_BASE;
 use ASNValue;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Core\System;
 use Friendica\DI;
+use phpseclib\Crypt\RSA;
 
 /**
  * Crypto class
@@ -86,27 +86,6 @@ class Crypto
                return $result;
        }
 
-       /**
-        * @param string $Der der formatted string
-        * @return string
-        */
-       private static function DerToRsa($Der)
-       {
-               //Encode:
-               $Der = base64_encode($Der);
-               //Split lines:
-               $lines = str_split($Der, 64);
-               $body = implode("\n", $lines);
-               //Get title:
-               $title = 'RSA PUBLIC KEY';
-               //Add wrapping:
-               $result = "-----BEGIN {$title}-----\n";
-               $result .= $body . "\n";
-               $result .= "-----END {$title}-----\n";
-
-               return $result;
-       }
-
        /**
         * @param string $Modulus        modulo
         * @param string $PublicExponent exponent
@@ -136,26 +115,6 @@ class Crypto
                return $PublicDER;
        }
 
-       /**
-        * @param string $Modulus        modulo
-        * @param string $PublicExponent exponent
-        * @return string
-        */
-       private static function pkcs1Encode($Modulus, $PublicExponent)
-       {
-               //Encode key sequence
-               $modulus = new ASNValue(ASNValue::TAG_INTEGER);
-               $modulus->SetIntBuffer($Modulus);
-               $publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
-               $publicExponent->SetIntBuffer($PublicExponent);
-               $keySequenceItems = [$modulus, $publicExponent];
-               $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
-               $keySequence->SetSequence($keySequenceItems);
-               //Encode bit string
-               $bitStringValue = $keySequence->Encode();
-               return $bitStringValue;
-       }
-
        /**
         * @param string $m modulo
         * @param string $e exponent
@@ -169,79 +128,37 @@ class Crypto
        }
 
        /**
-        * @param string $key key
-        * @param string $m   modulo reference
-        * @param object $e   exponent reference
-        * @return void
-        * @throws \Exception
-        */
-       private static function pubRsaToMe($key, &$m, &$e)
-       {
-               $lines = explode("\n", $key);
-               unset($lines[0]);
-               unset($lines[count($lines)]);
-               $x = base64_decode(implode('', $lines));
-
-               $r = ASN_BASE::parseASNString($x);
-
-               $m = Strings::base64UrlDecode($r[0]->asnData[0]->asnData);
-               $e = Strings::base64UrlDecode($r[0]->asnData[1]->asnData);
-       }
-
-       /**
-        * @param string $key key
-        * @return string
-        * @throws \Exception
+        * Transform RSA public keys to standard PEM output
+        *
+        * @param string $key A RSA public key
+        *
+        * @return string The PEM output of this key
         */
-       public static function rsaToPem($key)
+       public static function rsaToPem(string $key)
        {
-               self::pubRsaToMe($key, $m, $e);
-               return self::meToPem($m, $e);
-       }
+               $publicKey = new RSA();
+               $publicKey->setPublicKey($key);
 
-       /**
-        * @param string $key key
-        * @return string
-        * @throws \Exception
-        */
-       private static function pemToRsa($key)
-       {
-               self::pemToMe($key, $m, $e);
-               return self::meToRsa($m, $e);
+               return $publicKey->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8);
        }
 
        /**
-        * @param string $key key
-        * @param string $m   modulo reference
-        * @param string $e   exponent reference
+        * 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
-        * @throws \Exception
         */
-       public static function pemToMe($key, &$m, &$e)
+       public static function pemToMe(string $key, string &$modulus, string &$exponent)
        {
-               $lines = explode("\n", $key);
-               unset($lines[0]);
-               unset($lines[count($lines)]);
-               $x = base64_decode(implode('', $lines));
-
-               $r = ASN_BASE::parseASNString($x);
-
-               if (isset($r[0])) {
-                       $m = Strings::base64UrlDecode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData);
-                       $e = Strings::base64UrlDecode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData);
-               }
-       }
+               $publicKey = new RSA();
+               $publicKey->loadKey($key);
+               $publicKey->setPublicKey();
 
-       /**
-        * @param string $m modulo
-        * @param string $e exponent
-        * @return string
-        */
-       private static function meToRsa($m, $e)
-       {
-               $der = self::pkcs1Encode($m, $e);
-               $key = self::DerToRsa($der);
-               return $key;
+               $modulus  = $publicKey->modulus->toBytes();
+               $exponent = $publicKey->exponent->toBytes();
        }
 
        /**
@@ -312,42 +229,6 @@ class Crypto
                return openssl_decrypt($data, 'aes-256-cbc', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0"));
        }
 
-       /**
-        * Encrypt a string with 'aes-256-ctr' cipher method.
-        * 
-        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
-        * 
-        * @param string $data
-        * @param string $key   The key used for encryption.
-        * @param string $iv    A non-NULL Initialization Vector.
-        * 
-        * @return string|boolean Encrypted string or false on failure.
-        */
-       private static function encryptAES256CTR($data, $key, $iv)
-       {
-               $key = substr($key, 0, 32);
-               $iv = substr($iv, 0, 16);
-               return openssl_encrypt($data, 'aes-256-ctr', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0"));
-       }
-
-       /**
-        * Decrypt a string with 'aes-256-ctr' cipher method.
-        * 
-        * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
-        * 
-        * @param string $data
-        * @param string $key   The key used for decryption.
-        * @param string $iv    A non-NULL Initialization Vector.
-        * 
-        * @return string|boolean Decrypted string or false on failure.
-        */
-       private static function decryptAES256CTR($data, $key, $iv)
-       {
-               $key = substr($key, 0, 32);
-               $iv = substr($iv, 0, 16);
-               return openssl_decrypt($data, 'aes-256-ctr', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0"));
-       }
-
        /**
         *
         * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php
diff --git a/tests/datasets/crypto/rsa/diaspora-public-pem b/tests/datasets/crypto/rsa/diaspora-public-pem
new file mode 100644 (file)
index 0000000..09dd164
--- /dev/null
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----\r
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDReSjW7O4u4tK+UGKwogyw4Dok\r
+j1Z4f70INc4CTlHk2sngzTa3uMzk1EU+9nYigqMfI1/DYoSCC0ZqikvZVGkrMJj6\r
+khM7orTasR4Av9Sn54rOQaM+raUC3JXd9AdkdXx1IBC71cAXVqIg/ERCrrUpxDxc\r
+E6VXs4mFWpDHJ4q01QIDAQAB\r
+-----END PUBLIC KEY-----
\ No newline at end of file
diff --git a/tests/datasets/crypto/rsa/diaspora-public-rsa-base64 b/tests/datasets/crypto/rsa/diaspora-public-rsa-base64
new file mode 100644 (file)
index 0000000..ba835a4
--- /dev/null
@@ -0,0 +1 @@
+LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tDQpNSUdKQW9HQkFORjVLTmJzN2k3aTByNVFZckNpRExEZ09pU1BWbmgvdlFnMXpnSk9VZVRheWVETk5yZTR6T1RVDQpSVDcyZGlLQ294OGpYOE5paElJTFJtcUtTOWxVYVNzd21QcVNFenVpdE5xeEhnQy8xS2ZuaXM1Qm96NnRwUUxjDQpsZDMwQjJSMWZIVWdFTHZWd0JkV29pRDhSRUt1dFNuRVBGd1RwVmV6aVlWYWtNY25pclRWQWdNQkFBRT0NCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0
\ No newline at end of file
index 9f23221..5130533 100644 (file)
@@ -21,6 +21,8 @@
  */
 namespace Friendica\Util;
 
+use phpseclib\Crypt\RSA;
+use phpseclib\Math\BigInteger;
 use PHPUnit\Framework\TestCase;
 
 class CryptoTest extends TestCase
@@ -32,7 +34,7 @@ class CryptoTest extends TestCase
        private function assertRandomInt($min, $max)
        {
                global $phpMock;
-               $phpMock['random_int'] = function($mMin, $mMax) use ($min, $max) {
+               $phpMock['random_int'] = function ($mMin, $mMax) use ($min, $max) {
                        $this->assertEquals($min, $mMin);
                        $this->assertEquals($max, $mMax);
                        return 1;
@@ -51,6 +53,50 @@ class CryptoTest extends TestCase
                $this->assertEquals(8, strlen($test));
                $this->assertEquals(11111111, $test);
        }
+
+       public function dataRsa()
+       {
+               return [
+                       'diaspora' => [
+                               'key' => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/diaspora-public-rsa-base64'),
+                               'expected' => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/diaspora-public-pem'),
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider dataRsa
+        */
+       public function testPubRsaToMe(string $key, string $expected)
+       {
+               $this->assertEquals($expected, Crypto::rsaToPem(base64_decode($key)));
+       }
+
+
+       public function datePem()
+       {
+               return [
+                       'diaspora' => [
+                               'key' => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/diaspora-public-pem'),
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider datePem
+        */
+       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)
+                                                         ]);
+
+               $this->assertEquals($expectedRSA->getPublicKey(), $key);
+       }
 }
 
 /**