CryptoJs 使用 AES CBC 加解密資料

big_cat發表於2023-04-24

AES CBC 模式

廢話不多說,直接上程式碼,加密步驟為:

  1. 約定 key, 生成本次加密需要的 iv
  2. 資料體 cbc 加密 encData
  3. 資料體 base64 編碼 encDataBase64ed
  4. 計算資料體的 hmac
  5. {iv, mac, encDataBase64ed} stringify = payload
  6. payload base64編碼傳輸。payloadBase64ed
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AesCBC加解密</title>
    <style>
        * {
            box-sizing: border-box;
        }
        input, textarea {
            width: 100%;
            padding: 10px 20px;
            border-radius: 10px;
        }
    </style>
</head>
<body>
<div style="padding: 0 20px">
    <div>
        <h4>Key</h4>
        <input type="text" id="key" placeholder="請輸入約定的Key">
    </div>
    <div>
        <h4>密文</h4>
        <textarea name="encData" id="encData" rows="10" oninput="encDataDec()"></textarea>
    </div>
    <div>
        <h4>明文</h4>
        <textarea name="decData" id="decData" rows="10" oninput="decDataEnc()"></textarea>
    </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
<script>
    function encDataDec() {
        let key = document.getElementById("key").value
        if (key.trim() === "") {
            alert("請輸入約定的Key")
            return;
        }
        let encDataDom = document.getElementById("encData")
        let decDataDom = document.getElementById("decData")
        if (encDataDom.value === "") {
            decDataDom.value = ""
            return
        }
        try {
            decDataDom.value = AesCBCDecrypt(encDataDom.value, key)
        } catch (err) {
            decDataDom.value = err.toString()
        }
    }

    function decDataEnc() {
        let key = document.getElementById("key").value
        if (key.trim() === "") {
            alert("請輸入約定的Key")
            return;
        }
        let encDataDom = document.getElementById("encData")
        let decDataDom = document.getElementById("decData")
        if (decDataDom.value === "") {
            encDataDom.value = ""
            return
        }
        try {
            encDataDom.value = AesCBCEncrypt(decDataDom.value, key)
        } catch (err) {
            encDataDom.value = err.toString()
        }
    }

    function AesCBCEncrypt(bizData, key) {
        let iv = "te21".repeat(4)//16位隨機iv

        let waKey = CryptoJS.enc.Utf8.parse(key)
        let waIv = CryptoJS.enc.Utf8.parse(iv)

        let bizDataEnc = CryptoJS.AES.encrypt(bizData, waKey, {
            iv: waIv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        })

        let bizDataEncBase64 = CryptoJS.enc.Base64.stringify(bizDataEnc.ciphertext)
        let ivBase64 = CryptoJS.enc.Base64.stringify(waIv)

        let mac = CryptoJS.HmacSHA256(ivBase64 + bizDataEncBase64, waKey).toString()
        let payloadJson = {
            iv: ivBase64,
            mac: mac,
            value: bizDataEncBase64
        }
        return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(payloadJson)))
    }

    function AesCBCDecrypt(payloadEnc, key) {
        let payloadJson = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(payloadEnc)))
        let waKey = CryptoJS.enc.Utf8.parse(key)
        let waIv = CryptoJS.enc.Base64.parse(payloadJson.iv)
        let bizData = CryptoJS.AES.decrypt(payloadJson.value, waKey, {
            iv: waIv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        })
        return CryptoJS.enc.Utf8.stringify(bizData)
    }
</script>
</body>
</html>

相關文章