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)上,并且直觉上我认为我不应该生成它,但是我该如何解密呢?
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>