diff --git a/encoder/firewall.php b/encoder/firewall.php
index e2276e0..0400651 100644
--- a/encoder/firewall.php
+++ b/encoder/firewall.php
@@ -93,79 +93,67 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
diff --git a/encoder/firmware.php b/encoder/firmware.php
index ed20340..324ffcd 100755
--- a/encoder/firmware.php
+++ b/encoder/firmware.php
@@ -18,6 +18,97 @@ switch ($_POST['action']) {
case 'reboot':
exec('sudo reboot');
break;
+ case 'backup':
+
+ $jsonFiles = [
+ 'input.json',
+ 'output.json',
+ 'firewall.json',
+ 'network.json',
+ 'firmware.json',
+ ];
+
+ $tmpZip = sys_get_temp_dir() . '/backup.zip';
+ $outputFile = __DIR__ . '/universal_encoder_decoder.bin';
+
+ $publicKey = file_get_contents('/var/www/public.pem');
+ $publicKey = file_get_contents('/var/www/public.pem');
+
+ $zip = new ZipArchive();
+ $zip->open($tmpZip, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+
+ $files = new RecursiveIteratorIterator(
+ new RecursiveDirectoryIterator($sourceDir, FilesystemIterator::SKIP_DOTS)
+ );
+
+ foreach ($files as $file) {
+ $zip->addFile(
+ $file->getRealPath(),
+ substr($file->getRealPath(), strlen($sourceDir) + 1)
+ );
+ }
+
+ /* Add JSON files if exist */
+ foreach ($jsonFiles as $json) {
+ if (file_exists($json)) {
+ $zip->addFile($json, basename($json));
+ }
+ }
+
+ $zip->close();
+ $data = file_get_contents($tmpZip);
+
+ /* Generate AES key */
+ $aesKey = random_bytes(32);
+ $iv = random_bytes(16);
+
+ /* Encrypt ZIP */
+ $encryptedData = openssl_encrypt(
+ $data,
+ 'AES-256-CBC',
+ $aesKey,
+ OPENSSL_RAW_DATA,
+ $iv
+ );
+
+ /* Encrypt AES key using RSA public key */
+ openssl_public_encrypt($aesKey, $encryptedKey, $publicKey);
+
+ /* Final binary format */
+ $payload = json_encode([
+ 'key' => base64_encode($encryptedKey),
+ 'iv' => base64_encode($iv),
+ 'data' => base64_encode($encryptedData)
+ ]);
+
+ $filename = 'universal_encoder_decoder.bin';
+
+ header('Content-Description: File Transfer');
+ header('Content-Type: application/octet-stream');
+ header('Content-Disposition: attachment; filename="' . $filename . '"');
+ header('Content-Length: ' . strlen($payload));
+ header('Cache-Control: no-store, no-cache, must-revalidate');
+ header('Pragma: no-cache');
+ header('Expires: 0');
+
+ echo $payload;
+ flush();
+
+ unlink($tmpZip);
+
+ break;
+
+ case 'restore':
+ $inputFile = __DIR__ . '/universal_encoder_decoder.bin';
+ $restoreDir = __DIR__ . '/var/www/encoder/';
+ $tmpZip = sys_get_temp_dir() . '/restore.zip';
+
+ $privateKey = file_get_contents(__DIR__ . '/keys/private.pem');
+
+ if (!file_exists($inputFile)) {
+ die("Backup file not found\n");
+ }
+ break;
}
$board_id = trim(@file_get_contents('/sys/class/dmi/id/board_serial'));
diff --git a/encoder/private.pem b/encoder/private.pem
new file mode 100644
index 0000000..4e724ec
--- /dev/null
+++ b/encoder/private.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+oo7uGCyxw179QUUzXs18xVnordQGvA==
+-----END PRIVATE KEY-----
diff --git a/encoder/public.pem b/encoder/public.pem
new file mode 100644
index 0000000..ead2b54
--- /dev/null
+++ b/encoder/public.pem
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmkrmuGyijJ/IV86B/Gnx
+lI3QHeVriwWZPF+C/fC8TDeHz3MuzcDj5RG+iVDZwXK27TmGwPvmzrl4aCzDSz0C
+YV6Uj1dgXcrvbbQ2dx0hIk5fGmrkIsTXnNi8QWl3VZfQabT2D8vTBNLjEZZP0WYF
+JkB7OvjZmUtNjC1B9R/ITloHLHteTFy3W+WUUsKrI7C57gCnsq2422HQG147/YUE
+UDHhcHyP3Qcj879U2eQmySfIUTuLp81ywseV01X8hW4WgoQgCYt9hQmUlsLTxCF9
+/1cbv0ngDt2fD0nQxDz4qxVGJBFfiQd5t07NHbGAhaO/Ek2vyoZjJBhLQHSvj3ts
+1nfGeXC4Ngx7UETsiyfohl++u5DzgdOD5RvqyUw2BzmQQDICr+A8YgzESoUTReJd
+wg4irZwN+Wrum47loIrHk34ELkbibfRiu7Zzfq+kXFD0VbNWLP9RLyQy3eHvVQIm
+a2hC5xaaxNzf6Idxek1Q01K/2wmPvkRiwhBTmOYlEP+BZyRzjWxWEXWGvIGtoH2W
+APl9sdurYXZ9K46I+TqZeSvwEO5ew2M9lSYxvmU2AFdGOxa2/RwxLKGWt/6Kg5Ww
+e45Ord2W8TfS6QzgyE6n4nfIS5VEZthfblv8FOBlVnNA9J52Z2qFzy9JwG0FmbsK
+StOkIiCMQyrPzLCEH2iJTSsCAwEAAQ==
+-----END PUBLIC KEY-----