]> git.p6c8.net - jirafeau_project.git/commitdiff
Add encryption feature (disabled by default).
authorJerome Jutteau <jerome.jutteau@apbteam.org>
Wed, 24 Jul 2013 12:46:39 +0000 (14:46 +0200)
committerJerome Jutteau <jerome.jutteau@apbteam.org>
Thu, 25 Jul 2013 22:19:46 +0000 (00:19 +0200)
Notes:
- This feature requieres mcrypt module to be installed.
- File dedupliation will stop working (as files are encrypted).
- Server's ressource usage is heavier (encryption/decryption cost).

file.php
lib/config.php
lib/functions.js
lib/functions.php
lib/lang.php
script.php

index 710ce3d36529d5e78d4f210d1cf41ea6c54f30c9..d632beb257161ac7bb864b4393ed36eaceaf9a9f 100644 (file)
--- a/file.php
+++ b/file.php
@@ -33,7 +33,7 @@ if (!isset ($_GET['h']) || empty ($_GET['h']))
 /* Operations may take a long time.
  * Be sure PHP's safe mode is off.
  */
- set_time_limit(0);
+set_time_limit(0);
 
 $link_name = $_GET['h'];
 
@@ -59,6 +59,10 @@ $delete_code = '';
 if (isset ($_GET['d']) && !empty ($_GET['d']))
     $delete_code = $_GET['d'];
 
+$crypt_key = '';
+if (isset ($_GET['k']) && !empty ($_GET['k']))
+    $crypt_key = $_GET['k'];
+
 $button_download = false;
 if (isset ($_GET['bd']) && !empty ($_GET['bd']))
     $button_download = true;
@@ -100,6 +104,15 @@ if ($link['time'] != JIRAFEAU_INFINITY && time () > $link['time'])
     exit;
 }
 
+if (empty ($crypt_key) && $link['crypted'])
+{
+    require (JIRAFEAU_ROOT.'lib/template/header.php');
+    echo '<div class="error"><p>' . t('Sorry, the requested file is not found') .
+    '</p></div>';
+    require (JIRAFEAU_ROOT.'lib/template/footer.php');
+    exit;
+}
+
 $password_challenged = false;
 if (!empty ($link['key']))
 {
@@ -107,8 +120,10 @@ if (!empty ($link['key']))
     {
         require (JIRAFEAU_ROOT.'lib/template/header.php');
         echo '<div>' .
-             '<form action = "' . $_SERVER['REQUEST_URI'] . '" ' .
-                'method = "post" id = "submit">'; ?>
+             '<form action = "';
+        echo $cfg['web_root'] . '/file.php';
+        echo '" ' .
+             'method = "post" id = "submit">'; ?>
              <input type = "hidden" name = "jirafeau" value = "<?php echo JIRAFEAU_VERSION ?>"/><?php
         echo '<fieldset>' .
              '<legend>' . t('Password protection') .
@@ -121,14 +136,23 @@ if (!empty ($link['key']))
              '</td></tr>' .
              '<tr><td>';
             ?><input type="submit" id = "submit_download"  value="<?php echo t('Download'); ?>"
-            onclick="document.getElementById('submit').action='<?php echo $_SERVER['REQUEST_URI'] ?>&amp;bd=1';
-                     document.getElementById('submit_download').submit ();"/><?php
-
+            onclick="document.getElementById('submit').action='
+<?php
+        echo $cfg['web_root'] . '/file.php?h=' . $link_name . '&amp;bd=1';
+        if (!empty($crypt_key))
+            echo '&amp;k=' . urlencode($crypt_key);
+?>';
+        document.getElementById('submit_download').submit ();"/><?php
         if ($cfg['download_page'] && $cfg['preview'])
         {
             ?><input type="submit" id = "submit_preview"  value="<?php echo t('Preview'); ?>"
-            onclick="document.getElementById('submit').action='<?php echo $_SERVER['REQUEST_URI'] ?>&amp;bp=1';
-                     document.getElementById('submit_preview').submit ();"/><?php
+            onclick="document.getElementById('submit').action='
+<?php
+        echo $cfg['web_root'] . '/file.php?h=' . $link_name . '&amp;bp=1';
+        if (!empty($crypt_key))
+            echo '&amp;k=' . urlencode($crypt_key);
+?>';
+        document.getElementById('submit_preview').submit ();"/><?php
         }
         echo '</td></tr></table></fieldset></form></div>';
         require (JIRAFEAU_ROOT.'lib/template/footer.php');
@@ -136,7 +160,9 @@ if (!empty ($link['key']))
     }
     else
     {
-        if ($link['key'] != md5 ($_POST['key']))
+        if ($link['key'] == md5 ($_POST['key']))
+            $password_challenged = true;
+       else
         {
             header ("Access denied");
             require (JIRAFEAU_ROOT.'lib/template/header.php');
@@ -145,8 +171,6 @@ if (!empty ($link['key']))
             require (JIRAFEAU_ROOT.'lib/template/footer.php');
             exit;
         }
-        else
-            $password_challenged = true;
     }
 }
 
