From 9e6bf793805e6c8ded23b91b1a30a0a118a45a46 Mon Sep 17 00:00:00 2001 From: Adam Magness Date: Sat, 30 Dec 2017 11:51:49 -0500 Subject: [PATCH] Crypto to src move Crypto to src and Friendica\Util namespace --- include/crypto.php | 172 ------------------------- include/items.php | 1 - mod/dfrn_confirm.php | 5 +- mod/fetch.php | 2 - mod/hostxrd.php | 22 ++-- mod/item.php | 1 - mod/receive.php | 2 - mod/salmon.php | 10 +- mod/xrd.php | 24 ++-- src/Model/User.php | 6 +- src/Network/Probe.php | 10 +- src/Protocol/DFRN.php | 2 +- src/Protocol/Diaspora.php | 19 +-- src/Protocol/Salmon.php | 11 +- src/Util/Crypto.php | 260 ++++++++++++++++++++++++++++++++++++++ 15 files changed, 317 insertions(+), 230 deletions(-) delete mode 100644 include/crypto.php create mode 100644 src/Util/Crypto.php diff --git a/include/crypto.php b/include/crypto.php deleted file mode 100644 index dfc44c179..000000000 --- a/include/crypto.php +++ /dev/null @@ -1,172 +0,0 @@ -SetIntBuffer($Modulus); - $publicExponent = new ASNValue(ASNValue::TAG_INTEGER); - $publicExponent->SetIntBuffer($PublicExponent); - $keySequenceItems = array($modulus, $publicExponent); - $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE); - $keySequence->SetSequence($keySequenceItems); - //Encode bit string - $bitStringValue = $keySequence->Encode(); - $bitStringValue = chr(0x00) . $bitStringValue; //Add unused bits byte - $bitString = new ASNValue(ASNValue::TAG_BITSTRING); - $bitString->Value = $bitStringValue; - //Encode body - $bodyValue = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00" . $bitString->Encode(); - $body = new ASNValue(ASNValue::TAG_SEQUENCE); - $body->Value = $bodyValue; - //Get DER encoded public key: - $PublicDER = $body->Encode(); - return $PublicDER; -} - -function pkcs1_encode($Modulus, $PublicExponent) { - //Encode key sequence - $modulus = new ASNValue(ASNValue::TAG_INTEGER); - $modulus->SetIntBuffer($Modulus); - $publicExponent = new ASNValue(ASNValue::TAG_INTEGER); - $publicExponent->SetIntBuffer($PublicExponent); - $keySequenceItems = array($modulus, $publicExponent); - $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE); - $keySequence->SetSequence($keySequenceItems); - //Encode bit string - $bitStringValue = $keySequence->Encode(); - return $bitStringValue; -} - -function metopem($m, $e) { - $der = pkcs8_encode($m, $e); - $key = DerToPem($der, false); - return $key; -} - -function pubrsatome($key, &$m, &$e) -{ - require_once 'library/asn1.php'; - - $lines = explode("\n", $key); - unset($lines[0]); - unset($lines[count($lines)]); - $x = base64_decode(implode('', $lines)); - - $r = ASN_BASE::parseASNString($x); - - $m = base64url_decode($r[0]->asnData[0]->asnData); - $e = base64url_decode($r[0]->asnData[1]->asnData); -} - - -function rsatopem($key) { - pubrsatome($key, $m, $e); - return metopem($m, $e); -} - -function pemtorsa($key) { - pemtome($key, $m, $e); - return metorsa($m, $e); -} - -function pemtome($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 = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData); - $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData); -} - -function metorsa($m, $e) { - $der = pkcs1_encode($m, $e); - $key = DerToRsa($der); - return $key; -} - -function salmon_key($pubkey) { - pemtome($pubkey, $m, $e); - return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true) ; -} - -function new_keypair($bits) { - $openssl_options = array( - 'digest_alg' => 'sha1', - 'private_key_bits' => $bits, - 'encrypt_key' => false - ); - - $conf = Config::get('system', 'openssl_conf_file'); - if ($conf) { - $openssl_options['config'] = $conf; - } - $result = openssl_pkey_new($openssl_options); - - if (empty($result)) { - logger('new_keypair: failed'); - return false; - } - - // Get private key - $response = array('prvkey' => '', 'pubkey' => ''); - - openssl_pkey_export($result, $response['prvkey']); - - // Get public key - $pkey = openssl_pkey_get_details($result); - $response['pubkey'] = $pkey["key"]; - - return $response; -} diff --git a/include/items.php b/include/items.php index 275052c1f..a3f3c823b 100644 --- a/include/items.php +++ b/include/items.php @@ -21,7 +21,6 @@ use Friendica\Protocol\Feed; require_once 'include/bbcode.php'; require_once 'include/oembed.php'; -require_once 'include/crypto.php'; require_once 'include/tags.php'; require_once 'include/files.php'; require_once 'include/text.php'; diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php index 112ee34ab..a5f5f1bd3 100644 --- a/mod/dfrn_confirm.php +++ b/mod/dfrn_confirm.php @@ -29,6 +29,7 @@ use Friendica\Model\Group; use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Protocol\Diaspora; +use Friendica\Util\Crypto; require_once 'include/enotify.php'; @@ -162,9 +163,7 @@ function dfrn_confirm_post(App $a, $handsfree = null) { * worried about key leakage than anybody cracking it. * */ - require_once 'include/crypto.php'; - - $res = new_keypair(4096); + $res = Crypto::newKeypair(4096); $private_key = $res['prvkey']; diff --git a/mod/fetch.php b/mod/fetch.php index 68f6acc91..c097ee4c4 100644 --- a/mod/fetch.php +++ b/mod/fetch.php @@ -8,8 +8,6 @@ use Friendica\Core\System; use Friendica\Protocol\Diaspora; use Friendica\Util\XML; -require_once "include/crypto.php"; - function fetch_init(App $a) { diff --git a/mod/hostxrd.php b/mod/hostxrd.php index 0403945ef..a38d3ab61 100644 --- a/mod/hostxrd.php +++ b/mod/hostxrd.php @@ -1,18 +1,20 @@ $a->get_hostname(), '$zroot' => System::baseUrl(), '$domain' => System::baseUrl(), - '$bigkey' => salmon_key(Config::get('system','site_pubkey')), - )); - exit(); + '$bigkey' => Crypto::salmonKey(Config::get('system', 'site_pubkey'))) + ); + exit(); } diff --git a/mod/item.php b/mod/item.php index 13877fb35..1faef9601 100644 --- a/mod/item.php +++ b/mod/item.php @@ -29,7 +29,6 @@ use Friendica\Protocol\Diaspora; use Friendica\Protocol\Email; use Friendica\Util\Emailer; -require_once 'include/crypto.php'; require_once 'include/enotify.php'; require_once 'include/tags.php'; require_once 'include/files.php'; diff --git a/mod/receive.php b/mod/receive.php index 467a0d00a..fcc898a0c 100644 --- a/mod/receive.php +++ b/mod/receive.php @@ -9,8 +9,6 @@ use Friendica\Core\Config; use Friendica\Database\DBM; use Friendica\Protocol\Diaspora; -require_once 'include/crypto.php'; - /** * @param object $a App * @return void diff --git a/mod/salmon.php b/mod/salmon.php index 4d8b130f9..bd08431a4 100644 --- a/mod/salmon.php +++ b/mod/salmon.php @@ -7,8 +7,8 @@ use Friendica\Core\PConfig; use Friendica\Database\DBM; use Friendica\Protocol\OStatus; use Friendica\Protocol\Salmon; +use Friendica\Util\Crypto; -require_once 'include/crypto.php'; require_once 'include/items.php'; require_once 'include/follow.php'; @@ -117,23 +117,23 @@ function salmon_post(App $a) { logger('mod-salmon: key details: ' . print_r($key_info,true), LOGGER_DEBUG); - $pubkey = metopem($m,$e); + $pubkey = Crypto::meToPem($m, $e); // We should have everything we need now. Let's see if it verifies. // Try GNU Social format - $verify = rsa_verify($signed_data, $signature, $pubkey); + $verify = Crypto::rsaVerify($signed_data, $signature, $pubkey); $mode = 1; if (! $verify) { logger('mod-salmon: message did not verify using protocol. Trying compliant format.'); - $verify = rsa_verify($compliant_format, $signature, $pubkey); + $verify = Crypto::rsaVerify($compliant_format, $signature, $pubkey); $mode = 2; } if (! $verify) { logger('mod-salmon: message did not verify using padding. Trying old statusnet format.'); - $verify = rsa_verify($stnet_signed_data, $signature, $pubkey); + $verify = Crypto::rsaVerify($stnet_signed_data, $signature, $pubkey); $mode = 3; } diff --git a/mod/xrd.php b/mod/xrd.php index 49fdde254..599ee3794 100644 --- a/mod/xrd.php +++ b/mod/xrd.php @@ -1,12 +1,14 @@ argv[0] == 'xrd') { $uri = urldecode(notags(trim($_GET['uri']))); if ($_SERVER['HTTP_ACCEPT'] == 'application/jrd+json') { @@ -54,8 +56,9 @@ function xrd_init(App $a) { } } -function xrd_json($a, $uri, $alias, $profile_url, $r) { - $salmon_key = salmon_key($r['spubkey']); +function xrd_json($a, $uri, $alias, $profile_url, $r) +{ + $salmon_key = Crypto::salmonKey($r['spubkey']); header('Access-Control-Allow-Origin: *'); header("Content-type: application/json; charset=utf-8"); @@ -79,8 +82,9 @@ function xrd_json($a, $uri, $alias, $profile_url, $r) { killme(); } -function xrd_xml($a, $uri, $alias, $profile_url, $r) { - $salmon_key = salmon_key($r['spubkey']); +function xrd_xml($a, $uri, $alias, $profile_url, $r) +{ + $salmon_key = Crypto::salmonKey($r['spubkey']); header('Access-Control-Allow-Origin: *'); header("Content-type: text/xml"); @@ -100,8 +104,8 @@ function xrd_xml($a, $uri, $alias, $profile_url, $r) { '$salmon' => System::baseUrl() . '/salmon/' . $r['nickname'], '$salmen' => System::baseUrl() . '/salmon/' . $r['nickname'] . '/mention', '$subscribe' => System::baseUrl() . '/follow?url={uri}', - '$modexp' => 'data:application/magic-public-key,' . $salmon_key, - )); + '$modexp' => 'data:application/magic-public-key,' . $salmon_key) + ); $arr = array('user' => $r, 'xml' => $o); call_hooks('personal_xrd', $arr); diff --git a/src/Model/User.php b/src/Model/User.php index f487de766..4f294f6e8 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -16,11 +16,11 @@ use Friendica\Model\Contact; use Friendica\Model\Group; use Friendica\Model\Photo; use Friendica\Object\Image; +use Friendica\Util\Crypto; use dba; use Exception; require_once 'boot.php'; -require_once 'include/crypto.php'; require_once 'include/dba.php'; require_once 'include/enotify.php'; require_once 'include/network.php'; @@ -299,7 +299,7 @@ class User $return['password'] = $new_password; - $keys = new_keypair(4096); + $keys = Crypto::newKeypair(4096); if ($keys === false) { throw new Exception(t('SERIOUS ERROR: Generation of security keys failed.')); } @@ -308,7 +308,7 @@ class User $pubkey = $keys['pubkey']; // Create another keypair for signing/verifying salmon protocol messages. - $sres = new_keypair(512); + $sres = Crypto::newKeypair(512); $sprvkey = $sres['prvkey']; $spubkey = $sres['pubkey']; diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 56abbb7fd..539803b6e 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -17,6 +17,7 @@ use Friendica\Database\DBM; use Friendica\Model\Profile; use Friendica\Protocol\Email; use Friendica\Protocol\Feed; +use Friendica\Util\Crypto; use Friendica\Util\XML; use dba; @@ -25,7 +26,6 @@ use DOMDocument; require_once 'include/dba.php'; require_once 'include/network.php'; -require_once "include/crypto.php"; /** * @brief This class contain functions for probing URL @@ -944,7 +944,7 @@ class Probe //if (strstr($data["pubkey"], 'RSA ') || ($link["type"] == "RSA")) if (strstr($data["pubkey"], 'RSA ')) { - $data["pubkey"] = rsatopem($data["pubkey"]); + $data["pubkey"] = Crypto::rsaToPem($data["pubkey"]); } } } @@ -1043,7 +1043,7 @@ class Probe if ($search->length > 0) { $data["pubkey"] = $search->item(0)->nodeValue; if (strstr($data["pubkey"], 'RSA ')) { - $data["pubkey"] = rsatopem($data["pubkey"]); + $data["pubkey"] = Crypto::rsaToPem($data["pubkey"]); } } @@ -1133,7 +1133,7 @@ class Probe //if (strstr($data["pubkey"], 'RSA ') || ($link["type"] == "RSA")) if (strstr($data["pubkey"], 'RSA ')) { - $data["pubkey"] = rsatopem($data["pubkey"]); + $data["pubkey"] = Crypto::rsaToPem($data["pubkey"]); } } } @@ -1244,7 +1244,7 @@ class Probe if (sizeof($key) >= 3) { $m = base64url_decode($key[1]); $e = base64url_decode($key[2]); - $data["pubkey"] = metopem($m, $e); + $data["pubkey"] = Crypto::meToPem($m, $e); } } } diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index eeedd6324..5e9c91645 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -463,7 +463,7 @@ class DFRN /* get site pubkey. this could be a new installation with no site keys*/ $pubkey = Config::get('system', 'site_pubkey'); if (! $pubkey) { - $res = new_keypair(1024); + $res = Crypto::newKeypair(1024); Config::set('system', 'site_prvkey', $res['prvkey']); Config::set('system', 'site_pubkey', $res['pubkey']); } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 15a30f532..59ca2757f 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -22,6 +22,7 @@ use Friendica\Model\Group; use Friendica\Model\Profile; use Friendica\Model\User; use Friendica\Network\Probe; +use Friendica\Util\Crypto; use Friendica\Util\XML; use dba; @@ -173,7 +174,7 @@ class Diaspora $key = self::key($handle); - $verify = rsa_verify($signable_data, $sig, $key); + $verify = Crypto::rsaVerify($signable_data, $sig, $key); if (!$verify) { logger('Message did not verify. Discarding.'); return false; @@ -273,7 +274,7 @@ class Diaspora $author_addr = base64_decode($key_id); $key = self::key($author_addr); - $verify = rsa_verify($signed_data, $signature, $key); + $verify = Crypto::rsaVerify($signed_data, $signature, $key); if (!$verify) { logger('Message did not verify. Discarding.'); http_status_exit(400); @@ -406,7 +407,7 @@ class Diaspora http_status_exit(400); } - $verify = rsa_verify($signed_data, $signature, $key); + $verify = Crypto::rsaVerify($signed_data, $signature, $key); if (!$verify) { logger('Message did not verify. Discarding.'); @@ -699,7 +700,7 @@ class Diaspora $key = self::key($msg["author"]); - if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256")) { + if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) { logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG); return false; } @@ -709,7 +710,7 @@ class Diaspora $key = self::key($fields->author); - if (!rsa_verify($signed_data, $author_signature, $key, "sha256")) { + if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) { logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG); return false; } else { @@ -1432,7 +1433,7 @@ class Diaspora // Check signature $signed_text = 'AccountMigration:'.$old_handle.':'.$new_handle; $key = self::key($old_handle); - if (!rsa_verify($signed_text, $signature, $key, "sha256")) { + if (!Crypto::rsaVerify($signed_text, $signature, $key, "sha256")) { logger('No valid signature for migration.'); return false; } @@ -3032,7 +3033,7 @@ class Diaspora $user['uprvkey'] = $user['prvkey']; } - $signature = rsa_sign($signable_data, $user["uprvkey"]); + $signature = Crypto::rsaSign($signable_data, $user["uprvkey"]); $sig = base64url_encode($signature); $xmldata = array("me:env" => array("me:data" => $data, @@ -3088,7 +3089,7 @@ class Diaspora $signed_text = implode(";", $sigmsg); - return base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256")); + return base64_encode(Crypto::rsaSign($signed_text, $owner["uprvkey"], "sha256")); } /** @@ -3282,7 +3283,7 @@ class Diaspora $profile = self::createProfileData($uid); $signed_text = 'AccountMigration:'.$old_handle.':'.$profile['author']; - $signature = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256")); + $signature = base64_encode(Crypto::rsaSign($signed_text, $owner["uprvkey"], "sha256")); $message = array("author" => $old_handle, "profile" => $profile, diff --git a/src/Protocol/Salmon.php b/src/Protocol/Salmon.php index d26a3229d..38a88c14a 100644 --- a/src/Protocol/Salmon.php +++ b/src/Protocol/Salmon.php @@ -5,10 +5,9 @@ namespace Friendica\Protocol; use Friendica\Network\Probe; +use Friendica\Util\Crypto; use Friendica\Util\XML; -require_once 'include/crypto.php'; - /** * @brief Salmon Protocol class * The Salmon Protocol is a message exchange protocol running over HTTP designed to decentralize commentary @@ -107,18 +106,18 @@ class Salmon $data_type = 'application/atom+xml'; $encoding = 'base64url'; $algorithm = 'RSA-SHA256'; - $keyhash = base64url_encode(hash('sha256', salmon_key($owner['spubkey'])), true); + $keyhash = base64url_encode(hash('sha256', Crypto::salmonKey($owner['spubkey'])), true); $precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm); // GNU Social format - $signature = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey'])); + $signature = base64url_encode(Crypto::rsaSign($data . $precomputed, $owner['sprvkey'])); // Compliant format - $signature2 = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['sprvkey'])); + $signature2 = base64url_encode(Crypto::rsaSign(str_replace('=', '', $data . $precomputed), $owner['sprvkey'])); // Old Status.net format - $signature3 = base64url_encode(rsa_sign($data, $owner['sprvkey'])); + $signature3 = base64url_encode(Crypto::rsaSign($data, $owner['sprvkey'])); // At first try the non compliant method that works for GNU Social $xmldata = array("me:env" => array("me:data" => $data, diff --git a/src/Util/Crypto.php b/src/Util/Crypto.php new file mode 100644 index 000000000..433a5cd67 --- /dev/null +++ b/src/Util/Crypto.php @@ -0,0 +1,260 @@ +SetIntBuffer($Modulus); + $publicExponent = new ASNValue(ASNValue::TAG_INTEGER); + $publicExponent->SetIntBuffer($PublicExponent); + $keySequenceItems = array($modulus, $publicExponent); + $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE); + $keySequence->SetSequence($keySequenceItems); + //Encode bit string + $bitStringValue = $keySequence->Encode(); + $bitStringValue = chr(0x00) . $bitStringValue; //Add unused bits byte + $bitString = new ASNValue(ASNValue::TAG_BITSTRING); + $bitString->Value = $bitStringValue; + //Encode body + $bodyValue = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00" . $bitString->Encode(); + $body = new ASNValue(ASNValue::TAG_SEQUENCE); + $body->Value = $bodyValue; + //Get DER encoded public key: + $PublicDER = $body->Encode(); + 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 = array($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 + * @return string + */ + public static function meToPem($m, $e) + { + $der = self::pkcs8Encode($m, $e); + $key = self::DerToPem($der, false); + return $key; + } + + /** + * @param string $key key + * @param string $m modulo reference + * @param object $e exponent reference + * @return void + */ + 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 = base64url_decode($r[0]->asnData[0]->asnData); + $e = base64url_decode($r[0]->asnData[1]->asnData); + } + + /** + * @param string $key key + * @return string + */ + public static function rsaToPem($key) + { + self::pubRsaToMe($key, $m, $e); + return self::meToPem($m, $e); + } + + /** + * @param string $key key + * @return string + */ + private static function pemToRsa($key) + { + self::pemToMe($key, $m, $e); + return self::meToRsa($m, $e); + } + + /** + * @param string $key key + * @param string $m modulo reference + * @param string $e exponent reference + * @return void + */ + private static function pemToMe($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 = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData); + $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData); + } + + /** + * @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; + } + + /** + * @param string $pubkey public key + * @return string + */ + public static function salmonKey($pubkey) + { + self::pemToMe($pubkey, $m, $e); + return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true); + } + + /** + * @param integer $bits number of bits + * @return mixed + */ + public static function newKeypair($bits) + { + $openssl_options = array( + 'digest_alg' => 'sha1', + 'private_key_bits' => $bits, + 'encrypt_key' => false + ); + + $conf = Config::get('system', 'openssl_conf_file'); + if ($conf) { + $openssl_options['config'] = $conf; + } + $result = openssl_pkey_new($openssl_options); + + if (empty($result)) { + logger('new_keypair: failed'); + return false; + } + + // Get private key + $response = array('prvkey' => '', 'pubkey' => ''); + + openssl_pkey_export($result, $response['prvkey']); + + // Get public key + $pkey = openssl_pkey_get_details($result); + $response['pubkey'] = $pkey["key"]; + + return $response; + } +}