Crypto to src

move Crypto to src and Friendica\Util namespace
This commit is contained in:
Adam Magness 2017-12-30 11:51:49 -05:00
parent 6d6d83012c
commit 9e6bf79380
15 changed files with 317 additions and 230 deletions

View file

@ -1,172 +0,0 @@
<?php
use Friendica\Core\Config;
require_once 'library/ASNValue.class.php';
require_once 'library/asn1.php';
// supported algorithms are 'sha256', 'sha1'
function rsa_sign($data, $key, $alg = 'sha256') {
openssl_sign($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
return $sig;
}
function rsa_verify($data, $sig, $key, $alg = 'sha256') {
return openssl_verify($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
}
function DerToPem($Der, $Private = false) {
//Encode:
$Der = base64_encode($Der);
//Split lines:
$lines = str_split($Der, 65);
$body = implode("\n", $lines);
//Get title:
$title = $Private ? 'RSA PRIVATE KEY' : 'PUBLIC KEY';
//Add wrapping:
$result = "-----BEGIN {$title}-----\n";
$result .= $body . "\n";
$result .= "-----END {$title}-----\n";
return $result;
}
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;
}
function pkcs8_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();
$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;
}

View file

@ -21,7 +21,6 @@ use Friendica\Protocol\Feed;
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/oembed.php'; require_once 'include/oembed.php';
require_once 'include/crypto.php';
require_once 'include/tags.php'; require_once 'include/tags.php';
require_once 'include/files.php'; require_once 'include/files.php';
require_once 'include/text.php'; require_once 'include/text.php';

View file

@ -29,6 +29,7 @@ use Friendica\Model\Group;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Util\Crypto;
require_once 'include/enotify.php'; 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. * worried about key leakage than anybody cracking it.
* *
*/ */
require_once 'include/crypto.php'; $res = Crypto::newKeypair(4096);
$res = new_keypair(4096);
$private_key = $res['prvkey']; $private_key = $res['prvkey'];

View file