@@ -154,8 +178,10 @@ if ($cfg['download_page'] && !$password_challenged && !$button_download && !$but
 {
         require (JIRAFEAU_ROOT.'lib/template/header.php');
         echo '<div>' .
-             '<form action = "' . $_SERVER['REQUEST_URI'] . '" ' .
-                'method = "post" id = "submit">'; ?>
+             '<form action = "';
+        echo $cfg['web_root'] . '/file.php';
+        echo '" ' .
+             'method = "post" id = "submit">'; ?>
              <input type = "hidden" name = "jirafeau" value = "<?php echo JIRAFEAU_VERSION ?>"/><?php
         echo '<fieldset><legend>' . $link['file_name'] . '</legend><table>' .
              '<tr><td>' .
@@ -164,14 +190,24 @@ if ($cfg['download_page'] && !$password_challenged && !$button_download && !$but
              '<tr><td>' .
              t('By using our services, you accept of our'). ' <a href="' . $cfg['web_root'] . '/tos.php' . '">' . t('Term Of Service') . '</a>';
             ?><input type="submit" id = "submit_download"  value="<?php echo t('Download'); ?>"
-            onclick="document.getElementById('submit').action='<?php echo $_SERVER['REQUEST_URI'] ?>&amp;bd=1';
-                     document.getElementById('submit_download').submit ();"/><?php
+            onclick="document.getElementById('submit').action='
+<?php
+        echo $cfg['web_root'] . '/file.php?h=' . $link_name . '&amp;bd=1';
+        if (!empty($crypt_key))
+            echo '&amp;k=' . urlencode($crypt_key);
+?>';
+        document.getElementById('submit_download').submit ();"/><?php
 
         if ($cfg['download_page'] && $cfg['preview'])
         {
             ?><input type="submit" id = "submit_preview"  value="<?php echo t('Preview'); ?>"
-            onclick="document.getElementById('submit').action='<?php echo $_SERVER['REQUEST_URI'] ?>&amp;bp=1';
-                     document.getElementById('submit_preview').submit ();"/><?php
+            onclick="document.getElementById('submit').action='
+<?php
+        echo $cfg['web_root'] . '/file.php?h=' . $link_name . '&amp;bp=1';
+        if (!empty($crypt_key))
+            echo '&amp;k=' . urlencode($crypt_key);
+?>';
+        document.getElementById('submit_preview').submit ();"/><?php
         }
         echo '</td></tr>';
         echo '</table></fieldset></form></div>';
@@ -187,16 +223,41 @@ if (!jirafeau_is_viewable ($link['mime_type']) || !$cfg['preview'] || $button_do
 else
     header ('Content-Type: ' . $link['mime_type']);
 
-/* Read file */
-$r = fopen (VAR_FILES . $p . $link['md5'], 'r');
-while (!feof ($r))
+/* Read encrypted file. */
+if ($link['crypted'])
+{
+    /* Extract key and iv. */
+    $ex = explode (".", $crypt_key);
+    $key = $ex[0];
+    $iv = base64_decode($ex[1]);
+    error_log ("crypt_key: " . $crypt_key . " iv: " . $v . " key: ". $key . "\n", 3, "debug.log");
+    /* Init module */
+    $m = mcrypt_module_open('rijndael-256', '', 'ofb', '');
+    mcrypt_generic_init($m, $key, $iv);
+    /* Decrypt file. */
+    $r = fopen (VAR_FILES . $p . $link['md5'], 'r');
+    while (!feof ($r))
+    {
+        $dec = mdecrypt_generic($m, fread ($r, 1024));
+        print $dec;
+        ob_flush();
+    }
+    fclose ($r);
+    /* Cleanup. */
+    mcrypt_generic_deinit($m);
+    mcrypt_module_close($m);
+}
+/* Read file. */
+else
 {
-    print fread ($r, 1024);
-    ob_flush();
+    $r = fopen (VAR_FILES . $p . $link['md5'], 'r');
+    while (!feof ($r))
+    {
+        print fread ($r, 1024);
+        ob_flush();
+    }
+    fclose ($r);
 }
-fclose ($r);
-
-//readfile (VAR_FILES . $p . $link['md5']);
 
 if ($link['onetime'] == 'O')
     jirafeau_delete_link ($link_name);
index e80eefc324f955402a4750eb62196b43f8ee2943..790ae16f7df331e6dbf37404bf32d5e3bc128541 100644 (file)
@@ -47,6 +47,11 @@ $cfg['download_page'] = false;
    The scripting interface can propose to create, read, write, delete blocks
    of data. */
 $cfg['enable_blocks'] = false;
+/* Encryption feature. disabled by default.
+ * This feature needs to have mcrypt php module installed.
+ * Note: activating encryption will make file-deduplication to fail.
+ */
+$cfg['enable_crypt'] = false;
 
 if ((basename (__FILE__) != 'config.local.php')
     && file_exists (JIRAFEAU_ROOT.'lib/config.local.php'))
index 2dcde55f39528ced6dfc9e1b02a1cc085de0f4e2..2aa3bd68c9975115b48932bc36269857a54ea548 100755 (executable)
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-function show_link (url, reference, delete_code, date)
+function show_link (url, reference, delete_code, crypt_key, date)
 {
     var download_link = url + 'file.php?h=' + reference;
-    var delete_link = download_link + '&amp;d=' + delete_code;
-    var delete_link_href = download_link + '&d=' + delete_code;
+    var download_link_href = url + 'file.php?h=' + reference;
+    if (crypt_key.length > 0)
+    {
+        download_link += '&amp;k=' + crypt_key;
+        download_link_href += '&k=' + crypt_key;
+    }
+
+    var delete_link = url + 'file.php?h=' + reference + '&amp;d=' + delete_code;
+    var delete_link_href = url + 'file.php?h=' + reference + '&d=' + delete_code;
+
     document.getElementById('upload_link').innerHTML = download_link;
-    document.getElementById('upload_link').href = download_link;
+    document.getElementById('upload_link').href = download_link_href;
     document.getElementById('delete_link').innerHTML = delete_link;
     document.getElementById('delete_link').href = delete_link_href;
     if (date)
@@ -52,8 +60,11 @@ function upload_progress (e)
     /* Show the user the operation do not reach 100%, the server need time
      * to give a response before providing the link.
      */
-    var p = Math.round (e.loaded * 99 / e.total);
-    show_upload_progression (p.toString() + '%');
+    var p = Math.round (e.loaded * 100 / e.total);
+    if (p == 100)
+        show_upload_progression ('Finalizing ...');
+    else
+        show_upload_progression (p.toString() + '%');
 }
 
 function upload_failed (e)
@@ -91,10 +102,10 @@ function classic_upload (url, file, time, password, one_time)
                     d.setSeconds (d.getSeconds() + 2419200);
                 else
                     return;
-                show_link (url, res[0], res[1], d.toString());
+                show_link (url, res[0], res[1], res[2], d.toString());
             }
             else
-                show_link (url, res[0], res[1]);
+                show_link (url, res[0], res[1], res[2]);
         }
     }
     req.open ("POST", url + 'script.php' , true);
@@ -167,8 +178,11 @@ function async_upload_progress (e)
 {
     if (!e.lengthComputable && async_global_file.size != 0)
         return;
-    var p = Math.round ((e.loaded + async_global_transfered) * 99 / (async_global_file.size));
-    show_upload_progression (p.toString() + '%');
+    var p = Math.round ((e.loaded + async_global_transfered) * 100 / (async_global_file.size));
+    if (p == 100)
+        show_upload_progression ('Finalizing...');
+    else
+        show_upload_progression (p.toString() + '%');
 }
 
 function async_upload_push (code)
@@ -197,7 +211,7 @@ function async_upload_push (code)
     }
     req.open ("POST", async_global_url + 'script.php?push_async' , true);
 
