295 lines
7.9 KiB
PHP
Executable File
295 lines
7.9 KiB
PHP
Executable File
<?php
|
|
|
|
// simple santization function to accept only alphanumeric characters
|
|
function san($a, $b = "")
|
|
{
|
|
$a = preg_replace("/[^a-zA-Z0-9".$b."]/", "", $a);
|
|
|
|
return $a;
|
|
}
|
|
|
|
function san_ip($a)
|
|
{
|
|
$a = preg_replace("/[^a-fA-F0-9\[\]\.\:]/", "", $a);
|
|
return $a;
|
|
}
|
|
|
|
function san_host($a)
|
|
{
|
|
$a = preg_replace("/[^a-zA-Z0-9\.\-\:\/]/", "", $a);
|
|
return $a;
|
|
}
|
|
|
|
// api error and exit
|
|
function api_err($data)
|
|
{
|
|
global $_config;
|
|
echo json_encode(["status" => "error", "data" => $data, "coin" => $_config['coin']]);
|
|
exit;
|
|
}
|
|
|
|
// api print ok and exit
|
|
function api_echo($data)
|
|
{
|
|
global $_config;
|
|
echo json_encode(["status" => "ok", "data" => $data, "coin" => $_config['coin']]);
|
|
exit;
|
|
}
|
|
|
|
// log function, shows only in cli atm
|
|
function _log($data, $verbosity = 0)
|
|
{
|
|
$date = date("[Y-m-d H:i:s]");
|
|
$trace = debug_backtrace();
|
|
$loc = count($trace) - 1;
|
|
$file = substr($trace[$loc]['file'], strrpos($trace[$loc]['file'], "/") + 1);
|
|
|
|
$res = "$date ".$file.":".$trace[$loc]['line'];
|
|
|
|
if (!empty($trace[$loc]['class'])) {
|
|
$res .= "---".$trace[$loc]['class'];
|
|
}
|
|
if (!empty($trace[$loc]['function']) && $trace[$loc]['function'] != '_log') {
|
|
$res .= '->'.$trace[$loc]['function'].'()';
|
|
}
|
|
$res .= " $data \n";
|
|
if (php_sapi_name() === 'cli') {
|
|
echo $res;
|
|
}
|
|
global $_config;
|
|
if ($_config['enable_logging'] == true && $_config['log_verbosity'] >= $verbosity) {
|
|
@file_put_contents($_config['log_file'], $res, FILE_APPEND);
|
|
}
|
|
}
|
|
|
|
// converts PEM key to hex
|
|
function pem2hex($data)
|
|
{
|
|
$data = str_replace("-----BEGIN PUBLIC KEY-----", "", $data);
|
|
$data = str_replace("-----END PUBLIC KEY-----", "", $data);
|
|
$data = str_replace("-----BEGIN EC PRIVATE KEY-----", "", $data);
|
|
$data = str_replace("-----END EC PRIVATE KEY-----", "", $data);
|
|
$data = str_replace("\n", "", $data);
|
|
$data = base64_decode($data);
|
|
$data = bin2hex($data);
|
|
return $data;
|
|
}
|
|
|
|
// converts hex key to PEM
|
|
function hex2pem($data, $is_private_key = false)
|
|
{
|
|
$data = hex2bin($data);
|
|
$data = base64_encode($data);
|
|
if ($is_private_key) {
|
|
return "-----BEGIN EC PRIVATE KEY-----\n".$data."\n-----END EC PRIVATE KEY-----";
|
|
}
|
|
return "-----BEGIN PUBLIC KEY-----\n".$data."\n-----END PUBLIC KEY-----";
|
|
}
|
|
|
|
|
|
// Base58 encoding/decoding functions - all credits go to https://github.com/stephen-hill/base58php
|
|
function base58_encode($string)
|
|
{
|
|
$alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
$base = strlen($alphabet);
|
|
// Type validation
|
|
if (is_string($string) === false) {
|
|
return false;
|
|
}
|
|
// If the string is empty, then the encoded string is obviously empty
|
|
if (strlen($string) === 0) {
|
|
return '';
|
|
}
|
|
// Now we need to convert the byte array into an arbitrary-precision decimal
|
|
// We basically do this by performing a base256 to base10 conversion
|
|
$hex = unpack('H*', $string);
|
|
$hex = reset($hex);
|
|
$decimal = gmp_init($hex, 16);
|
|
// This loop now performs base 10 to base 58 conversion
|
|
// The remainder or modulo on each loop becomes a base 58 character
|
|
$output = '';
|
|
while (gmp_cmp($decimal, $base) >= 0) {
|
|
list($decimal, $mod) = gmp_div_qr($decimal, $base);
|
|
$output .= $alphabet[gmp_intval($mod)];
|
|
}
|
|
// If there's still a remainder, append it
|
|
if (gmp_cmp($decimal, 0) > 0) {
|
|
$output .= $alphabet[gmp_intval($decimal)];
|
|
}
|
|
// Now we need to reverse the encoded data
|
|
$output = strrev($output);
|
|
// Now we need to add leading zeros
|
|
$bytes = str_split($string);
|
|
foreach ($bytes as $byte) {
|
|
if ($byte === "\x00") {
|
|
$output = $alphabet[0].$output;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return (string)$output;
|
|
}
|
|
|
|
function base58_decode($base58)
|
|
{
|
|
$alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
$base = strlen($alphabet);
|
|
|
|
// Type Validation
|
|
if (is_string($base58) === false) {
|
|
return false;
|
|
}
|
|
// If the string is empty, then the decoded string is obviously empty
|
|
if (strlen($base58) === 0) {
|
|
return '';
|
|
}
|
|
$indexes = array_flip(str_split($alphabet));
|
|
$chars = str_split($base58);
|
|
// Check for invalid characters in the supplied base58 string
|
|
foreach ($chars as $char) {
|
|
if (isset($indexes[$char]) === false) {
|
|
return false;
|
|
}
|
|
}
|
|
// Convert from base58 to base10
|
|
$decimal = gmp_init($indexes[$chars[0]], 10);
|
|
for ($i = 1, $l = count($chars); $i < $l; $i++) {
|
|
$decimal = gmp_mul($decimal, $base);
|
|
$decimal = gmp_add($decimal, $indexes[$chars[$i]]);
|
|
}
|
|
// Convert from base10 to base256 (8-bit byte array)
|
|
$output = '';
|
|
while (gmp_cmp($decimal, 0) > 0) {
|
|
list($decimal, $byte) = gmp_div_qr($decimal, 256);
|
|
$output = pack('C', gmp_intval($byte)).$output;
|
|
}
|
|
// Now we need to add leading zeros
|
|
foreach ($chars as $char) {
|
|
if ($indexes[$char] === 0) {
|
|
$output = "\x00".$output;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
// converts PEM key to the base58 version used by ARO
|
|
function pem2coin($data)
|
|
{
|
|
$data = str_replace("-----BEGIN PUBLIC KEY-----", "", $data);
|
|
$data = str_replace("-----END PUBLIC KEY-----", "", $data);
|
|
$data = str_replace("-----BEGIN EC PRIVATE KEY-----", "", $data);
|
|
$data = str_replace("-----END EC PRIVATE KEY-----", "", $data);
|
|
$data = str_replace("\n", "", $data);
|
|
$data = base64_decode($data);
|
|
|
|
|
|
return base58_encode($data);
|
|
}
|
|
|
|
// converts the key in base58 to PEM
|
|
function coin2pem($data, $is_private_key = false)
|
|
{
|
|
$data = base58_decode($data);
|
|
$data = base64_encode($data);
|
|
|
|
$dat = str_split($data, 64);
|
|
$data = implode("\n", $dat);
|
|
|
|
if ($is_private_key) {
|
|
return "-----BEGIN EC PRIVATE KEY-----\n".$data."\n-----END EC PRIVATE KEY-----\n";
|
|
}
|
|
return "-----BEGIN PUBLIC KEY-----\n".$data."\n-----END PUBLIC KEY-----\n";
|
|
}
|
|
|
|
// sign data with private key
|
|
function ec_sign($data, $key)
|
|
{
|
|
// transform the base58 key format to PEM
|
|
$private_key = coin2pem($key, true);
|
|
|
|
|
|
$pkey = openssl_pkey_get_private($private_key);
|
|
|
|
$k = openssl_pkey_get_details($pkey);
|
|
|
|
|
|
openssl_sign($data, $signature, $pkey, OPENSSL_ALGO_SHA256);
|
|
|
|
// the signature will be base58 encoded
|
|
return base58_encode($signature);
|
|
}
|
|
|
|
|
|
function ec_verify($data, $signature, $key)
|
|
{
|
|
// transform the base58 key to PEM
|
|
$public_key = coin2pem($key);
|
|
|
|
$signature = base58_decode($signature);
|
|
|
|
$pkey = openssl_pkey_get_public($public_key);
|
|
|
|
$res = openssl_verify($data, $signature, $pkey, OPENSSL_ALGO_SHA256);
|
|
|
|
|
|
if ($res === 1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// POST data to an URL (usualy peer). The data is an array, json encoded with is sent as $_POST['data']
|
|
function peer_post($url, $data = [], $timeout = 60, $debug = false)
|
|
{
|
|
global $_config;
|
|
if ($debug) {
|
|
echo "\nPeer post: $url\n";
|
|
}
|
|
$postdata = http_build_query(
|
|
[
|
|
'data' => json_encode($data),
|
|
"coin" => $_config['coin'],
|
|
]
|
|
);
|
|
|
|
$opts = [
|
|
'http' =>
|
|
[
|
|
'timeout' => $timeout,
|
|
'method' => 'POST',
|
|
'header' => 'Content-type: application/x-www-form-urlencoded',
|
|
'content' => $postdata,
|
|
],
|
|
];
|
|
|
|
$context = stream_context_create($opts);
|
|
|
|
$result = file_get_contents($url, false, $context);
|
|
if ($debug) {
|
|
echo "\nPeer response: $result\n";
|
|
}
|
|
$res = json_decode($result, true);
|
|
|
|
// the function will return false if something goes wrong
|
|
if ($res['status'] != "ok" || $res['coin'] != $_config['coin']) {
|
|
return false;
|
|
}
|
|
return $res['data'];
|
|
}
|
|
|
|
// convers hex to base58
|
|
function hex2coin($hex)
|
|
{
|
|
$data = hex2bin($hex);
|
|
return base58_encode($data);
|
|
}
|
|
|
|
// converts base58 to hex
|
|
function coin2hex($data)
|
|
{
|
|
$bin = base58_decode($data);
|
|
return bin2hex($bin);
|
|
}
|