title: Android Webview, formhash not working on some Android devices
body: <p>I've been developing a web application on Android and iOS and working with a web view. Everything is working fine on the iPhone, but on Android it is not working on all devices and it is driving me crazy. On five Android devices it's working great, but on two devices it doesn't go further than the login page. However it does work on the mobile site (not app) in the browser.</p>
  
  <p>The devices where the mobile app is not working on are HTC One (v4.3) and Acer Liquid Z3 (v4.2). Another device also HTC One (v4.3) it does work on and this makes the problem very difficult to understand and solve.</p>
  
  <p>The first window when the application is opened is a simple login window. On the devices where it isn't working, it just reloads the page and the user can login again. The login information are checked with the details in a database. When it does work (or opened in the browser) it loads to a new page.</p>
  
  <p>MainActivity.java:</p>
  
  <pre><code>public class MainActivity extends Activity {
  
  WebView mWebView;
  private ProgressBar loadingProgressBar;
  
  @SuppressLint("SetJavaScriptEnabled")
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
  
      requestWindowFeature(Window.FEATURE_NO_TITLE);
      getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
              WindowManager.LayoutParams.FLAG_FULLSCREEN);
  
      setContentView(R.layout.activity_main);
  
      mWebView = (WebView) findViewById(R.id.webview);
  
      mWebView.getSettings().setJavaScriptEnabled(true);
      mWebView.setWebViewClient(new DivumWebViewClient());
  
      mWebView.loadUrl("http://www.xxxx.com/index.php");
  
      loadingProgressBar = (ProgressBar) findViewById(R.id.progressbar_title);
      mWebView.setWebChromeClient(new WebChromeClient() {
          @Override
          public void onProgressChanged(WebView view, int newProgress) {
              super.onProgressChanged(view, newProgress);
              loadingProgressBar.setProgress(newProgress);
              if (newProgress == 100) {
                  loadingProgressBar.setVisibility(View.GONE);
              } else {
                  loadingProgressBar.setVisibility(View.VISIBLE);
              }
          }
      });
  
  }
  
  private class DivumWebViewClient extends WebViewClient {
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
          view.loadUrl(url);
          return true;
      }
  }
  }
  </code></pre>
  
  <p>index.php</p>
  
  <pre><code>.....
  &lt;body class="blue-bg"&gt;
  &lt;?php
  if (isset($_GET['error'])) {
      echo '&lt;p class="error"&gt;Error Logging In!&lt;/p&gt;';
  } 
  sec_session_start(); 
  if (isset($_POST['email'], $_POST['p'])) {
      $email = $_POST['email'];
      $password = $_POST['p']; 
  
      if (login($email, $password, $mysqli) == true) {
          // Login success 
          header('Location: dashboard.php');
          exit;
      } else if(login($email, $password, $mysqli) == false){
          $error['error'] = "&lt;p&gt;Enter login details:&lt;/p&gt;\n";
      }
  } 
  ?&gt;  
  &lt;div class="signin" style="margin-top: 0;"&gt;
  
      &lt;div class="signin-body"&gt;
  
          &lt;a href="index.php" title="Login" class="pull-right"&gt;
              &lt;img src="../assets/images/logo.jpg" title="Login" alt="Login"&gt;
          &lt;/a&gt;
          &lt;br&gt;&lt;h3&gt;Login&lt;/h3&gt;
          &lt;?=$error['error']?&gt;
          &lt;form action="&lt;?=$_SERVER['PHP_SELF']?&gt;" id="login-validatie" method="post"        name="login_form"&gt;                  
              &lt;div class="form-group"&gt;
               &lt;input type="text" class="form-control" placeholder="Emailadres" name="email" id="email"&gt;
              &lt;/div&gt;
  
              &lt;div class="form-group"&gt;
               &lt;input type="password" class="form-control" placeholder="Wachtwoord" name="password" id="password"&gt;
              &lt;/div&gt;
  
  
              &lt;div class="form-group clearfix"&gt;
              &lt;input type="submit" onclick="formhash(this.form, this.form.password);" class="btn btn-med blue-bg pull-right" value="Inloggen"&gt;
              &lt;/div&gt;
  
              &lt;hr&gt;          
          &lt;/form&gt;
  
      &lt;/div&gt;
  
  &lt;/div&gt;
  &lt;script src="../assets/js/scripts.js"&gt;&lt;/script&gt;    
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>I don't know if it a bug or something. It is strange it works on most devices, but not on some devices. It also works in the browser, which makes me think it has something to do with the web view in Android. I am at a dead end and appreciate every help. Thanks!</p>
  
  <p><strong>update</strong>
  I've finally tracked where the problem lies and it has to do with form hashing. The password gives a different sha512 hash on some Android devices within the webview which makes it impossible to login. Don't know if it is a limitation of Android's web view on some devices, does anyone know how to solve this?  </p>
  
  <p>forms.js</p>
  
  <pre><code>function formhash(form, password) {
      // Create a new element input, this will be our hashed password field. 
      var p = document.createElement("input");
  
      // Add the new element to our form. 
      p.name = "p";
      p.type = "hidden";
      p.value = hex_sha512(password.value);
  
      form.appendChild(p);
  
      // Make sure the plaintext password doesn't get sent. 
      password.value = "";
  
      // Finally submit the form. 
      form.submit();
  }
  </code></pre>
  
  <p>functions.php</p>
  
  <pre><code>function login($email, $password, $mysqli) {
      // Using prepared statements means that SQL injection is not possible. 
      if ($stmt = $mysqli-&gt;prepare("SELECT id, username, password, salt FROM x WHERE email = ? LIMIT 1")) {
          $stmt-&gt;bind_param('s', $email);  // Bind "$email" to parameter.
          $stmt-&gt;execute();    // Execute the prepared query.
          $stmt-&gt;store_result();
  
          // get variables from result.
          $stmt-&gt;bind_result($user_id, $username, $db_password, $salt);
          $stmt-&gt;fetch();
  
          // hash the password with the unique salt.
          $password = hash('sha512', $password . $salt);
          ?&gt;&lt;script&gt; var x; x = "&lt;?php print($password); ?&gt;"; console.log("Logging: password is " + x); &lt;/script&gt;&lt;?
  
          if ($stmt-&gt;num_rows == 1) {
              // If the user exists we check if the account is locked
              // from too many login attempts 
  
              if (checkbrute($user_id, $mysqli) == true) {
                  // Account is locked 
                  // Send an email to user saying their account is locked
                  return false;
              } else {
                  // Check if the password in the database matches
                  // the password the user submitted.
                  if ($db_password == $password) {
                      // Password is correct!
                      // Get the user-agent string of the user.
                      $user_browser = $_SERVER['HTTP_USER_AGENT'];
                      // XSS protection as we might print this value
                      $user_id = preg_replace("/[^0-9]+/", "", $user_id);
                      $_SESSION['user_id'] = $user_id;
                      // XSS protection as we might print this value
                      $username = preg_replace("/[^a-zA-Z0-9_\-]+/", 
                                                              "", 
                                                              $username);
                      $_SESSION['username'] = $username;
                      $_SESSION['login_string'] = hash('sha512', 
                            $password . $user_browser);
                      // Login successful.
                      return true;
                  } else {
                      // Password is not correct
                      // We record this attempt in the database
                      $now = time();
                      $mysqli-&gt;query("INSERT INTO login_attempts(user_id, time)
                                  VALUES ('$user_id', '$now')");
                      return false;
                  }
              }
          } else {
              // No user exists.
              return false;
          }
      }
  }
  </code></pre>
  
  <p>When using on the iPhone app, Androids browser, desktop browsers or on some Android apps it gives a single sha5 hash: <code>c7d9a2def4f8d0f9c4b65d7522566ed33549b266174b2b12ae7f7b047e7efed2e92d18e552d1c812f073e794d16feb8ccf9df85399c475f24571472dece2d9b2</code></p>
  
  <p>but on some Android devices it gives one of the two hashes when using the same password for some weird reason:
  <code>98488504186f9f69041c80217c311cfb4772f46319c945d3bc30c0c2db5650e675774bc6978749770b598e70d4553ec0391e7d3ec0b56d51eef51eeadbb7e10e</code></p>
  
  <p><code>a3e08c365ef82d4256d8e58fd63b53d63d50b6b3cac3cdaba395cc73289e5f955491f11f06408c2c6e6ae531d69ddb10f234ecef0cf375d9782abea27909c9ef</code></p>