Fixed DiffieHellman only half-implemented in user admin CP (changing passwords did not work)
authorDan
Mon, 17 Nov 2008 11:25:06 -0500
changeset 742 551b6a0aa3b4
parent 741 a216e412c439
child 743 0acb5d0f8328
Fixed DiffieHellman only half-implemented in user admin CP (changing passwords did not work)
language/english/user.json
plugins/admin/UserManager.php
--- a/language/english/user.json	Sat Nov 15 18:23:25 2008 -0500
+++ b/language/english/user.json	Mon Nov 17 11:25:06 2008 -0500
@@ -84,6 +84,7 @@
       err_key_not_found_cleared: 'It seems that the list of encryption keys used for login information has reached its maximum length, thus preventing new keys from being inserted. The list has been automatically cleared. Please try logging in again; if you are still unable to log in, please contact the site administration.',
       err_dh_key_not_found: 'Enano couldn\'t retrieve the private key used for the high-strength encrypted logon. It is possible that the list of keys was cleared during your logon process as this happens approximately once every 72 hours. Please try logging in again; if you are still unable to log in, please contact the site administration.',
       err_dh_key_not_numeric: 'The Diffie-Hellman public key you sent through was not an arbitrary-precision decimal integer.',
+      err_dh_hash_no_match: 'The Diffie-Hellman key was not calculated correctly by one of the parties (I got a different shared secret than you did).',
       err_key_wrong_length: 'The encryption key was the wrong length.',
       err_too_big_for_britches: 'You are trying to authenticate at a level that your user account does not permit.',
       err_invalid_credentials: 'You have entered an invalid username or password. Please enter your login details again.',
--- a/plugins/admin/UserManager.php	Sat Nov 15 18:23:25 2008 -0500
+++ b/plugins/admin/UserManager.php	Mon Nov 17 11:25:06 2008 -0500
@@ -77,13 +77,66 @@
         if ( $_POST['changing_pw'] == 'yes' )
         {
           $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
-          $key_hex_md5 = $_POST['crypt_key'];
-          $key_hex = $session->fetch_public_key($key_hex_md5);
-          if ( $key_hex )
+          if ( $_POST['dh_supported'] === 'true' )
           {
-            $key_bin = hexdecode($key_hex);
-            $data_hex = $_POST['crypt_data'];
-            $password = $aes->decrypt($data_hex, $key_bin, ENC_HEX);
+            $my_public = $_POST['dh_public'];
+            $remote_public = $_POST['dh_mypublic'];
+            
+            // Check the key
+            if ( !preg_match('/^[0-9]+$/', $my_public) || !preg_match('/^[0-9]+$/', $remote_public) )
+            {
+              $errors[] = $lang->get('user_err_dh_key_not_numeric');
+            }
+            else
+            {
+              // We have our own public key - cross reference it with the private key in the database
+              $q = $db->sql_query('SELECT private_key, key_id FROM ' . table_prefix . "diffiehellman WHERE public_key = '$my_public';");
+              if ( !$q )
+                $db->_die();
+              
+              if ( $db->numrows() < 1 )
+              {
+                $errors[] = $lang->get('user_err_dh_key_not_found');
+              }
+              else
+              {
+                list($my_private, $key_id) = $db->fetchrow_num($q);
+                $db->free_result();
+                // now that we have this key it can be disposed of
+                $q = $db->sql_query("DELETE FROM " . table_prefix . "diffiehellman WHERE key_id = $key_id;");
+                if ( !$q )
+                  $db->_die();
+                // get the shared secret
+                $dh_secret = dh_gen_shared_secret($my_private, $remote_public);
+                global $_math;
+                $dh_secret = $_math->str($dh_secret);
+                
+                // make sure we calculated everything right
+                $secret_check = sha1($dh_secret);
+                if ( $secret_check !== $_POST['crypt_key'] )
+                {
+                  // uh-oh.
+                  $errors[] = $lang->get('user_err_dh_key_not_found');
+                }
+                else
+                {
+                  $aes_key = substr(sha256($dh_secret), 0, ( AES_BITS / 4 ));
+                  $aes_key = hexdecode($aes_key);
+                  $password = $aes->decrypt($_POST['crypt_data'], $aes_key, ENC_HEX);
+                }
+              }
+            }
+          }
+          else if ( $_POST['dh_supported'] === 'false' )
+          {
+            $key_hex_md5 = $_POST['crypt_key'];
+            $key_hex = $session->fetch_public_key($key_hex_md5);
+            if ( $key_hex )
+            {
+              $key_bin = hexdecode($key_hex);
+              $data_hex = $_POST['crypt_data'];
+              $password = $aes->decrypt($data_hex, $key_bin, ENC_HEX);
+            }
           }
           else
           {