Edit File by line
/home/barbar84/www/wp-conte.../plugins/updraftp.../includes
File: class-udrpc.php
<?php
[0] Fix | Delete
// @codingStandardsIgnoreStart
[1] Fix | Delete
/*
[2] Fix | Delete
This class provides methods for encrypting, sending, receiving and decrypting messages of arbitrary length, using standard encryption methods and including protection against replay attacks.
[3] Fix | Delete
[4] Fix | Delete
Example:
[5] Fix | Delete
[6] Fix | Delete
// Set a key and encrypt with it
[7] Fix | Delete
$ud_rpc = new UpdraftPlus_Remote_Communications($name_indicator); // $name_indicator is a key indicator - indicating which key is being used.
[8] Fix | Delete
$ud_rpc->set_key_local($our_private_key);
[9] Fix | Delete
$ud_rpc->set_key_remote($their_public_key);
[10] Fix | Delete
$encrypted = $ud_rpc->encrypt_message('blah blah');
[11] Fix | Delete
[12] Fix | Delete
// Use the saved WP site option
[13] Fix | Delete
$ud_rpc = new UpdraftPlus_Remote_Communications($name_indicator); // $name_indicator is a key indicator - indicating which key is being used.
[14] Fix | Delete
$ud_rpc->set_option_name('udrpc_remotekey');
[15] Fix | Delete
if (!$ud_rpc->get_key_remote()) throw new Exception('...');
[16] Fix | Delete
$encrypted = $ud_rpc->encrypt_message('blah blah');
[17] Fix | Delete
[18] Fix | Delete
// Generate a new key
[19] Fix | Delete
$ud_rpc = new UpdraftPlus_Remote_Communications('myindicator.example.com');
[20] Fix | Delete
$ud_rpc->set_option_name('udrpc_localkey'); // Save as a WP site option
[21] Fix | Delete
$new_pair = $ud_rpc->generate_new_keypair();
[22] Fix | Delete
if ($new_pair) {
[23] Fix | Delete
$local_private_key = $ud_rpc->get_key_local();
[24] Fix | Delete
$remote_public_key = $ud_rpc->get_key_remote();
[25] Fix | Delete
// ...
[26] Fix | Delete
} else {
[27] Fix | Delete
throw new Exception('...');
[28] Fix | Delete
}
[29] Fix | Delete
[30] Fix | Delete
// Send a message
[31] Fix | Delete
$ud_rpc->activate_replay_protection();
[32] Fix | Delete
$ud_rpc->set_destination_url('https://example.com/path/to/wp');
[33] Fix | Delete
$ud_rpc->send_message('ping');
[34] Fix | Delete
$ud_rpc->send_message('somecommand', array('param1' => 'data', 'param2' => 'moredata'));
[35] Fix | Delete
[36] Fix | Delete
// N.B. The data sent needs to be something that will pass json_encode(). So, it may be desirable to base64-encode it first.
[37] Fix | Delete
[38] Fix | Delete
// Create a listener for incoming messages
[39] Fix | Delete
[40] Fix | Delete
add_filter('udrpc_command_somecommand', 'my_function', 10, 3);
[41] Fix | Delete
// function my_function($response, $data, $name_indicator) { ... ; return array('response' => 'my_reply', 'data' => 'any mixed data'); }
[42] Fix | Delete
// Or:
[43] Fix | Delete
// add_filter('udrpc_action', 'some_function', 10, 4); // Function must return something other than false to indicate that it handled the specific command. Any returned value will be sent as the reply.
[44] Fix | Delete
// function some_function($response, $command, $data, $name_indicator) { ...; return array('response' => 'my_reply', 'data' => 'any mixed data'); }
[45] Fix | Delete
$ud_rpc->set_option_name('udrpc_local_private_key');
[46] Fix | Delete
$ud_rpc->activate_replay_protection();
[47] Fix | Delete
if ($ud_rpc->get_key_local()) {
[48] Fix | Delete
// Make sure you call this before the wp_loaded action is fired (e.g. at init)
[49] Fix | Delete
$ud_rpc->create_listener();
[50] Fix | Delete
}
[51] Fix | Delete
[52] Fix | Delete
// Instead of using activate_replay_protection(), you can use activate_sequence_protection() (receiving side) and set_next_send_sequence_id(). They are very similar; but, the sequence number code isn't tested, and is problematic if you may have multiple clients that don't share storage (you can use the current time as a sequence number, but if two clients send at the same millisecond (or whatever granularity you use), you may have problems); whereas the replay protection code relies on database storage on the sending side (not just the receiving).
[53] Fix | Delete
[54] Fix | Delete
*/
[55] Fix | Delete
// @codingStandardsIgnoreEnd
[56] Fix | Delete
if (!class_exists('UpdraftPlus_Remote_Communications')) :
[57] Fix | Delete
class UpdraftPlus_Remote_Communications {
[58] Fix | Delete
[59] Fix | Delete
// Version numbers relate to versions of this PHP library only (i.e. it's not a protocol support number, and version numbers of other compatible libraries (e.g. JavaScript) are not comparable)
[60] Fix | Delete
public $version = '1.4.23';
[61] Fix | Delete
[62] Fix | Delete
private $key_name_indicator;
[63] Fix | Delete
[64] Fix | Delete
private $key_option_name = false;
[65] Fix | Delete
[66] Fix | Delete
private $key_remote = false;
[67] Fix | Delete
[68] Fix | Delete
private $key_local = false;
[69] Fix | Delete
[70] Fix | Delete
private $can_generate = false;
[71] Fix | Delete
[72] Fix | Delete
private $destination_url = false;
[73] Fix | Delete
[74] Fix | Delete
private $maximum_replay_time_difference = 300;
[75] Fix | Delete
[76] Fix | Delete
private $extra_replay_protection = false;
[77] Fix | Delete
[78] Fix | Delete
private $sequence_protection_tolerance;
[79] Fix | Delete
[80] Fix | Delete
private $sequence_protection_table;
[81] Fix | Delete
[82] Fix | Delete
private $sequence_protection_column;
[83] Fix | Delete
[84] Fix | Delete
private $sequence_protection_where_sql;
[85] Fix | Delete
[86] Fix | Delete
// Debug may log confidential data using $this->log() - so only use when you are in a secure environment
[87] Fix | Delete
private $debug = false;
[88] Fix | Delete
[89] Fix | Delete
private $next_send_sequence_id;
[90] Fix | Delete
[91] Fix | Delete
private $allow_cors_from = array();
[92] Fix | Delete
[93] Fix | Delete
private $http_transport = null;
[94] Fix | Delete
[95] Fix | Delete
// Default protocol version - this can be over-ridden with set_message_format
[96] Fix | Delete
// Protocol version 1 (which uses only one RSA key-pair, instead of two) is legacy/deprecated
[97] Fix | Delete
private $format = 2;
[98] Fix | Delete
[99] Fix | Delete
private $http_credentials = array();
[100] Fix | Delete
[101] Fix | Delete
private $incoming_message = null;
[102] Fix | Delete
[103] Fix | Delete
private $message_random_number = null;
[104] Fix | Delete
[105] Fix | Delete
private $require_message_to_be_understood = false;
[106] Fix | Delete
[107] Fix | Delete
public function __construct($key_name_indicator = 'default') {
[108] Fix | Delete
$this->set_key_name_indicator($key_name_indicator);
[109] Fix | Delete
}
[110] Fix | Delete
[111] Fix | Delete
public function set_key_name_indicator($key_name_indicator) {
[112] Fix | Delete
$this->key_name_indicator = $key_name_indicator;
[113] Fix | Delete
}
[114] Fix | Delete
[115] Fix | Delete
public function set_can_generate($can_generate = true) {
[116] Fix | Delete
$this->can_generate = $can_generate;
[117] Fix | Delete
}
[118] Fix | Delete
[119] Fix | Delete
/**
[120] Fix | Delete
* Which sites to allow CORS requests from
[121] Fix | Delete
*
[122] Fix | Delete
* @param string $allow_cors_from
[123] Fix | Delete
*/
[124] Fix | Delete
public function set_allow_cors_from($allow_cors_from) {
[125] Fix | Delete
$this->allow_cors_from = $allow_cors_from;
[126] Fix | Delete
}
[127] Fix | Delete
[128] Fix | Delete
public function set_maximum_replay_time_difference($replay_time_difference) {
[129] Fix | Delete
$this->maximum_replay_time_difference = (int) $replay_time_difference;
[130] Fix | Delete
}
[131] Fix | Delete
[132] Fix | Delete
/**
[133] Fix | Delete
* This will cause more things to be sent to $this->log()
[134] Fix | Delete
*
[135] Fix | Delete
* @param boolean $debug
[136] Fix | Delete
*/
[137] Fix | Delete
public function set_debug($debug = true) {
[138] Fix | Delete
$this->debug = (bool) $debug;
[139] Fix | Delete
}
[140] Fix | Delete
[141] Fix | Delete
/**
[142] Fix | Delete
* Supported values: a Guzzle object, or, if not, then WP's HTTP API function siwll be used
[143] Fix | Delete
*
[144] Fix | Delete
* @param string $transport
[145] Fix | Delete
*/
[146] Fix | Delete
public function set_http_transport($transport) {
[147] Fix | Delete
$this->http_transport = $transport;
[148] Fix | Delete
}
[149] Fix | Delete
[150] Fix | Delete
/**
[151] Fix | Delete
* Sequence protection and replay protection perform similar functions, and using both is often over-kill; the distinction is that sequence protection can be used without needing to do database writes on the sending side (e.g. use the value of time() as the sequence number).
[152] Fix | Delete
* The only rule of sequences is that the receiving side will reject any sequence number that is less than the last previously seen one, within the bounds of the tolerance (but it may also reject those if they are repeats).
[153] Fix | Delete
* The given table/column will record a comma-separated list of recently seen sequences numbers within the tolerance threshold.
[154] Fix | Delete
*
[155] Fix | Delete
* @param string $table
[156] Fix | Delete
* @param string $column
[157] Fix | Delete
* @param string $where_sql
[158] Fix | Delete
* @param integer $tolerance
[159] Fix | Delete
*/
[160] Fix | Delete
public function activate_sequence_protection($table, $column, $where_sql, $tolerance = 5) {
[161] Fix | Delete
$this->sequence_protection_tolerance = (int) $tolerance;
[162] Fix | Delete
$this->sequence_protection_table = (string) $table;
[163] Fix | Delete
$this->sequence_protection_column = (string) $column;
[164] Fix | Delete
$this->sequence_protection_where_sql = (string) $where_sql;
[165] Fix | Delete
}
[166] Fix | Delete
[167] Fix | Delete
private function ensure_crypto_loaded() {
[168] Fix | Delete
if (!class_exists('Crypt_Rijndael') || !class_exists('Crypt_RSA') || !class_exists('Crypt_Hash')) {
[169] Fix | Delete
global $updraftplus;
[170] Fix | Delete
// phpseclib 1.x uses deprecated PHP4-style constructors
[171] Fix | Delete
$this->no_deprecation_warnings_on_php7();
[172] Fix | Delete
if (is_a($updraftplus, 'UpdraftPlus')) {
[173] Fix | Delete
// Since May 2019, the second parameter is unused; but, since we don't know the version, we send it.
[174] Fix | Delete
$ensure_phpseclib = $updraftplus->ensure_phpseclib(array('Crypt_Rijndael', 'Crypt_RSA', 'Crypt_Hash'), array('Crypt/Rijndael', 'Crypt/RSA', 'Crypt/Hash'));
[175] Fix | Delete
if (is_wp_error($ensure_phpseclib)) return $ensure_phpseclib;
[176] Fix | Delete
} elseif (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/vendor/phpseclib/phpseclib/phpseclib')) {
[177] Fix | Delete
$pdir = UPDRAFTPLUS_DIR.'/vendor/phpseclib/phpseclib/phpseclib';
[178] Fix | Delete
if (false === strpos(get_include_path(), $pdir)) set_include_path($pdir.PATH_SEPARATOR.get_include_path());
[179] Fix | Delete
if (!class_exists('Crypt_Rijndael')) include_once 'Crypt/Rijndael.php';
[180] Fix | Delete
if (!class_exists('Crypt_RSA')) include_once 'Crypt/RSA.php';
[181] Fix | Delete
if (!class_exists('Crypt_Hash')) include_once 'Crypt/Hash.php';
[182] Fix | Delete
} elseif (file_exists(dirname(dirname(__FILE__)).'/vendor/phpseclib/phpseclib/phpseclib')) {
[183] Fix | Delete
$pdir = dirname(dirname(__FILE__)).'/vendor/phpseclib/phpseclib/phpseclib';
[184] Fix | Delete
if (false === strpos(get_include_path(), $pdir)) set_include_path($pdir.PATH_SEPARATOR.get_include_path());
[185] Fix | Delete
if (!class_exists('Crypt_Rijndael')) include_once 'Crypt/Rijndael.php';
[186] Fix | Delete
if (!class_exists('Crypt_RSA')) include_once 'Crypt/RSA.php';
[187] Fix | Delete
if (!class_exists('Crypt_Hash')) include_once 'Crypt/Hash.php';
[188] Fix | Delete
}
[189] Fix | Delete
}
[190] Fix | Delete
}
[191] Fix | Delete
[192] Fix | Delete
/**
[193] Fix | Delete
* Ugly, but necessary to prevent debug output breaking the conversation when the user has debug turned on
[194] Fix | Delete
*/
[195] Fix | Delete
private function no_deprecation_warnings_on_php7() {
[196] Fix | Delete
// PHP_MAJOR_VERSION is defined in PHP 5.2.7+
[197] Fix | Delete
// We don't test for PHP > 7 because the specific deprecated element will be removed in PHP 8 - and so no warning should come anyway (and we shouldn't suppress other stuff until we know we need to).
[198] Fix | Delete
// @codingStandardsIgnoreLine
[199] Fix | Delete
if (defined('PHP_MAJOR_VERSION') && PHP_MAJOR_VERSION == 7) {
[200] Fix | Delete
$old_level = error_reporting();
[201] Fix | Delete
// @codingStandardsIgnoreLine
[202] Fix | Delete
$new_level = $old_level & ~E_DEPRECATED;
[203] Fix | Delete
if ($old_level != $new_level) error_reporting($new_level);
[204] Fix | Delete
}
[205] Fix | Delete
}
[206] Fix | Delete
[207] Fix | Delete
public function set_destination_url($destination_url) {
[208] Fix | Delete
$this->destination_url = $destination_url;
[209] Fix | Delete
}
[210] Fix | Delete
[211] Fix | Delete
public function get_destination_url() {
[212] Fix | Delete
return $this->destination_url;
[213] Fix | Delete
}
[214] Fix | Delete
[215] Fix | Delete
public function set_option_name($key_option_name) {
[216] Fix | Delete
$this->key_option_name = $key_option_name;
[217] Fix | Delete
}
[218] Fix | Delete
[219] Fix | Delete
/**
[220] Fix | Delete
* Method to get the remote key
[221] Fix | Delete
*
[222] Fix | Delete
* @return string
[223] Fix | Delete
*/
[224] Fix | Delete
public function get_key_remote() {
[225] Fix | Delete
if (empty($this->key_remote) && $this->can_generate) {
[226] Fix | Delete
$this->generate_new_keypair();
[227] Fix | Delete
}
[228] Fix | Delete
[229] Fix | Delete
return empty($this->key_remote) ? false : $this->key_remote;
[230] Fix | Delete
}
[231] Fix | Delete
[232] Fix | Delete
/**
[233] Fix | Delete
* Set the remote key
[234] Fix | Delete
*
[235] Fix | Delete
* @param string $key_remote
[236] Fix | Delete
*/
[237] Fix | Delete
public function set_key_remote($key_remote) {
[238] Fix | Delete
$this->key_remote = $key_remote;
[239] Fix | Delete
}
[240] Fix | Delete
[241] Fix | Delete
/**
[242] Fix | Delete
* Used for sending - when receiving, the format is part of the message
[243] Fix | Delete
*
[244] Fix | Delete
* @param integer $format
[245] Fix | Delete
*/
[246] Fix | Delete
public function set_message_format($format = 2) {
[247] Fix | Delete
$this->format = $format;
[248] Fix | Delete
}
[249] Fix | Delete
[250] Fix | Delete
/**
[251] Fix | Delete
* Used for sending - when receiving, the format is part of the message
[252] Fix | Delete
*
[253] Fix | Delete
* @return integer
[254] Fix | Delete
*/
[255] Fix | Delete
public function get_message_format() {
[256] Fix | Delete
return $this->format;
[257] Fix | Delete
}
[258] Fix | Delete
[259] Fix | Delete
/**
[260] Fix | Delete
* Method to get the local key
[261] Fix | Delete
*
[262] Fix | Delete
* @return string
[263] Fix | Delete
*/
[264] Fix | Delete
public function get_key_local() {
[265] Fix | Delete
if (empty($this->key_local)) {
[266] Fix | Delete
if ($this->key_option_name) {
[267] Fix | Delete
$key_local = get_site_option($this->key_option_name);
[268] Fix | Delete
if ($key_local) {
[269] Fix | Delete
$this->key_local = $key_local;
[270] Fix | Delete
}
[271] Fix | Delete
}
[272] Fix | Delete
}
[273] Fix | Delete
if (empty($this->key_local) && $this->can_generate) {
[274] Fix | Delete
$this->generate_new_keypair();
[275] Fix | Delete
}
[276] Fix | Delete
[277] Fix | Delete
return empty($this->key_local) ? false : $this->key_local;
[278] Fix | Delete
}
[279] Fix | Delete
[280] Fix | Delete
/**
[281] Fix | Delete
* Tests whether a supplied string (after trimming) is a valid portable bundle
[282] Fix | Delete
*
[283] Fix | Delete
* @param string $bundle [description]
[284] Fix | Delete
* @param string $format same as get_portable_bundle()
[285] Fix | Delete
* @return array (which the consumer is free to use - e.g. convert into internationalised string), with keys 'code' and (perhaps) 'data'
[286] Fix | Delete
*/
[287] Fix | Delete
public function decode_portable_bundle($bundle, $format = 'raw') {
[288] Fix | Delete
$bundle = trim($bundle);
[289] Fix | Delete
if ('base64_with_count' == $format) {
[290] Fix | Delete
if (strlen($bundle) < 5) return array('code' => 'invalid_wrong_length', 'data' => 'too_short');
[291] Fix | Delete
$len = substr($bundle, 0, 4);
[292] Fix | Delete
$bundle = substr($bundle, 4);
[293] Fix | Delete
$len = hexdec($len);
[294] Fix | Delete
if (strlen($bundle) != $len) return array('code' => 'invalid_wrong_length', 'data' => "1,$len,".strlen($bundle));
[295] Fix | Delete
if (false === ($bundle = base64_decode($bundle))) return array('code' => 'invalid_corrupt', 'data' => 'not_base64');
[296] Fix | Delete
if (null === ($bundle = json_decode($bundle, true))) return array('code' => 'invalid_corrupt', 'data' => 'not_json');
[297] Fix | Delete
}
[298] Fix | Delete
if (empty($bundle['key'])) return array('code' => 'invalid_corrupt', 'data' => 'no_key');
[299] Fix | Delete
if (empty($bundle['url'])) return array('code' => 'invalid_corrupt', 'data' => 'no_url');
[300] Fix | Delete
if (empty($bundle['name_indicator'])) return array('code' => 'invalid_corrupt', 'data' => 'no_name_indicator');
[301] Fix | Delete
[302] Fix | Delete
return $bundle;
[303] Fix | Delete
}
[304] Fix | Delete
[305] Fix | Delete
/**
[306] Fix | Delete
* Method to get a portable bundle sufficient to contact this site (i.e. remote site - so you need to have generated a key-pair, or stored the remote key somewhere and restored it)
[307] Fix | Delete
*
[308] Fix | Delete
* @param string $format Supported formats: base64_with_count and default)raw
[309] Fix | Delete
* @param array $extra_info needs to be JSON-serialisable, so be careful about what you put into it.
[310] Fix | Delete
* @param array $options [description]
[311] Fix | Delete
* @return array
[312] Fix | Delete
*/
[313] Fix | Delete
public function get_portable_bundle($format = 'raw', $extra_info = array(), $options = array()) {
[314] Fix | Delete
[315] Fix | Delete
$bundle = array_merge($extra_info, array(
[316] Fix | Delete
'key' => empty($options['key']) ? $this->get_key_remote() : $options['key'],
[317] Fix | Delete
'name_indicator' => $this->key_name_indicator,
[318] Fix | Delete
'url' => trailingslashit(network_site_url()),
[319] Fix | Delete
'admin_url' => trailingslashit(admin_url()),
[320] Fix | Delete
'network_admin_url' => trailingslashit(network_admin_url()),
[321] Fix | Delete
'format_support' => 2,
[322] Fix | Delete
));
[323] Fix | Delete
[324] Fix | Delete
if ('base64_with_count' == $format) {
[325] Fix | Delete
$bundle = base64_encode(json_encode($bundle));
[326] Fix | Delete
[327] Fix | Delete
$len = strlen($bundle); // Get the length
[328] Fix | Delete
$len = dechex($len); // The first bytes of the message are the bundle length
[329] Fix | Delete
$len = str_pad($len, 4, '0', STR_PAD_LEFT); // Zero pad
[330] Fix | Delete
[331] Fix | Delete
return $len.$bundle;
[332] Fix | Delete
[333] Fix | Delete
} else {
[334] Fix | Delete
return $bundle;
[335] Fix | Delete
}
[336] Fix | Delete
[337] Fix | Delete
}
[338] Fix | Delete
[339] Fix | Delete
public function set_key_local($key_local) {
[340] Fix | Delete
$this->key_local = $key_local;
[341] Fix | Delete
if ($this->key_option_name) update_site_option($this->key_option_name, $this->key_local);
[342] Fix | Delete
}
[343] Fix | Delete
[344] Fix | Delete
public function generate_new_keypair($key_size = 2048) {
[345] Fix | Delete
[346] Fix | Delete
$this->ensure_crypto_loaded();
[347] Fix | Delete
[348] Fix | Delete
$rsa = new Crypt_RSA();
[349] Fix | Delete
$keys = $rsa->createKey($key_size);
[350] Fix | Delete
[351] Fix | Delete
if (empty($keys['privatekey'])) {
[352] Fix | Delete
$this->set_key_local(false);
[353] Fix | Delete
} else {
[354] Fix | Delete
$this->set_key_local($keys['privatekey']);
[355] Fix | Delete
}
[356] Fix | Delete
[357] Fix | Delete
if (empty($keys['publickey'])) {
[358] Fix | Delete
$this->set_key_remote(false);
[359] Fix | Delete
} else {
[360] Fix | Delete
$this->set_key_remote($keys['publickey']);
[361] Fix | Delete
}
[362] Fix | Delete
[363] Fix | Delete
return empty($keys['publickey']) ? false : true;
[364] Fix | Delete
}
[365] Fix | Delete
[366] Fix | Delete
/**
[367] Fix | Delete
* A base-64 encoded RSA hash (PKCS_1) of the message digest
[368] Fix | Delete
*
[369] Fix | Delete
* @param string $message
[370] Fix | Delete
* @param boolean $use_key
[371] Fix | Delete
* @return array
[372] Fix | Delete
*/
[373] Fix | Delete
public function signature_for_message($message, $use_key = false) {
[374] Fix | Delete
[375] Fix | Delete
$hash_algorithm = 'sha256';
[376] Fix | Delete
[377] Fix | Delete
// Sign with the private (local) key
[378] Fix | Delete
if (!$use_key) {
[379] Fix | Delete
if (!$this->key_local) throw new Exception('No signing key has been set');
[380] Fix | Delete
$use_key = $this->key_local;
[381] Fix | Delete
}
[382] Fix | Delete
[383] Fix | Delete
$this->ensure_crypto_loaded();
[384] Fix | Delete
[385] Fix | Delete
$rsa = new Crypt_RSA();
[386] Fix | Delete
$rsa->loadKey($use_key);
[387] Fix | Delete
// This is the older signature mode; phpseclib's default is the preferred CRYPT_RSA_SIGNATURE_PSS; however, Forge JS doesn't yet support this. More info: https://en.wikipedia.org/wiki/PKCS_1
[388] Fix | Delete
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
[389] Fix | Delete
[390] Fix | Delete
// Don't do this: Crypt_RSA::sign() already calculates the digest of the hash
[391] Fix | Delete
// $hash = new Crypt_Hash($hash_algorithm);
[392] Fix | Delete
// $hashed = $hash->hash($message);
[393] Fix | Delete
[394] Fix | Delete
// if ($this->debug) $this->log("Message hash (hash=$hash_algorithm) (hex): ".bin2hex($hashed));
[395] Fix | Delete
[396] Fix | Delete
// phpseclib defaults to SHA1
[397] Fix | Delete
$rsa->setHash($hash_algorithm);
[398] Fix | Delete
$encrypted = $rsa->sign($message);
[399] Fix | Delete
[400] Fix | Delete
if ($this->debug) $this->log('Signed hash (mode='.CRYPT_RSA_SIGNATURE_PKCS1.') (hex): '.bin2hex($encrypted));
[401] Fix | Delete
[402] Fix | Delete
$signature = base64_encode($encrypted);
[403] Fix | Delete
[404] Fix | Delete
if ($this->debug) $this->log("Message signature (base64): $signature");
[405] Fix | Delete
[406] Fix | Delete
return $signature;
[407] Fix | Delete
}
[408] Fix | Delete
[409] Fix | Delete
/**
[410] Fix | Delete
* Log description
[411] Fix | Delete
*
[412] Fix | Delete
* @param string $message
[413] Fix | Delete
* @param string $level $level is not yet used much
[414] Fix | Delete
*/
[415] Fix | Delete
private function log($message, $level = 'notice') {
[416] Fix | Delete
// Allow other plugins to do something with the message
[417] Fix | Delete
do_action('udrpc_log', $message, $level, $this->key_name_indicator, $this->debug, $this);
[418] Fix | Delete
if ('info' != $level) error_log('UDRPC ('.$this->key_name_indicator.", $level): $message");
[419] Fix | Delete
}
[420] Fix | Delete
[421] Fix | Delete
/**
[422] Fix | Delete
* Encrypt the message, using the local key (which needs to exist)
[423] Fix | Delete
*
[424] Fix | Delete
* @param string $plaintext
[425] Fix | Delete
* @param boolean $use_key
[426] Fix | Delete
* @param integer $key_length
[427] Fix | Delete
* @return array
[428] Fix | Delete
*/
[429] Fix | Delete
public function encrypt_message($plaintext, $use_key = false, $key_length = 32) {
[430] Fix | Delete
[431] Fix | Delete
if (!$use_key) {
[432] Fix | Delete
if (1 == $this->format) {
[433] Fix | Delete
if (!$this->key_local) throw new Exception('No encryption key has been set');
[434] Fix | Delete
$use_key = $this->key_local;
[435] Fix | Delete
} else {
[436] Fix | Delete
if (!$this->key_remote) throw new Exception('No encryption key has been set');
[437] Fix | Delete
$use_key = $this->key_remote;
[438] Fix | Delete
}
[439] Fix | Delete
}
[440] Fix | Delete
[441] Fix | Delete
$this->ensure_crypto_loaded();
[442] Fix | Delete
[443] Fix | Delete
$rsa = new Crypt_RSA();
[444] Fix | Delete
[445] Fix | Delete
if (defined('UDRPC_PHPSECLIB_ENCRYPTION_MODE')) $rsa->setEncryptionMode(UDRPC_PHPSECLIB_ENCRYPTION_MODE);
[446] Fix | Delete
[447] Fix | Delete
$rij = new Crypt_Rijndael();
[448] Fix | Delete
[449] Fix | Delete
// Generate Random Symmetric Key
[450] Fix | Delete
$sym_key = crypt_random_string($key_length);
[451] Fix | Delete
[452] Fix | Delete
if ($this->debug) $this->log('Unencrypted symmetric key (hex): '.bin2hex($sym_key));
[453] Fix | Delete
[454] Fix | Delete
// Encrypt Message with new Symmetric Key
[455] Fix | Delete
$rij->setKey($sym_key);
[456] Fix | Delete
$ciphertext = $rij->encrypt($plaintext);
[457] Fix | Delete
[458] Fix | Delete
if ($this->debug) $this->log('Encrypted ciphertext (hex): '.bin2hex($ciphertext));
[459] Fix | Delete
[460] Fix | Delete
$ciphertext = base64_encode($ciphertext);
[461] Fix | Delete
[462] Fix | Delete
// Encrypt the Symmetric Key with the Asymmetric Key
[463] Fix | Delete
$rsa->loadKey($use_key);
[464] Fix | Delete
$sym_key = $rsa->encrypt($sym_key);
[465] Fix | Delete
[466] Fix | Delete
if ($this->debug) $this->log('Encrypted symmetric key (hex): '.bin2hex($sym_key));
[467] Fix | Delete
[468] Fix | Delete
// Base 64 encode the symmetric key for transport
[469] Fix | Delete
$sym_key = base64_encode($sym_key);
[470] Fix | Delete
[471] Fix | Delete
if ($this->debug) $this->log('Encrypted symmetric key (b64): '.$sym_key);
[472] Fix | Delete
[473] Fix | Delete
$len = str_pad(dechex(strlen($sym_key)), 3, '0', STR_PAD_LEFT); // Zero pad to be sure.
[474] Fix | Delete
[475] Fix | Delete
// 16 characters of hex is enough for the payload to be to 16 exabytes (giga < tera < peta < exa) of data
[476] Fix | Delete
$cipherlen = str_pad(dechex(strlen($ciphertext)), 16, '0', STR_PAD_LEFT);
[477] Fix | Delete
[478] Fix | Delete
// Concatenate the length, the encrypted symmetric key, and the message
[479] Fix | Delete
return $len.$sym_key.$cipherlen.$ciphertext;
[480] Fix | Delete
[481] Fix | Delete
}
[482] Fix | Delete
[483] Fix | Delete
/**
[484] Fix | Delete
* Decrypt the message, using the local key (which needs to exist)
[485] Fix | Delete
*
[486] Fix | Delete
* @param string $message
[487] Fix | Delete
* @return array
[488] Fix | Delete
*/
[489] Fix | Delete
public function decrypt_message($message) {
[490] Fix | Delete
[491] Fix | Delete
if (!$this->key_local) throw new Exception('No decryption key has been set');
[492] Fix | Delete
[493] Fix | Delete
$this->ensure_crypto_loaded();
[494] Fix | Delete
[495] Fix | Delete
$rsa = new Crypt_RSA();
[496] Fix | Delete
if (defined('UDRPC_PHPSECLIB_ENCRYPTION_MODE')) $rsa->setEncryptionMode(UDRPC_PHPSECLIB_ENCRYPTION_MODE);
[497] Fix | Delete
// Defaults to CRYPT_AES_MODE_CBC
[498] Fix | Delete
$rij = new Crypt_Rijndael();
[499] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function