@ -8,8 +8,6 @@ use Friendica\Core\System;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Util\XML; use Friendica\Util\XML;
require_once "include/crypto.php";
function fetch_init(App $a) function fetch_init(App $a)
{ {

View file

@ -1,18 +1,20 @@
<?php <?php
/**
* @file mod/hostxrd.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Util\Crypto;
require_once('include/crypto.php'); function hostxrd_init(App $a)
{
function hostxrd_init(App $a) {
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Origin: *');
header("Content-type: text/xml"); header("Content-type: text/xml");
$pubkey = Config::get('system', 'site_pubkey'); $pubkey = Config::get('system', 'site_pubkey');
if (! $pubkey) { if (! $pubkey) {
$res = new_keypair(1024); $res = Crypto::newKeypair(1024);
Config::set('system','site_prvkey', $res['prvkey']); Config::set('system','site_prvkey', $res['prvkey']);
Config::set('system','site_pubkey', $res['pubkey']); Config::set('system','site_pubkey', $res['pubkey']);
@ -23,8 +25,8 @@ function hostxrd_init(App $a) {
'$zhost' => $a->get_hostname(), '$zhost' => $a->get_hostname(),
'$zroot' => System::baseUrl(), '$zroot' => System::baseUrl(),
'$domain' => System::baseUrl(), '$domain' => System::baseUrl(),
'$bigkey' => salmon_key(Config::get('system','site_pubkey')), '$bigkey' => Crypto::salmonKey(Config::get('system', 'site_pubkey')))
)); );
exit();
exit();
} }

View file

@ -29,7 +29,6 @@ use Friendica\Protocol\Diaspora;
use Friendica\Protocol\Email; use Friendica\Protocol\Email;
use Friendica\Util\Emailer; use Friendica\Util\Emailer;
require_once 'include/crypto.php';
require_once 'include/enotify.php'; require_once 'include/enotify.php';
require_once 'include/tags.php'; require_once 'include/tags.php';
require_once 'include/files.php'; require_once 'include/files.php';

View file

@ -9,8 +9,6 @@ use Friendica\Core\Config;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
require_once 'include/crypto.php';
/** /**
* @param object $a App * @param object $a App
* @return void * @return void

View file

@ -7,8 +7,8 @@ use Friendica\Core\PConfig;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Protocol\OStatus; use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon; use Friendica\Protocol\Salmon;
use Friendica\Util\Crypto;
require_once 'include/crypto.php';
require_once 'include/items.php'; require_once 'include/items.php';
require_once 'include/follow.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); 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. // We should have everything we need now. Let's see if it verifies.
// Try GNU Social format // Try GNU Social format
$verify = rsa_verify($signed_data, $signature, $pubkey); $verify = Crypto::rsaVerify($signed_data, $signature, $pubkey);
$mode = 1; $mode = 1;
if (! $verify) { if (! $verify) {
logger('mod-salmon: message did not verify using protocol. Trying compliant format.'); 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; $mode = 2;
} }
if (! $verify) { if (! $verify) {
logger('mod-salmon: message did not verify using padding. Trying old statusnet format.'); 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; $mode = 3;
} }

View file

@ -1,12 +1,14 @@
<?php <?php
/**
* @file mod/xrd.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Util\Crypto;
require_once('include/crypto.php'); function xrd_init(App $a)
{
function xrd_init(App $a) {
if ($a->argv[0] == 'xrd') { if ($a->argv[0] == 'xrd') {
$uri = urldecode(notags(trim($_GET['uri']))); $uri = urldecode(notags(trim($_GET['uri'])));
if ($_SERVER['HTTP_ACCEPT'] == 'application/jrd+json') { 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) { function xrd_json($a, $uri, $alias, $profile_url, $r)
$salmon_key = salmon_key($r['spubkey']); {
$salmon_key = Crypto::salmonKey($r['spubkey']);
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Origin: *');
header("Content-type: application/json; charset=utf-8"); header("Content-type: application/json; charset=utf-8");
@ -79,8 +82,9 @@ function xrd_json($a, $uri, $alias, $profile_url, $r) {
killme(); killme();
} }
function xrd_xml($a, $uri, $alias, $profile_url, $r) { function xrd_xml($a, $uri, $alias, $profile_url, $r)
$salmon_key = salmon_key($r['spubkey']); {
$salmon_key = Crypto::salmonKey($r['spubkey']);
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Origin: *');
header("Content-type: text/xml"); header("Content-type: text/xml");
@ -100,8 +104,8 @@ function xrd_xml($a, $uri, $alias, $profile_url, $r) {
'$salmon' => System::baseUrl() . '/salmon/' . $r['nickname'], '$salmon' => System::baseUrl() . '/salmon/' . $r['nickname'],
'$salmen' => System::baseUrl() . '/salmon/' . $r['nickname'] . '/mention', '$salmen' => System::baseUrl() . '/salmon/' . $r['nickname'] . '/mention',
'$subscribe' => System::baseUrl() . '/follow?url={uri}', '$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); $arr = array('user' => $r, 'xml' => $o);
call_hooks('personal_xrd', $arr); call_hooks('personal_xrd', $arr);

View file

@ -16,11 +16,11 @@ use Friendica\Model\Contact;
use Friendica\Model\Group; use Friendica\Model\Group;
use Friendica\Model\Photo; use Friendica\Model\Photo;
use Friendica\Object\Image; use Friendica\Object\Image;
use Friendica\Util\Crypto;
use dba; use dba;
use Exception; use Exception;
require_once 'boot.php'; require_once 'boot.php';
require_once 'include/crypto.php';
require_once 'include/dba.php'; require_once 'include/dba.php';
require_once 'include/enotify.php'; require_once 'include/enotify.php';
require_once 'include/network.php'; require_once 'include/network.php';
@ -299,7 +299,7 @@ class User
$return['password'] = $new_password; $return['password'] = $new_password;
$keys = new_keypair(4096); $keys = Crypto::newKeypair(4096);
if ($keys === false) { if ($keys === false) {
throw new Exception(t('SERIOUS ERROR: Generation of security keys failed.')); throw new Exception(t('SERIOUS ERROR: Generation of security keys failed.'));
} }
@ -308,7 +308,7 @@ class User
$pubkey = $keys['pubkey']; $pubkey = $keys['pubkey'];
// Create another keypair for signing/verifying salmon protocol messages. // Create another keypair for signing/verifying salmon protocol messages.
$sres = new_keypair(512); $sres = Crypto::newKeypair(512);
$sprvkey = $sres['prvkey']; $sprvkey = $sres['prvkey'];
$spubkey = $sres['pubkey']; $spubkey = $sres['pubkey'];

View file

@ -17,6 +17,7 @@ use Friendica\Database\DBM;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Protocol\Email; use Friendica\Protocol\Email;
use Friendica\Protocol\Feed; use Friendica\Protocol\Feed;
use Friendica\Util\Crypto;
use Friendica\Util\XML; use Friendica\Util\XML;
use dba; use dba;
@ -25,7 +26,6 @@ use DOMDocument;
require_once 'include/dba.php'; require_once 'include/dba.php';
require_once 'include/network.php'; require_once 'include/network.php';
require_once "include/crypto.php";
/** /**
* @brief This class contain functions for probing URL * @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 ') || ($link["type"] == "RSA"))
if (strstr($data["pubkey"], '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) { if ($search->length > 0) {
$data["pubkey"] = $search->item(0)->nodeValue; $data["pubkey"] = $search->item(0)->nodeValue;
if (strstr($data["pubkey"], 'RSA ')) { 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 ') || ($link["type"] == "RSA"))
if (strstr($data["pubkey"], '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) { if (sizeof($key) >= 3) {
$m = base64url_decode($key[1]); $m = base64url_decode($key[1]);
$e = base64url_decode($key[2]); $e = base64url_decode($key[2]);
$data["pubkey"] = metopem($m, $e); $data["pubkey"] = Crypto::meToPem($m, $e);
} }
} }
} }

View file

@ -463,7 +463,7 @@ class DFRN
/* get site pubkey. this could be a new installation with no site keys*/ /* get site pubkey. this could be a new installation with no site keys*/
$pubkey = Config::get('system', 'site_pubkey'); $pubkey = Config::get('system', 'site_pubkey');
if (! $pubkey) { if (! $pubkey) {
$res = new_keypair(1024); $res = Crypto::newKeypair(1024);
Config::set('system', 'site_prvkey', $res['prvkey']); Config::set('system', 'site_prvkey', $res['prvkey']);
Config::set('system', 'site_pubkey', $res['pubkey']); Config::set('system', 'site_pubkey', $res['pubkey']);
} }

View file

@ -22,6 +22,7 @@ use Friendica\Model\Group;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Util\Crypto;
use Friendica\Util\XML; use Friendica\Util\XML;
use dba; use dba;
@ -173,7 +174,7 @@ class Diaspora
$key = self::key($handle); $key = self::key($handle);
$verify = rsa_verify($signable_data, $sig, $key); $verify = Crypto::rsaVerify($signable_data, $sig, $key);
if (!$verify) { if (!$verify) {
logger('Message did not verify. Discarding.'); logger('Message did not verify. Discarding.');
return false; return false;
@ -273,7 +274,7 @@ class Diaspora
$author_addr = base64_decode($key_id); $author_addr = base64_decode($key_id);
$key = self::key($author_addr); $key = self::key($author_addr);
$verify = rsa_verify($signed_data, $signature, $key); $verify = Crypto::rsaVerify($signed_data, $signature, $key);
if (!$verify) { if (!$verify) {
logger('Message did not verify. Discarding.'); logger('Message did not verify. Discarding.');
http_status_exit(400); http_status_exit(400);
@ -406,7 +407,7 @@ class Diaspora
http_status_exit(400); http_status_exit(400);
} }
$verify = rsa_verify($signed_data, $signature, $key); $verify = Crypto::rsaVerify($signed_data, $signature, $key);
if (!$verify) { if (!$verify) {
logger('Message did not verify. Discarding.'); logger('Message did not verify. Discarding.');
@ -699,7 +700,7 @@ class Diaspora
$key = self::key($msg["author"]); $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); 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; return false;
} }
@ -709,7 +710,7 @@ class Diaspora
$key = self::key($fields->author); $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); 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; return false;
} else { } else {
@ -1432,7 +1433,7 @@ class Diaspora
// Check signature // Check signature
$signed_text = 'AccountMigration:'.$old_handle.':'.$new_handle; $signed_text = 'AccountMigration:'.$old_handle.':'.$new_handle;
$key = self::key($old_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.'); logger('No valid signature for migration.');
return false; return false;
} }
@ -3032,7 +3033,7 @@ class Diaspora
$user['uprvkey'] = $user['prvkey']; $user['uprvkey'] = $user['prvkey'];
} }
$signature = rsa_sign($signable_data, $user["uprvkey"]); $signature = Crypto::rsaSign($signable_data, $user["uprvkey"]);
$sig = base64url_encode($signature); $sig = base64url_encode($signature);
$xmldata = array("me:env" => array("me:data" => $data, $xmldata = array("me:env" => array("me:data" => $data,
@ -3088,7 +3089,7 @@ class Diaspora
$signed_text = implode(";", $sigmsg); $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); $profile = self::createProfileData($uid);
$signed_text = 'AccountMigration:'.$old_handle.':'.$profile['author']; $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, $message = array("author" => $old_handle,
"profile" => $profile, "profile" => $profile,

View file

@ -5,10 +5,9 @@
namespace Friendica\Protocol; namespace Friendica\Protocol;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Util\Crypto;
use Friendica\Util\XML; use Friendica\Util\XML;
require_once 'include/crypto.php';
/** /**
* @brief Salmon Protocol class * @brief Salmon Protocol class
* The Salmon Protocol is a message exchange protocol running over HTTP designed to decentralize commentary * 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'; $data_type = 'application/atom+xml';
$encoding = 'base64url'; $encoding = 'base64url';
$algorithm = 'RSA-SHA256'; $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); $precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm);
// GNU Social format // GNU Social format
$signature = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey'])); $signature = base64url_encode(Crypto::rsaSign($data . $precomputed, $owner['sprvkey']));
// Compliant format // 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 // 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 // At first try the non compliant method that works for GNU Social
$xmldata = array("me:env" => array("me:data" => $data, $xmldata = array("me:env" => array("me:data" => $data,

260
src/Util/Crypto.php Normal file
View file

@ -0,0 +1,260 @@
<?php
/**
* @file src/Util/Crypto.php
*/
namespace Friendica\Util;
use Friendica\Core\Config;
require_once 'library/ASNValue.class.php';
require_once 'library/asn1.php';
/**
* @brief Crypto class
*/
class Crypto
{
// supported algorithms are 'sha256', 'sha1'
/**
* @param string $data data
* @param string $key key
* @param string $alg algorithm
* @return string
*/
public static function rsaSign($data, $key, $alg = 'sha256')
{
openssl_sign($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
return $sig;
}
/**
* @param string $data data
* @param string $sig signature
* @param string $key key
* @param string $alg algorithm
* @return boolean
*/
public static function rsaVerify($data, $sig, $key, $alg = 'sha256')
{
return openssl_verify($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
}
/**
* @param string $Der der formatted string
* @param string $Private key type optional, default false
* @return string
*/
private static function DerToPem($Der, $Private = false)
{
//Encode:
$Der = base64_encode($Der);
//Split lines:
$lines = str_split($Der, 65);
$body = implode("\n", $lines);
//Get title:
$title = $Private ? 'RSA PRIVATE KEY' : 'PUBLIC KEY';
//Add wrapping:
$result = "-----BEGIN {$title}-----\n";
$result .= $body . "\n";
$result .= "-----END {$title}-----\n";
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
* @return string
*/
private static function pkcs8Encode($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();
$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;
}
}