-    var chunk_size = parseInt (async_global_max_size * 0.90);
+    var chunk_size = parseInt (async_global_max_size * 0.50);
     var start = async_global_transfered;
     var end = start + chunk_size;
     if (end >= async_global_file.size)
@@ -240,10 +254,10 @@ function async_upload_end (code)
                     d.setSeconds (d.getSeconds() + 2419200);
                 else
                     return;
-                show_link (async_global_url, res[0], res[1], d.toString());
+                show_link (async_global_url, res[0], res[1], res[2], d.toString());
             }
             else
-                show_link (async_global_url, res[0], res[1]);
+                show_link (async_global_url, res[0], res[1], res[2]);
         }
     }
     req.open ("POST", async_global_url + 'script.php?end_async' , true);
index 96f4c2faa77d76a1ecca51c5c9cbd20f43473b9f..c07b6c93046bdc4c6c584b7602e213a83c727d24 100755 (executable)
@@ -306,13 +306,14 @@ jirafeau_delete_file ($md5)
  * @param $key if not empty, protect the file with this key
  * @param $time the time of validity of the file
  * @param $ip uploader's ip
+ * @param $crypt boolean asking to crypt or not
  * @returns an array containing some information
  *   'error' => information on possible errors
  *   'link' => the link name of the uploaded file
  *   'delete_link' => the link code to delete file
  */
 function
