如何使用密码和javascript函数解密AES-GCM加密文本?

问题描述 投票:0回答:1

async function generateAESKeyFromPassword(password) {
  const encoder = new TextEncoder();
  const passwordKey = await crypto.subtle.importKey('raw',encoder.encode(password),'PBKDF2', false,['deriveKey']);
  return await crypto.subtle.deriveKey({
    name: 'PBKDF2',
    salt: crypto.getRandomValues(new Uint8Array(16)),
    iterations: 100000,
    hash: 'SHA-256',
  }, passwordKey, {
    name: 'AES-GCM',
    length: 256,
  }, true, ['encrypt', 'decrypt']);
}

async function encryptText(password, plaintext) {
    const encoder = new TextEncoder();
    const data = encoder.encode(plaintext);
    const key = await generateAESKeyFromPassword(password);

    const iv = crypto.getRandomValues(new Uint8Array(12));
    const ciphertext = await crypto.subtle.encrypt(
      {
        name: 'AES-GCM',
        iv: iv,
      },
      key,
      data
    );
    
    const combined = new Uint8Array(12 + ciphertext.byteLength);
    combined.set(iv);
    combined.set(new Uint8Array(ciphertext), 12);
    return btoa(String.fromCharCode(...combined));
}

async function decryptText(key, combinedBase64) {
    const combinedArray = new Uint8Array(
      atob(combinedBase64)
        .split('')
        .map((char) => char.charCodeAt(0))
    );
    
    const iv = combinedArray.slice(0, 12);
    const ciphertextArray = combinedArray.slice(12);
    
    const decryptedData = await crypto.subtle.decrypt(
      {
        name: 'AES-GCM',
        iv: iv,
      },
      key,
      ciphertextArray
    );
    
    const decoder = new TextDecoder();
    const decryptedText = decoder.decode(decryptedData);
    
    return decryptedText;
}

const encryptedTextBase64 = "Jkf7KDJjnxwYapwGyiaVltQyIdw5whGrKSAo2qeLqYNd8aXwMeIzsFRkz4Z4yZlNfhKw+moqnST6xOuK8lR41vPAhKuv0jfWtmGwmGZGIRIDFxJSCZCElvfANw==";
const password = "mypassword";

generateAESKeyFromPassword(password)
  .then(key => {
    return decryptText(key, encryptedTextBase64);
  })
  .then(decryptedText => {
    console.log("SUCCESS:", decryptedText);
  })
  .catch(error => {
    console.error("ERROR:", error);
  });

密码:Jkf7KDJjnxwYapwGyiaVltQyIdw5whGrKSAo2qeLqYNd8aXwMeIzsFRkz4Z4yZlNfhKw+moqnST6xOuK8lR41vPAhKuv0jfWtmGwmGZGZGIRIDFxJSCZCElvfANw== 密码:“我的密码”。 iv 是密码。

我只能假设问题出在新的 AESKEY 生成(函数generateAESKeyFromPassword)上,并且直觉上我认为我不应该生成它,但是我该如何解密呢?

javascript aes aes-gcm
1个回答
0
投票

const encryptForm = document.getElementById("encrypt");
encryptForm.addEventListener("submit", async function (event) {
  event.preventDefault();

  const dataText = this.querySelector(".text").value;
  const dataPassword = this.querySelector(".password").value;
  const resultBlock = this.querySelector(".result");
  
  const encryptedData = await encryptText(dataPassword, dataText);
  
  resultBlock.innerHTML = "result: " + encryptedData;
});

const decryptForm = document.getElementById("decrypt");
decryptForm.addEventListener("submit", async function (event) {
  event.preventDefault();

  const dataText = this.querySelector(".text").value;
  const dataPassword = this.querySelector(".password").value;
  const resultBlock = this.querySelector(".result");
  
  const decryptedData = await decryptText(dataPassword, dataText);
  
  resultBlock.innerHTML = "result: " + decryptedData;
});

async function genAES(password, salt) {
  const encoder = new TextEncoder();
  const passwordEncoded = encoder.encode(password);

  const passwordKey = await crypto.subtle.importKey(
    "raw",
    passwordEncoded,
    "PBKDF2",
    false,
    ["deriveKey"]
  );

  return await crypto.subtle.deriveKey(
    {
      name: "PBKDF2",
      salt: salt,
      iterations: 1,
      hash: "SHA-256"
    },
    passwordKey,
    {
      name: "AES-GCM",
      length: 256
    },
    true,
    ["encrypt", "decrypt"]
  );
}

async function encryptText(password, plaintext) {
  const encoder = new TextEncoder();
  const data = encoder.encode(plaintext);
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const salt = crypto.getRandomValues(new Uint8Array(16));
  const key = await genAES(password, salt);

  const ciphertext = await crypto.subtle.encrypt(
    {
      name: "AES-GCM",
      iv: iv
    },
    key,
    data
  );

  // Объединение salt, iv и ciphertext в одном ArrayBuffer
  const combined = new Uint8Array(16 + 12 + ciphertext.byteLength);
  combined.set(salt);
  combined.set(iv, 16);
  combined.set(new Uint8Array(ciphertext), 16 + 12);

  return btoa(String.fromCharCode(...combined));
}

async function decryptText(password, enrcyptdata) {
  const combinedArray = new Uint8Array(
    atob(enrcyptdata)
      .split('')
      .map((char) => char.charCodeAt(0))
  );

  const salt = combinedArray.slice(0, 16);
  const iv = combinedArray.slice(16, 28);
  const ciphertextArray = combinedArray.slice(28);
  const key = await genAES(password, salt);
  
  const decryptedData = await crypto.subtle.decrypt(
    {
      name: 'AES-GCM',
      iv: iv,
    },
    key,
    ciphertextArray
  );

  const decoder = new TextDecoder();
  const decryptedText = decoder.decode(decryptedData);

  return decryptedText;
}
<form id="encrypt">
  <h1>Encrypt</h1>
  <p>text</p>
  <input type="text" class="text">
  <p>password</p>
  <input type="text" class="password">
  <p><button>Encrypt</button> <span class="result"></span></p>
</form>

<form id="decrypt">
  <h1>Decrypt</h1>
  <p>encrypt data</p>
  <input type="text" class="text">
  <p>password</p>
  <input type="text" class="password">
  <p><button>Decrypt</button> <span class="result"></span></p>
</form>

© www.soinside.com 2019 - 2024. All rights reserved.