Vue

by tranxuanthang

HTML

<div id="app">
  <h1>
    Tạo password hash với PBKDF2
  </h1>
  <p>
    Nhập mật khẩu:<br>
    <input type="password" v-model="inputPassword" /><br>
    Nhập salt (dạng hex):<br>
    <input type="text" v-model="inputSalt" /><button @click="renewSalt">
      Làm mới
    </button><br>
    Số iteration:<br>
    <input type="number" v-model="inputIterations" /><br>
    <button @click="submitPassword">
      Tạo hash
    </button><br>
    <div v-if="loading">
      Đang tính...
    </div>
    Mã hash của mật khẩu (dạng hex): {{ resultDigest }}<br>
  </p>
</div>

Vue

// https://bitcoin.stackexchange.com/questions/52727/byte-array-to-hexadecimal-and-back-again-in-javascript
const toHexString = byteArray => {
  var bufferView = new Uint8Array(byteArray);
  return Array.prototype.map.call(bufferView, function (byte) {
    return ("0" + (byte & 0xFF).toString(16)).slice(-2);
  }).join("");
};

const toByteArray = hexString => {
  var result = [];
  while (hexString.length >= 2) {
    result.push(parseInt(hexString.substring(0, 2), 16));
    hexString = hexString.substring(2, hexString.length);
  }
  return new Uint8Array(result);
};

const getRandomArrayBuffer = bytesNumber => {
  let byte = new Uint8Array(bytesNumber);
  crypto.getRandomValues(byte);
  return byte;
};

const getKeyMaterial = async (passwordString) => {
  const passwordBuffer = new TextEncoder().encode(passwordString);
  return await crypto.subtle.importKey("raw", passwordBuffer, "PBKDF2", false, ["deriveBits"]);
};

const getDerivedBits = async (saltBuffer, keyMaterial, iterations, bitLength) => {
  const params = {
    name: "PBKDF2",
    salt: saltBuffer,
    iterations: iterations,
    hash: "SHA-256"
  };
  return await window.crypto.subtle.deriveBits(
    params,
    keyMaterial,
    bitLength
  );
};

new Vue({
  el: "#app",
  data: {
    inputPassword: null,
    inputSalt: null,
    inputIterations: 100000,
    resultDigest: null,
    loading: false
  },
  methods: {
    submitPassword: async function () {
      // Cập nhật UI
      this.loading = true;
      this.resultSalt = null;
      this.resultDigest = null;

      // Tạo hash
      let saltBuffer = toByteArray(this.inputSalt);
      
      // Tạo CryptoKey object từ password đầu vào
      let keyMaterial = await getKeyMaterial(this.inputPassword);

      // 160: số bit của mã hash pbkdf2
      let resultBuffer = await getDerivedBits(saltBuffer, keyMaterial, this.inputIterations, 160);

      // Cập nhật kết quả
      this.resultDigest = toHexString(new Uint8Array(resultBuffer));

      // Cập nhật...