Vue

by tranxuanthang

HTML

<div id="app">
  <h1>Mã hóa và giải mã với AES-GCM</h1>
  <h2>Mã hóa</h2>
  Mật khẩu:<br>
  <input type="password" v-model="inputPassword" /><br>
  Nội dung:<br>
  <textarea v-model="inputContent"></textarea><br>
  <button @click="submitEncrypt">Mã hóa</button><br>
  Kết quả: (click để copy)<br>
  <div class="result-data">
    <div class="error" v-if="errorEncrypt">
      Mã hóa thất bại!
    </div>
    <div class="data nothing" v-else-if="resultEncrypted == ''">
      Chưa có gì :(
    </div>
    <div class="data" v-else>
      {{ resultEncrypted }}
    </div>
  </div>
  <br>
  <h2>Giải mã</h2>
  Mật khẩu:<br>
  <input type="password" v-model="inputPasswordDecrypt" /><br>
  Dữ liệu đã mã hóa (dạng JSON):<br>
  <textarea v-model="inputEncrypted"></textarea><br>
  <button @click="submitDecrypt">Giải mã</button><br>
  Kết quả:<br>
  <div class="result-data">
    <div class="error" v-if="errorDecrypt">
      Giải mã thất bại!
    </div>
    <div class="data nothing" v-else-if="resultDecrypted == ''">
      Chưa có gì :(
    </div>
    <div class="data" v-else>
      {{ resultDecrypted }}
    </div>
  </div>
</div>

CSS

body {
  font-size: 16px;
}

h1 {
  font-size: 160%;
}

h2 {
  font-size: 130%;
}

textarea {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  width: 100%;
}

.result-data {
  -webkit-user-select: all;
  -moz-user-select: all;
  -ms-user-select: all;
  user-select: all;
  word-wrap: break-word;
  font-family: monospace;
  padding: 8px;
  background-color: #eee;
}

.error {
  color: red;
}

.nothing {
  color: blue;
}

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, { name: "PBKDF2" }, false, ["deriveBits", "deriveKey"]);
};

const getKey = async (saltBuffer, keyMaterial, iterations) => {
  let params = {
    name: "PBKDF2",
    salt: saltBuffer,
    iterations: 100000,
    hash: "SHA-256"
  };
  return await crypto.subtle.deriveKey(
    params,
    keyMaterial,
    { name: "AES-GCM", length: 256 },
    true,
    ["encrypt", "decrypt"]
  );
};

const encryptMessage = async (dataBuffer, key, ivBuffer) => {
  return await crypto.subtle.encrypt(
    {
      name: "AES-GCM",
      iv: ivBuffer
    },
    key,
    dataBuffer
  );
}

const decryptMessage = async (encryptedDataBuffer, key, ivBuffer) => {
  return await crypto.subtle.decrypt(
    {
      name: "AES-GCM",
      iv: ivBuffer
    },
    key,
    encryptedDataBuffer
  );
}

new Vue({
  el: "#app",
  data: {
    inputPassword: "",
    inputContent: "",
    resultEncrypted: "",
    inputPasswordDecrypt: "",
    inputEncrypted: "",
    resultDecrypted: "",
    errorEncrypt: false,
    errorDecrypt: false
  },
  methods: {
    submitEncrypt: async function () {
      try {
        // Tạo khóa
     ...