-jirafeau_upload ($file, $one_time_download, $key, $time, $ip)
+jirafeau_upload ($file, $one_time_download, $key, $time, $ip, $crypt)
 {
     if (empty ($file['tmp_name']) || !is_uploaded_file ($file['tmp_name']))
     {
@@ -327,6 +328,16 @@ jirafeau_upload ($file, $one_time_download, $key, $time, $ip)
     /* array representing no error */
     $noerr = array ('has_error' => false, 'why' => '');
 
+    /* Crypt file if option is enabled. */
+    $crypted = false;
+    $crypt_key = '';
+    if ($crypt == true && extension_loaded('mcrypt'))
+    {
+        $crypt_key = jirafeau_encrypt_file ($file['tmp_name'], $file['tmp_name']);
+        if (strlen($crypt_key) > 0)
+            $crypted = true;
+    }
+
     /* file informations */
     $md5 = md5_file ($file['tmp_name']);
     $name = str_replace (NL, '', trim ($file['name']));
@@ -370,7 +381,7 @@ jirafeau_upload ($file, $one_time_download, $key, $time, $ip)
     /* Create delete code. */
     $delete_link_code = jirafeau_gen_random (8);
 
-    /* md5 password or empty */
+    /* md5 password or empty. */
     $password = '';
     if (!empty ($key))
         $password = md5 ($key);
@@ -381,7 +392,7 @@ jirafeau_upload ($file, $one_time_download, $key, $time, $ip)
     fwrite ($handle,
             $name . NL. $mime_type . NL. $size . NL. $password . NL. $time .
             NL . $md5. NL . ($one_time_download ? 'O' : 'R') . NL . date ('U') .
-            NL . $ip . NL. $delete_link_code . NL);
+            NL . $ip . NL. $delete_link_code . NL . ($crypted ? 'C' : 'O'));
     fclose ($handle);
     $md5_link = base_16_to_64 (md5_file ($link_tmp_name));
     $l = s2p ("$md5_link");
@@ -411,7 +422,8 @@ jirafeau_upload ($file, $one_time_download, $key, $time, $ip)
     }
    return (array ('error' => $noerr,
                   'link' => $md5_link,
-                  'delete_link' => $delete_link_code));
+                  'delete_link' => $delete_link_code,
+                  'crypt_key' => $crypt_key));
 }
 
 /**
@@ -533,6 +545,8 @@ jirafeau_get_link ($hash)
     $out['upload_date'] = trim ($c[7]);
     $out['ip'] = trim ($c[8]);
     $out['link_code'] = trim ($c[9]);
+    if (trim ($c[10]) == 'C')
+           $out['crypted'] = true;
     
     return $out;
 }
@@ -867,10 +881,11 @@ jirafeau_async_push ($ref, $data, $code)
   * Finalyze an asynchronous upload.
   * @param $ref asynchronous upload reference
   * @param $code client code for this operation
+  * @param $crypt boolean asking to crypt or not
   * @return  a string containing the download reference followed by a delete code or the string "Error"
   */
 function
