<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8" />
<title>AES 加密解密</title>
<script src="https://netnr.eu.org/crypto-js@4.2.0/crypto-js.js"></script>
</head>
<body>
</body>
</html>
/**
* AES 256 GCM 加密
* @param {*} plaintext 纯文本
* @param {*} password 密钥
* @returns
*/
async function AESEncrypt(plaintext, password) {
const pwUtf8 = new TextEncoder().encode(password);
const pwHash = await window.crypto.subtle.digest('SHA-256', pwUtf8);
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const ivStr = Array.from(iv).map(b => String.fromCharCode(b)).join('');
const alg = { name: 'AES-GCM', iv: iv };
const key = await window.crypto.subtle.importKey('raw', pwHash, alg, false, ['encrypt']);
const ptUint8 = new TextEncoder().encode(plaintext);
const ctBuffer = await window.crypto.subtle.encrypt(alg, key, ptUint8);
const ctArray = Array.from(new Uint8Array(ctBuffer));
const ctStr = ctArray.map(byte => String.fromCharCode(byte)).join('');
return window.btoa(ivStr + ctStr);
}
/**
* AES 256 GCM 解密
* @param {*} ciphertext 密文
* @param {*} password 密钥
* @returns
*/
async function AESDecrypt(ciphertext, password) {
const pwUtf8 = new TextEncoder().encode(password);
const pwHash = await window.crypto.subtle.digest('SHA-256', pwUtf8);
const ivStr = window.atob(ciphertext).slice(0, 12);
const iv = new Uint8Array(Array.from(ivStr).map(ch => ch.charCodeAt(0)));
const alg = { name: 'AES-GCM', iv: iv };
const key = await window.crypto.subtle.importKey('raw', pwHash, alg, false, ['decrypt']);
const ctStr = window.atob(ciphertext).slice(12);
const ctUint8 = new Uint8Array(Array.from(ctStr).map(ch => ch.charCodeAt(0)));
const plainBuffer = await window.crypto.subtle.decrypt(alg, key, ctUint8);
return new TextDecoder().decode(plainBuffer);
}
var plaintext = 'Hello,世界,123!';
var password = "key";
console.debug(`plaintext: ${plaintext} \t password: ${password}`)
async function Test1() {
var v1 = await AESEncrypt(plaintext, password);
console.debug(`Local AES-256-GCM Encrypt: ${v1}`)
var v2 = await AESDecrypt(v1, password);
console.debug(`Local AES-256-GCM Decrypt: ${v2}`)
}
Test1();
//ref https://gist.github.com/chrisveness/43bcda93af9f646d083fad678071b90a
/**
* ref: crypto-js
* aes-256-cbc Encrypt
*/
function aesEncrypt(data, key, iv) {
key = (key || "").padEnd(32, ' ');
iv = (iv || "").padEnd(16, ' ');
var result = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
}).toString();
return result;
}
/**
* ref: crypto-js
* aes-256-cbc Decrypt
*/
function aesDecrypt(data, key, iv) {
key = (key || "").padEnd(32, ' ');
iv = (iv || "").padEnd(16, ' ');
var result = CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
}).toString(CryptoJS.enc.Utf8);
return result;
}
console.debug(`CryptoJS AES-256-CBC Encrypt: ${aesEncrypt(plaintext, password)}`);
console.debug(`CryptoJS AES-256-CBC Decrypt: ${aesDecrypt("UsorChZSHOmkd0SQDL+Tp+n//MKpKmzClya9YsKPZII=", password)}`);