public function post() { \header('Content-Type: application/json'); if (!empty($_POST['message']) && !empty($_POST['signature']) && !empty($_POST['prevhash']) && !empty($_POST['merkleroot']) && !empty($_POST['block'])) { // Plausibly a message from the mother ship? Let's check our $signature = \base64_decode($_POST['signature']); $message = \base64_decode($_POST['message']); $pubkey = \base64_decode(\ParagonIE\AsgardClient\MetaData::AUTHORIZED_PUBLICKEY); if (\Sodium::crypto_sign_verify_detached($signature, $message, $pubkey)) { // Should be the same as a new message $re_encode = \json_encode(['signature' => $_POST['signature'], 'message' => $_POST['message']], JSON_PRETTY_PRINT); return $this->insertBlock($re_encode, $_POST['merkleroot'], $_POST['block'], $_POST['prevhash']); } } // Usual case: You are not l33t enough to grab our priv8 key echo \json_encode(['error' => 'Access denied.'], JSON_PRETTY_PRINT); exit; }
/** * Verify the signature of a block * * @param type $block */ private function verifySignature($block) { $signed = \Sodium::crypto_sign_verify_detached(\base64_decode($block['signature']), \base64_decode($block['message']), \base64_decode(Base\MetaData::AUTHORIZED_PUBLICKEY)); if ($signed === false) { die("Signature verification failed!"); } return \json_decode(\base64_decode($block['message']), true); }
/** * Verify new blocks with our peers * * @param array $newBlocks * @param boolean $echo */ private function peerPressure($newBlocks, $echo = false) { if ($echo) { echo "\n\tVerifying new blocks...\n"; } // SELECT hash FROM blocks ORDER BY id DESC $lasthash = $this->bc->selectOne('blocks', ['hash'], [], [['id', 'DESC']], [], 0, 1); // SELECT * FROM notaries $notaries = $this->db->select('notaries'); $consensus = ['fail' => 0, 'timeout' => 0, 'pass' => 0]; foreach ($notaries as $peer) { $hostname = $peer['https'] > 0 ? 'https://' . $peer['host'] . ':' . $peer['port'] : 'http://' . $peer['host'] . ':' . $peer['port']; $net = new Base\HTTPS($hostname); $body = $net->get('/blockchain/hash/' . $lasthash); if (!empty($body)) { $response = \json_decode($body, true); } else { ++$consensus['timeout']; continue; } if (!empty($response['message']) && !empty($response['signature'])) { // Let's grab everything we need to verify the detached signature $msg = \base64_decode($response['message']); $sig = \base64_decode($response['signature']); $pubkey = \base64_decode($peer['publickey']); if (\Sodium::crypto_sign_verify_detached($sig, $msg, $pubkey)) { // At this point, we know the signature was valid. $analysis = $this->analyzePeerResponse(\json_decode($msg, true), $newBlocks, $peer, $echo); if ($analysis) { ++$consensus['pass']; // Don't run the last line of the loop continue; } } elseif ($echo) { echo $this->c['red'], 'Peer signature failed: ', $peer['nickname'], $this->c[''], "\n"; } } elseif ($echo) { echo $this->c['red'], 'Peer connection failed or response invalid: ', $peer['nickname'], $this->c[''], "\n"; } // When something fails, increment it here. ++$consensus['fail']; } // After the foreach loop runs, decide whether or not to proceed. if ($consensus['fail'] === 0 && $consensus['pass'] > 0) { // No failures, at least 1 success return true; } if ($echo) { echo $this->c['red'], 'An error has occurred!', $this->c[''], "\n", 'Attempting to synchronize the distributed ledger failed!', "\n"; } return false; }