-jirafeau_async_end ($ref, $code)
+jirafeau_async_end ($ref, $code, $crypt)
 {
     /* Get async infos. */
     $a = jirafeau_get_async_ref ($ref);
@@ -882,6 +897,16 @@ jirafeau_async_end ($ref, $code)
     $p = VAR_ASYNC . s2p ($ref) . $ref . "_data";
     if (!file_exists($p))
         return "Error";
+
+    $crypted = false;
+    $crypt_key = '';
+    if ($crypt == true && extension_loaded('mcrypt'))
+    {
+        $cypt_key = jirafeau_encrypt_file ($p, $p);
+        if (strlen($crypt_key) > 0)
+            $crypted = true;
+    }
+
     $md5 = md5_file ($p);
     $size = filesize($p);
     $np = s2p ($md5);
@@ -911,7 +936,7 @@ jirafeau_async_end ($ref, $code)
     fwrite ($handle,
             $a['file_name'] . NL . $a['mime_type'] . NL . $size . NL .
             $a['key'] . NL . $a['time'] . NL . $md5 . NL . $a['onetime'] . NL .
-            date ('U') . NL . $a['ip'] . NL . $delete_link_code . NL);
+            date ('U') . NL . $a['ip'] . NL . $delete_link_code . NL . ($crypted ? 'C' : 'O'));
     fclose ($handle);
     $md5_link = base_16_to_64 (md5_file ($link_tmp_name));
     $l = s2p ("$md5_link");
@@ -921,7 +946,7 @@ jirafeau_async_end ($ref, $code)
     
     /* Clean async upload. */
     jirafeau_async_delete ($ref);
