mirror of
https://github.com/friendica/friendica
synced 2024-12-23 08:00:16 +00:00
commit
e376e1abf6
15 changed files with 320 additions and 230 deletions
|
@ -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;
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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'];
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file mod/hostxrd.php
|
||||
*/
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Protocol\Salmon;
|
||||
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("Content-type: text/xml");
|
||||
$pubkey = Config::get('system','site_pubkey');
|
||||
$pubkey = Config::get('system', 'site_pubkey');
|
||||
|
||||
if(! $pubkey) {
|
||||
$res = new_keypair(1024);
|
||||
if (! $pubkey) {
|
||||
$res = Crypto::newKeypair(1024);
|
||||
|
||||
Config::set('system','site_prvkey', $res['prvkey']);
|
||||
Config::set('system','site_pubkey', $res['pubkey']);
|
||||
|
@ -23,8 +26,8 @@ function hostxrd_init(App $a) {
|
|||
'$zhost' => $a->get_hostname(),
|
||||
'$zroot' => System::baseUrl(),
|
||||
'$domain' => System::baseUrl(),
|
||||
'$bigkey' => salmon_key(Config::get('system','site_pubkey')),
|
||||
));
|
||||
exit();
|
||||
'$bigkey' => Salmon::salmonKey(Config::get('system', 'site_pubkey')))
|
||||
);
|
||||
|
||||
exit();
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
24
mod/xrd.php
24
mod/xrd.php
|
@ -1,12 +1,14 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file mod/xrd.php
|
||||
*/
|
||||
use Friendica\App;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBM;
|
||||
use Friendica\Protocol\Salmon;
|
||||
|
||||
require_once('include/crypto.php');
|
||||
|
||||
function xrd_init(App $a) {
|
||||
function xrd_init(App $a)
|
||||
{
|
||||
if ($a->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 = Salmon::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 = Salmon::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);
|
||||
|
|
|
@ -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'];
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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']);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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', self::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,
|
||||
|
@ -201,4 +200,14 @@ class Salmon
|
|||
|
||||
return (($return_code >= 200) && ($return_code < 300)) ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pubkey public key
|
||||
* @return string
|
||||
*/
|
||||
public static function salmonKey($pubkey)
|
||||
{
|
||||
Crypto::pemToMe($pubkey, $m, $e);
|
||||
return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true);
|
||||
}
|
||||
}
|
||||
|
|
252
src/Util/Crypto.php
Normal file
252
src/Util/Crypto.php
Normal file
|
@ -0,0 +1,252 @@
|
|||
<?php
|
||||
/**
|
||||
* @file src/Util/Crypto.php
|
||||
*/
|
||||
namespace Friendica\Util;
|
||||
|
||||
use Friendica\Core\Config;
|
||||
use ASN_BASE;
|
||||
use ASNValue;
|
||||
|
||||
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
|
||||
*/
|
||||
public 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 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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue