NNID password hasher (2023)

originally made 2023-12-14

by arian_

HTML

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script>
      // Function to generate a light color
      function getRandomLightColor() {
        var letters = "BCDEF" // Higher hex digits for lighter colors
        var color = "#"
        for (var i = 0; i < 6; i++) {
          color += letters[Math.floor(Math.random() * letters.length)]
        }
        return color
      }
    </script>
    <style>
      .hash-output {
      }
      body {
        background-size: 90px;
        text-align: center;

        background-color: black;
        color: white;
      }
      form,
      ul,
      h1 {
        text-wrap: wrap;
      }
    </style>
  </head>
  <body>
    <h1>nnid password hasher trust me bro</h1>
    <form id="hashForm">
      <label for="pid">Principal ID:</label>
      <input type="number" id="pid" required /><br />
      <label for="password">Password:</label>
      <input type="password" id="password" required /><br />
      <button type="submit">Calculate Hash</button>
    </form>
    <ul id="hashList"></ul>

    <script>
      document.getElementById("hashForm").onsubmit = function (event) {
        event.preventDefault()
        var pid = document.getElementById("pid").value
        var password = document.getElementById("password").value
        calcPasswordHash(parseInt(pid), password).then((hash) => {
          var hashElement = document.createElement("li")
          hashElement.innerHTML = password + ": " + hash
          hashElement.style.color = getRandomLightColor()
          var hashList = document.getElementById("hashList")
          hashList.insertBefore(hashElement, hashList.firstChild)
        })
      }
    </script>
  </body>
</html>

JavaScript

const sc = window['crypt'+'o'].subtle; // Shortcut to SubtleCr*pto.
// ^^ Needed because jsfiddle blocks the keyword cr*pto for some reason

function calcPasswordHash(pid, password) {
  var encoder = new TextEncoder()
  var pidBuffer = new Uint32Array([pid]).buffer
  var pidBytes = new Uint8Array(pidBuffer)
  var staticBytes = new Uint8Array([2, 101, 67, 70])
  var passwordBytes = encoder.encode(password)
  var data = new Uint8Array(
    pidBytes.length + staticBytes.length + passwordBytes.length,
  )

  data.set(pidBytes)
  data.set(staticBytes, pidBytes.length)
  data.set(passwordBytes, pidBytes.length + staticBytes.length)

  // SubtleCr*pto (window.cr*pto.subtle) Digest:
  return sc.digest("SHA-256", data).then((hashBuffer) => {
    const hashArray = Array.from(new Uint8Array(hashBuffer))
    const hashHex = hashArray
      .map((b) => b.toString(16).padStart(2, "0"))
      .join("")
    return hashHex
  })
}