-    return $md5_link . NL . $delete_link_code;
+    return $md5_link . NL . $delete_link_code . NL . urlencode($crypt_key);
 }
 
 /**
@@ -1264,5 +1289,80 @@ jirafeau_admin_clean_block ()
     return $count;
 }
 
+/**
+ * Crypt file and returns decrypt key.
+ * @param $fp_src file path to the file to crypt.
+ * @param $fp_dst file path to the file to write crypted file (could be the same).
+ * @return decrypt key composed of the key and the iv separated by a point ('.')
+ */
+function
+jirafeau_encrypt_file ($fp_src, $fp_dst)
+{
+    $fs = filesize ($fp_src);
+    if ($fs === false || $fs == 0 || !extension_loaded('mcrypt'))
+        return '';
+
+    /* Prepare module. */
+    $m = mcrypt_module_open('rijndael-256', '', 'ofb', '');
+    $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($m), MCRYPT_DEV_URANDOM);
+    /* Generate key. */
+    $ks = mcrypt_enc_get_key_size($m);
+    $key = substr(md5(jirafeau_gen_random(12)), 0, $ks);
+    /* Init module. */
+    mcrypt_generic_init($m, $key, $iv);
+    /* Crypt file. */
+    $r = fopen ($fp_src, 'r');
+    $w = fopen ($fp_dst, 'c');
+    while (!feof ($r))
+    {
+        $enc = mcrypt_generic($m, fread ($r, 1024));
+        if (fwrite ($w, $enc) === false)
+            return '';
+    }
+    fclose ($r);
+    fclose ($w);
+    /* Cleanup. */
+    mcrypt_generic_deinit($m);
+    mcrypt_module_close($m);
+    return $key . "." . base64_encode($iv);
+}
+
+/**
+ * Decrypt file.
+ * @param $fp_src file path to the file to decrypt.
+ * @param $fp_dst file path to the file to write decrypted file (could be the same).
+ * @param $k string composed of the key and the iv separated by a point ('.')
+ * @return key used to decrypt. a string of length 0 is returned if failed.
+ */
+function
+jirafeau_decrypt_file ($fp_src, $fp_dst, $k)
+{
+    $fs = filesize ($fp_src);
+    if ($fs === false || $fs == 0 || !extension_loaded('mcrypt'))
+        return false;
+
+    /* Extract key and iv. */
+    $ex = explode (".", $k);
+    $key = $ex[0];
+    $iv = base64_decode($ex[1]);
+    /* Init module */
+    $m = mcrypt_module_open('rijndael-256', '', 'ofb', '');
+    mcrypt_generic_init($m, $key, $iv);
+    /* Decrypt file. */
+    $r = fopen ($fp_src, 'r');
+    $w = fopen ($fp_dst, 'c');
+    while (!feof ($r))
+    {
+        $dec = mdecrypt_generic($m, fread ($r, 1024));
+        if (fwrite ($w, $dec) === false)
+            return false;
+    }
+    fclose ($r);
+    fclose ($w);
+    /* Cleanup. */
+    mcrypt_generic_deinit($m);
+    mcrypt_module_close($m);
+    return true;
+}
 
 ?>
index 6e592a29de22cae0d4c041a6fc6a76fbe8cbd142..bf74e8d77a4acef42c7161a547b2e6f4052e81ae 100755 (executable)
@@ -54,4 +54,4 @@ function t ($text)
     return ($text);\r
 }\r
 \r
-?>
\ No newline at end of file
+?>\r
index a6b9457e5f9bfb035253a6a77cf8784136fcd05e..7d5e25c37d5238f78f436371892c398ebb0177a1 100755 (executable)
@@ -292,7 +292,8 @@ if (isset ($_FILES['file']) && is_writable (VAR_FILES)
         }\r
     $res = jirafeau_upload ($_FILES['file'],\r
                             isset ($_POST['one_time_download']),\r
-                            $key, $time, $_SERVER['REMOTE_ADDR']);\r
+                            $key, $time, $_SERVER['REMOTE_ADDR'],\r
+                            $cfg['enable_crypt']);\r
     \r
     if (empty($res) || $res['error']['has_error'])\r
     {\r
@@ -301,9 +302,12 @@ if (isset ($_FILES['file']) && is_writable (VAR_FILES)
     }\r
     /* Print direct link. */\r
     echo $res['link'];\r
-    echo NL;\r
     /* Print delete link. */\r
+    echo NL;\r
     echo $res['delete_link'];\r
+    /* Print decrypt key. */\r
+    echo NL;\r
+    echo urlencode($res['crypt_key']);\r
 }\r
 elseif (isset ($_GET['h']))\r
 {\r
@@ -580,7 +584,7 @@ elseif (isset ($_GET['end_async']))
         || !isset ($_POST['code']))\r
         echo "Error";\r
     else\r
-        echo jirafeau_async_end ($_POST['ref'], $_POST['code']);\r
+        echo jirafeau_async_end ($_POST['ref'], $_POST['code'], $cfg['enable_crypt']);\r
 }\r
 /* Initialize block. */\r
 elseif (isset ($_GET['init_block']) && $cfg['enable_blocks'])\r

patrick-canterino.de