正在研究js-md5

分享和讨论Javascript相关的话题
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

正在研究js-md5

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

hash算法有:md5, sha0, sha1, sha256, sha512, sm3, shap512
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

一般可能用sha256也就足夠了。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

了解到crypto.js已經包含了大多數的加密算法,包括md5、sha256、base64等。

下面要研究的就是crypto.js如何使用。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

grok:

代码: 全选

當然可以!以下是如何在本地瀏覽器中使用提供的 `md5.js` 代碼的繁體中文說明:

### 前提條件
1. **CryptoJS 庫**:`md5.js` 依賴於 CryptoJS 的核心模組(`core.js`),提供 `WordArray` 和 `Hasher` 等基礎類。你需要核心模組和 MD5 模組。
2. **HTML 文件**:創建一個 HTML 文件來載入腳本並執行 MD5 雜湊計算。
3. **本地文件**:確保 `core.js` 和 `md5.js` 在你的項目目錄中。

### 使用步驟

1. **獲取 CryptoJS 核心模組**:
   - `md5.js` 需要 `core.js`。你可以從 CryptoJS 官方網站或 CDN 下載完整庫。
   - 為方便起見,建議使用 CDN(如 jsDelivr)載入核心和 MD5 模組。

2. **設置項目目錄**:
   - 將 `core.js` 和 `md5.js` 放入項目資料夾(例如 `./js/crypto-js/`),或使用 CDN。
   - 在同一目錄中創建一個 HTML 文件(例如 `index.html`)。

3. **創建 HTML 文件**:
   以下是載入 CryptoJS(核心和 MD5)並展示 MD5 雜湊計算的 HTML 示例:

   ```html
   <!DOCTYPE html>
   <html lang="zh-TW">
   <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>MD5 雜湊範例</title>
   </head>
   <body>
       <h1>MD5 雜湊範例</h1>
       <p>輸入:<input type="text" id="inputText" value="Hello, World!"></p>
       <button onclick="computeMD5()">計算 MD5</button>
       <p>MD5 雜湊:<span id="output"></span></p>

       <!-- 從 CDN 載入 CryptoJS 核心和 MD5 -->
       <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/core.min.js"></script>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/md5.min.js"></script>
       <!-- 或者使用本地文件 -->
       <!-- <script src="js/crypto-js/core.js"></script> -->
       <!-- <script src="js/crypto-js/md5.js"></script> -->

       <script>
           function computeMD5() {
               // 獲取輸入文字
               const inputText = document.getElementById('inputText').value;
               // 計算 MD5 雜湊
               const hash = CryptoJS.MD5(inputText);
               // 顯示雜湊值(轉為十六進位字串)
               document.getElementById('output').textContent = hash.toString();
           }
       </script>
   </body>
   </html>
   ```

4. **代碼說明**:
   - **載入腳本**:
     - 使用 `<script>` 標籤從 CDN 載入 `core.min.js` 和 `md5.min.js`。若使用本地文件,則替換為本地路徑。
     - 確保 `core.js` 在 `md5.js` 之前載入,因後者依賴前者。
   - **計算 MD5**:
     - `computeMD5` 函數從 HTML 輸入欄位獲取文字。
     - `CryptoJS.MD5(inputText)` 計算輸入文字的 MD5 雜湊。
     - 使用 `toString()` 將雜湊轉為十六進位字串並顯示在 `<span>` 中。

5. **運行 HTML 文件**:
   - **本地伺服器**:由於瀏覽器安全限制(CORS),不能直接用 `file://` 打開 HTML 文件。需使用本地網頁伺服器:
     - **Node.js**:安裝 `http-server`(`npm install -g http-server`),在項目目錄運行 `http-server`,然後訪問 `http://localhost:8080`。
     - **Python**:在項目目錄運行 `python -m http.server 8000`(Python 3),訪問 `http://localhost:8000`。
     - **其他選項**:使用 VS Code 的 Live Server 擴展或其他本地伺服器工具。
   - 在瀏覽器中打開伺服器 URL(例如 `http://localhost:8080`)。

6. **測試 MD5 雜湊**:
   - 在瀏覽器中打開 HTML 頁面。
   - 在輸入欄位輸入文字(例如 "Hello, World!")。
   - 點擊「計算 MD5」按鈕,查看 MD5 雜湊值(例如 `65a8e27d8879283831b664bd8b7f0ad4`)。

7. **使用本地 `md5.js`(可選)**:
   - 若要直接使用提供的 `md5.js` 代碼,確保項目資料夾中有兼容的 `core.js`。
   - 將提供的 `md5.js` 代碼保存為 `md5.js`(例如 `./js/crypto-js/md5.js`)。
   - 在 HTML 文件中引用,如上述註解中的 `<script>` 標籤所示。
   - 確認 `core.js` 與 `md5.js` 版本兼容,提供的代碼需 `CryptoJS` 物件包含 `lib.WordArray` 和 `сию

8. **其他注意事項**:
   - **HMAC-MD5**:代碼也支持 HMAC-MD5(例如 `CryptoJS.HmacMD5(message, key)`)。可修改腳本以計算 HMAC-MD5:
     ```javascript
     const hmac = CryptoJS.HmacMD5("message", "secretkey").toString();
     ```
   - **錯誤處理**:若雜湊計算失敗,檢查瀏覽器控制台(F12 或 Ctrl+Shift+J)是否有錯誤,例如缺少 `CryptoJS` 或文件路徑錯誤。
   - **安全提醒**:MD5 已被認為在密碼學上不安全,不應用於安全關鍵任務(如密碼雜湊),僅用於非安全用途(如校驗和)。

### 示例輸出
輸入 "Hello, World!",MD5 雜湊應為:
```
65a8e27d8879283831b664bd8b7f0ad4
```

### 故障排除
- **腳本無效**:確保 `core.js` 在 `md5.js` 之前載入,檢查控制台錯誤。
- **CORS 問題**:使用本地網頁伺服器而非直接打開 HTML 文件。
- **缺少依賴**:若使用本地文件,確認 `core.js` 版本與 `md5.js` 兼容。

按照以上步驟,你即可在本地瀏覽器中使用 `md5.js` 計算 MD5 雜湊。如需具體部分協助,請告訴我!
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

SJCL:斯坦福大學開發的aes加密

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

SJCL加密後需要保存的數據(gemini2.5pro)

帖子 ejsoon »

代码: 全选

好的,我們來詳細介紹一下 SJCL (Stanford Javascript Crypto Library) 可用的加密模式,以及在使用 PBKDF2 時,加密結果中除了密文、鹽和初始向量 (IV) 之外,還需要哪些參數。

### SJCL 簡介

SJCL 是一個由斯坦福大學計算機安全實驗室設計和開發的 JavaScript 加密庫,旨在提供安全、快速且易於使用的加密工具。它特別注重默認設置的安全性,以幫助開發者避免常見的密碼學錯誤。

### PBKDF2 的角色

首先,需要釐清一個重要的概念:**PBKDF2 (Password-Based Key Derivation Function 2) 並不是一種加密模式**,而是一個密鑰派生函數。它的作用是將一個(通常是較弱的)用戶密碼轉換成一個強度足夠的、固定長度的密鑰,以供後續的加密算法使用。

這個過程通常如下:
`密碼 + 鹽 (Salt)  ->  PBKDF2 (反覆運算)  ->  加密密鑰`

因此,當你在 SJCL 中使用密碼進行加密時,PBKDF2 會被自動調用來生成密鑰。這也是為什麼加密結果中會包含 `salt`(鹽)和 `iter`(反覆運算次數)的原因。

-----

### SJCL 可用的主要加密模式

SJCL 主要支持的是**經過身份驗證的加密模式 (Authenticated Encryption with Associated Data, AEAD)**。這類模式的優點是在加密數據的同時,還能生成一個驗證標籤 (Authentication Tag),用於確保數據在傳輸或存儲過程中沒有被篡改。這比傳統的非驗證模式(如 CBC)要安全得多。

SJCL 的默認和推薦模式是 **CCM**。

1.  **CCM (Counter with CBC-MAC)**

      * **簡介**: 這是一種為塊加密算法(如 AES)設計的 AEAD 模式,結合了 CTR (Counter) 模式的加密和 CBC-MAC 的認證功能。它是 SJCL 的**默認模式**。
      * **優點**: 安全性高,能同時保證機密性 (Confidentiality) 和完整性 (Integrity)。

2.  **GCM (Galois/Counter Mode)**

      * **簡介**: 另一種流行的 AEAD 模式,同樣結合了 CTR 模式和一種基於伽羅瓦域 (Galois Field) 乘法的認證機制。
      * **優點**: 通常比 CCM 有更高的性能(尤其是在有硬件加速支持的環境下),同樣提供高強度的機密性和完整性驗證。

3.  **OCB 2.0 (Offset Codebook Mode)**

      * **簡介**: 這是一種非常高效的 AEAD 模式,計算成本很低。
      * **注意**: OCB 模式受到專利保護,雖然在某些情況下可以免費使用,但在商業項目中使用前需要注意其許可證問題。因此,CCM 或 GCM 是更普遍的選擇。

4.  **CBC (Cipher Block Chaining)**

      * **簡介**: 一種較傳統的加密模式。SJCL 也支持此模式,但不推薦直接使用,因為它**本身不提供數據完整性驗證**。如果必須使用,開發者需要自己實現一個獨立的 MAC(如 HMAC)來防止篡改攻擊。SJCL 的設計哲學就是盡量避免讓開發者陷入這種困境。

-----

### 加密結果中還需要什麼?

當你使用 `sjcl.encrypt()` 函數並傳入密碼時,SJCL 會自動處理 PBKDF2 和加密,並生成一個 JSON 字符串。這個字符串包含了**解密所需的所有參數**。

我們來分解一下這個 JSON 對象的典型結構:

```json
{
  "iv": "...",       // 初始向量 (Initialization Vector)
  "v": 1,            // SJCL 版本號
  "iter": 10000,     // PBKDF2 的反覆運算次數
  "ks": 128,         // 密鑰長度 (Key Size),單位是位
  "ts": 64,          // 驗證標籤長度 (Tag Size),單位是位
  "mode": "ccm",     // 使用的加密模式
  "adata": "",       // 附加驗證數據 (Additional Authenticated Data)
  "cipher": "aes",   // 使用的加密算法
  "salt": "...",     // 用於 PBKDF2 的鹽
  "ct": "..."        // 密文 (Ciphertext),其中包含了加密後的數據和驗證標籤
}
```

除了你提到的**密文 (`ct`)**、**鹽 (`salt`)** 和 **IV (`iv`)** 之外,這些不同的模式還需要以下關鍵信息才能成功解密:

| 參數 | 解釋 | 為何需要? |
| :--- | :--- | :--- |
| **`mode`** | **加密模式** | 這是解密的核心參數之一。解密時必須使用與加密時完全相同的模式(如 `ccm` 或 `gcm`),否則無法正確還原數據。 |
| **`iter`** | **PBKDF2 迭代次數** | 解密時,需要使用用戶密碼、`salt` 和完全相同的 `iter` 次數,才能派生出與加密時一致的密鑰。 |
| **`ks`** | **密鑰長度** | 派生密鑰時需要知道目標密鑰的長度(如 128 位、192 位或 256 位)。 |
| **`ts`** | **驗證標籤長度** | **對於 AEAD 模式(如 CCM, GCM)至關重要**。它告訴解密程序,在密文 (`ct`) 的末尾有多少位是驗證標籤。解密程序會重新計算標籤並與此部分進行比較,以驗證數據的完整性。 |
| **`adata`** | **附加驗證數據** | 這是一個可選參數。`adata` 是指那些**不需要加密但需要保護其完整性**的數據(例如,元數據、非機密的頭部信息等)。如果在加密時提供了 `adata`,那麼在解密時**必須提供完全相同的 `adata`**,否則驗證會失敗。 |
| `cipher` | 加密算法 | 標明了使用的對稱加密算法,通常是 `aes`。 |
| `v` | 版本號 | 確保庫版本的兼容性。 |

### 總結

總結來說,當你使用 SJCL 配合 PBKDF2 進行加密時,除了**密文、鹽、IV** 之外,解密過程還依賴於一個完整的參數集合,其中:

  * **對於所有模式**:都需要 `iter` 和 `ks` 來重新生成正確的加密密鑰。
  * **對於 AEAD 模式 (CCM, GCM)**:`mode`、`ts` 和 `adata` 是解密和驗證數據完整性的關鍵。解密函數會從密文 `ct` 中提取驗證標籤,並使用這些參數來驗證數據是否被篡改。

SJCL 的優勢在於它將所有這些必需的參數都整齊地打包在一個 JSON 對象中,大大簡化了開發者的工作,並降低了因遺漏參數而導致解密失敗或安全漏洞的風險。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

crypto.js的加密結果格式:

代码: 全选

{
  "ct": "...", // Ciphertext (Base64)
  "salt": "...", // Salt (Hex)
  "iv": "...", // IV (Hex)
  "mac": "...", // HMAC Tag (Hex)
  "config": {
    "mode": "CBC",
    "padding": "Pkcs7",
    "iterations": 1000,
    "keySize": 256
  }
}
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

代码: 全选

用crypto.js以及SJCL做一個html+js+css程式,適配手機端。

要求如下:

一,html的元素有:

h2{加密}
textarea#ejc_text{明文}
input#ejc_encryptpw{密碼}
button[type=button]#ejc_encrypt{加密}

rypto.js的aes加密結果:
pre#ejc_aes_ecb
pre#ejc_aes_cbc
pre#ejc_aes_cfb
pre#ejc_aes_ctr
pre#ejc_aes_ofb

SJCL的aes加密結果:
pre#sjcl_mode_cbc
pre#sjcl_mode_ccm
pre#sjcl_mode_ctr
pre#sjcl_mode_gcm

h2{解密}
textarea#ejc_encrypttext
input#ejc_decryptpw
button[type=button]#ejc_decrypt{解密}
textarea#ejc_decryptresult

二,在必要的地方添加h4標題。

三,當點擊ejc_encrypt時,crypto.js以及SJCL將產生加密結果。

四,pre需強制換行。其內容將為json格式。

如果是SJCL的加密結果,其格式為:
{"iv":"Phr6GAlAjJiotvc+mj8sZQ==",
"v":1,
"iter":1000,
"ks":128,
"ts":64,
"mode":"ccm",
"adata":"",
"cipher":"aes",
"salt":"ZnJ87+1uVg0=",
"ct":"pf7M+U5nenIAXHcFJhVo1w/oBjQ="}

如果是crypto.js的加密結果,其格式為:
{
  "ct": "...", // Ciphertext (Base64)
  "salt": "...", // Salt (Base64)
  "iv": "...", // IV (Base64)
  "hmac-sha256": "...", // HMAC Tag (Base64)
  "config": {
    "mode": "CBC",
    "padding": "Pkcs7",
    "iterations": 1000,
    "keySize": 256
  }
}

五,當產生結果後,點擊其中一個pre,它的內容將輸入至ejc_encrypttext中。

六,當擊點ejc_decrypt時,js將識別它是crypto.js還是SJCL的加密結果,然後用ejc_decryptpw解密。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

grok:

代码: 全选

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加密解密工具</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <script src="https://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f4f4f4;
            max-width: 100%;
            box-sizing: border-box;
        }
        h2, h4 {
            color: #333;
        }
        textarea, input, button {
            width: 100%;
            margin-bottom: 10px;
            padding: 10px;
            box-sizing: border-box;
            font-size: 16px;
        }
        textarea {
            height: 100px;
            resize: vertical;
        }
        input[type="password"] {
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        button {
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background-color: #0056b3;
        }
        pre {
            background-color: #fff;
            border: 1px solid #ccc;
            padding: 10px;
            white-space: pre-wrap;
            word-wrap: break-word;
            cursor: pointer;
            margin-bottom: 10px;
            font-size: 14px;
        }
        pre:hover {
            background-color: #f0f0f0;
        }
        @media (max-width: 600px) {
            body {
                padding: 10px;
            }
            textarea, input, button {
                font-size: 14px;
            }
            pre {
                font-size: 12px;
            }
        }
    </style>
</head>
<body>
    <h2>加密</h2>
    <h4>明文</h4>
    <textarea id="ejc_text" placeholder="輸入明文"></textarea>
    <h4>密碼</h4>
    <input type="password" id="ejc_encryptpw" placeholder="輸入加密密碼">
    <button type="button" id="ejc_encrypt">加密</button>

    <h4>Crypto.js AES 加密結果</h4>
    <h5>ECB Mode</h5>
    <pre id="ejc_aes_ecb"></pre>
    <h5>CBC Mode</h5>
    <pre id="ejc_aes_cbc"></pre>
    <h5>CFB Mode</h5>
    <pre id="ejc_aes_cfb"></pre>
    <h5>CTR Mode</h5>
    <pre id="ejc_aes_ctr"></pre>
    <h5>OFB Mode</h5>
    <pre id="ejc_aes_ofb"></pre>

    <h4>SJCL AES 加密結果</h4>
    <h5>CBC Mode</h5>
    <pre id="sjcl_mode_cbc"></pre>
    <h5>CCM Mode</h5>
    <pre id="sjcl_mode_ccm"></pre>
    <h5>CTR Mode</h5>
    <pre id="sjcl_mode_ctr"></pre>
    <h5>GCM Mode</h5>
    <pre id="sjcl_mode_gcm"></pre>

    <h2>解密</h2>
    <h4>密文</h4>
    <textarea id="ejc_encrypttext" placeholder="輸入密文"></textarea>
    <h4>密碼</h4>
    <input type="password" id="ejc_decryptpw" placeholder="輸入解密密碼">
    <button type="button" id="ejc_decrypt">解密</button>
    <h4>解密結果</h4>
    <textarea id="ejc_decryptresult" readonly></textarea>

    <script>
        // 加密函數
        document.getElementById('ejc_encrypt').addEventListener('click', () => {
            const plaintext = document.getElementById('ejc_text').value;
            const password = document.getElementById('ejc_encryptpw').value;
            if (!plaintext || !password) {
                alert('請輸入明文和密碼');
                return;
            }

            // CryptoJS 加密
            const modes = [
                { id: 'ejc_aes_ecb', mode: CryptoJS.mode.ECB },
                { id: 'ejc_aes_cbc', mode: CryptoJS.mode.CBC },
                { id: 'ejc_aes_cfb', mode: CryptoJS.mode.CFB },
                { id: 'ejc_aes_ctr', mode: CryptoJS.mode.CTR },
                { id: 'ejc_aes_ofb', mode: CryptoJS.mode.OFB }
            ];

            modes.forEach(({ id, mode }) => {
                const salt = CryptoJS.lib.WordArray.random(16);
                const iv = mode === CryptoJS.mode.ECB ? '' : CryptoJS.lib.WordArray.random(16);
                const key = CryptoJS.PBKDF2(password, salt, { keySize: 256/32, iterations: 1000 });
                const encrypted = CryptoJS.AES.encrypt(plaintext, key, {
                    iv: iv,
                    mode: mode,
                    padding: CryptoJS.pad.Pkcs7
                });
                const hmac = CryptoJS.HmacSHA256(encrypted.ciphertext, key).toString(CryptoJS.enc.Base64);
                const result = {
                    ct: encrypted.ciphertext.toString(CryptoJS.enc.Base64),
                    salt: salt.toString(CryptoJS.enc.Base64),
                    iv: iv ? iv.toString(CryptoJS.enc.Base64) : '',
                    'hmac-sha256': hmac,
                    config: {
                        mode: mode === CryptoJS.mode.ECB ? 'ECB' :
                              mode === CryptoJS.mode.CBC ? 'CBC' :
                              mode === CryptoJS.mode.CFB ? 'CFB' :
                              mode === CryptoJS.mode.CTR ? 'CTR' : 'OFB',
                        padding: 'Pkcs7',
                        iterations: 1000,
                        keySize: 256
                    }
                };
                document.getElementById(id).textContent = JSON.stringify(result, null, 2);
            });

            // SJCL 加密
            const sjclModes = [
                { id: 'sjcl_mode_cbc', mode: 'cbc' },
                { id: 'sjcl_mode_ccm', mode: 'ccm' },
                { id: 'sjcl_mode_ctr', mode: 'ctr' },
                { id: 'sjcl_mode_gcm', mode: 'gcm' }
            ];

            sjclModes.forEach(({ id, mode }) => {
                const encrypted = sjcl.encrypt(password, plaintext, {
                    mode: mode,
                    iter: 1000,
                    ks: 128,
                    ts: 64
                });
                document.getElementById(id).textContent = JSON.stringify(JSON.parse(encrypted), null, 2);
            });
        });

        // 點擊 pre 複製到密文輸入框
        const pres = document.querySelectorAll('pre');
        pres.forEach(pre => {
            pre.addEventListener('click', () => {
                document.getElementById('ejc_encrypttext').value = pre.textContent;
            });
        });

        // 解密函數
        document.getElementById('ejc_decrypt').addEventListener('click', () => {
            const ciphertext = document.getElementById('ejc_encrypttext').value;
            const password = document.getElementById('ejc_decryptpw').value;
            const resultField = document.getElementById('ejc_decryptresult');

            if (!ciphertext || !password) {
                alert('請輸入密文和密碼');
                resultField.value = '';
                return;
            }

            try {
                const json = JSON.parse(ciphertext);

                if (json.ct && json.salt && json.config) {
                    // CryptoJS 解密
                    const { ct, salt, iv, config } = json;
                    const mode = config.mode === 'ECB' ? CryptoJS.mode.ECB :
                                config.mode === 'CBC' ? CryptoJS.mode.CBC :
                                config.mode === 'CFB' ? CryptoJS.mode.CFB :
                                config.mode === 'CTR' ? CryptoJS.mode.CTR :
                                CryptoJS.mode.OFB;
                    const key = CryptoJS.PBKDF2(password, CryptoJS.enc.Base64.parse(salt), {
                        keySize: 256/32,
                        iterations: config.iterations
                    });
                    const decrypted = CryptoJS.AES.decrypt(
                        { ciphertext: CryptoJS.enc.Base64.parse(ct) },
                        key,
                        {
                            iv: iv ? CryptoJS.enc.Base64.parse(iv) : undefined,
                            mode: mode,
                            padding: CryptoJS.pad.Pkcs7
                        }
                    );
                    const hmac = CryptoJS.HmacSHA256(CryptoJS.enc.Base64.parse(ct), key).toString(CryptoJS.enc.Base64);
                    if (hmac !== json['hmac-sha256']) {
                        throw new Error('HMAC 驗證失敗');
                    }
                    resultField.value = decrypted.toString(CryptoJS.enc.Utf8);
                } else if (json.ct && json.iv && json.salt) {
                    // SJCL 解密
                    const decrypted = sjcl.decrypt(password, JSON.stringify(json));
                    resultField.value = decrypted;
                } else {
                    throw new Error('無效的密文格式');
                }
            } catch (e) {
                resultField.value = '解密失敗: ' + e.message;
            }
        });
    </script>
</body>
</html>
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

gemini:

代码: 全选

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加密解密工具</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>加密解密工具</h1>

    <div class="container">
        <h2>加密</h2>

        <h4>明文</h4>
        <textarea id="ejc_text" placeholder="輸入明文"></textarea>

        <h4>密碼</h4>
        <input type="password" id="ejc_encryptpw" placeholder="輸入密碼">

        <button type="button" id="ejc_encrypt">加密</button>

        <hr>

        <h3>Crypto.js AES 加密結果:</h3>
        <h4>ECB 模式</h4>
        <pre id="ejc_aes_ecb" class="breakable"></pre>
        <h4>CBC 模式</h4>
        <pre id="ejc_aes_cbc" class="breakable"></pre>
        <h4>CFB 模式</h4>
        <pre id="ejc_aes_cfb" class="breakable"></pre>
        <h4>CTR 模式</h4>
        <pre id="ejc_aes_ctr" class="breakable"></pre>
        <h4>OFB 模式</h4>
        <pre id="ejc_aes_ofb" class="breakable"></pre>

        <hr>

        <h3>SJCL AES 加密結果:</h3>
        <h4>CBC 模式</h4>
        <pre id="sjcl_mode_cbc" class="breakable"></pre>
        <h4>CCM 模式</h4>
        <pre id="sjcl_mode_ccm" class="breakable"></pre>
        <h4>CTR 模式</h4>
        <pre id="sjcl_mode_ctr" class="breakable"></pre>
        <h4>GCM 模式</h4>
        <pre id="sjcl_mode_gcm" class="breakable"></pre>
    </div>

    <div class="container">
        <h2>解密</h2>

        <h4>加密結果</h4>
        <textarea id="ejc_encrypttext" placeholder="貼上加密結果"></textarea>

        <h4>密碼</h4>
        <input type="password" id="ejc_decryptpw" placeholder="輸入密碼">

        <button type="button" id="ejc_decrypt">解密</button>

        <h4>解密結果</h4>
        <textarea id="ejc_decryptresult" readonly placeholder="解密結果將顯示在這裡"></textarea>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sjcl/1.0.8/sjcl.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

代码: 全选

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
    background-color: #f4f4f4;
    color: #333;
}

h1 {
    text-align: center;
    color: #0056b3;
}

h2 {
    color: #0056b3;
    border-bottom: 2px solid #0056b3;
    padding-bottom: 5px;
    margin-top: 20px;
}

h3 {
    color: #0056b3;
    margin-top: 15px;
}

h4 {
    color: #555;
    margin-top: 10px;
}

.container {
    background-color: #fff;
    padding: 20px;
    margin-bottom: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

textarea, input[type="password"] {
    width: calc(100% - 20px);
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
    font-size: 16px;
}

textarea {
    min-height: 100px;
    resize: vertical;
}

button {
    background-color: #007bff;
    color: white;
    padding: 10px 15px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
    width: 100%;
    box-sizing: border-box;
    margin-top: 10px;
}

button:hover {
    background-color: #0056b3;
}

pre {
    background-color: #e9e9e9;
    padding: 10px;
    border-radius: 4px;
    overflow-x: auto; /* Allow horizontal scrolling for long lines */
    white-space: pre-wrap; /* Force wrapping for pre content */
    word-wrap: break-word; /* Break long words */
    margin-bottom: 10px;
    cursor: pointer;
    font-size: 14px;
}

pre:hover {
    background-color: #dcdcdc;
}

hr {
    border: 0;
    border-top: 1px dashed #ccc;
    margin: 20px 0;
}

/* Mobile responsiveness */
@media (max-width: 600px) {
    body {
        padding: 10px;
    }

    .container {
        padding: 15px;
    }

    textarea, input[type="password"], button {
        font-size: 14px;
    }
}

代码: 全选

document.addEventListener('DOMContentLoaded', () => {
    const ejcText = document.getElementById('ejc_text');
    const ejcEncryptPw = document.getElementById('ejc_encryptpw');
    const ejcEncryptBtn = document.getElementById('ejc_encrypt');

    const ejcAesEcb = document.getElementById('ejc_aes_ecb');
    const ejcAesCbc = document.getElementById('ejc_aes_cbc');
    const ejcAesCfb = document.getElementById('ejc_aes_cfb');
    const ejcAesCtr = document.getElementById('ejc_aes_ctr');
    const ejcAesOfb = document.getElementById('ejc_aes_ofb');

    const sjclModeCbc = document.getElementById('sjcl_mode_cbc');
    const sjclModeCcm = document.getElementById('sjcl_mode_ccm');
    const sjclModeCtr = document.getElementById('sjcl_mode_ctr');
    const sjclModeGcm = document.getElementById('sjcl_mode_gcm');

    const ejcEncryptText = document.getElementById('ejc_encrypttext');
    const ejcDecryptPw = document.getElementById('ejc_decryptpw');
    const ejcDecryptBtn = document.getElementById('ejc_decrypt');
    const ejcDecryptResult = document.getElementById('ejc_decryptresult');

    // --- 加密功能 ---
    ejcEncryptBtn.addEventListener('click', () => {
        const plaintext = ejcText.value;
        const password = ejcEncryptPw.value;

        if (!plaintext || !password) {
            alert('請輸入明文和密碼!');
            return;
        }

        // Crypto.js 加密
        try {
            const cryptoAesEcb = CryptoJS.AES.encrypt(plaintext, password, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
            ejcAesEcb.textContent = JSON.stringify({
                ct: cryptoAesEcb.ciphertext.toString(CryptoJS.enc.Base64),
                salt: cryptoAesEcb.salt ? cryptoAesEcb.salt.toString(CryptoJS.enc.Base64) : '',
                iv: cryptoAesEcb.iv ? cryptoAesEcb.iv.toString(CryptoJS.enc.Base64) : '',
                'hmac-sha256': '', // ECB typically doesn't use HMAC for direct encryption
                config: { mode: 'ECB', padding: 'Pkcs7', iterations: 1 }
            }, null, 2);

            const cryptoAesCbc = CryptoJS.AES.encrypt(plaintext, password, { mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
            ejcAesCbc.textContent = JSON.stringify({
                ct: cryptoAesCbc.ciphertext.toString(CryptoJS.enc.Base64),
                salt: cryptoAesCbc.salt ? cryptoAesCbc.salt.toString(CryptoJS.enc.Base64) : '',
                iv: cryptoAesCbc.iv ? cryptoAesCbc.iv.toString(CryptoJS.enc.Base64) : '',
                'hmac-sha256': '',
                config: { mode: 'CBC', padding: 'Pkcs7', iterations: 1 }
            }, null, 2);

            const cryptoAesCfb = CryptoJS.AES.encrypt(plaintext, password, { mode: CryptoJS.mode.CFB, padding: CryptoJS.pad.NoPadding }); // CFB often uses NoPadding
            ejcAesCfb.textContent = JSON.stringify({
                ct: cryptoAesCfb.ciphertext.toString(CryptoJS.enc.Base64),
                salt: cryptoAesCfb.salt ? cryptoAesCfb.salt.toString(CryptoJS.enc.Base64) : '',
                iv: cryptoAesCfb.iv ? cryptoAesCfb.iv.toString(CryptoJS.enc.Base64) : '',
                'hmac-sha256': '',
                config: { mode: 'CFB', padding: 'NoPadding', iterations: 1 }
            }, null, 2);

            const cryptoAesCtr = CryptoJS.AES.encrypt(plaintext, password, { mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding }); // CTR often uses NoPadding
            ejcAesCtr.textContent = JSON.stringify({
                ct: cryptoAesCtr.ciphertext.toString(CryptoJS.enc.Base64),
                salt: cryptoAesCtr.salt ? cryptoAesCtr.salt.toString(CryptoJS.enc.Base64) : '',
                iv: cryptoAesCtr.iv ? cryptoAesCtr.iv.toString(CryptoJS.enc.Base64) : '',
                'hmac-sha256': '',
                config: { mode: 'CTR', padding: 'NoPadding', iterations: 1 }
            }, null, 2);

            const cryptoAesOfb = CryptoJS.AES.encrypt(plaintext, password, { mode: CryptoJS.mode.OFB, padding: CryptoJS.pad.NoPadding }); // OFB often uses NoPadding
            ejcAesOfb.textContent = JSON.stringify({
                ct: cryptoAesOfb.ciphertext.toString(CryptoJS.enc.Base64),
                salt: cryptoAesOfb.salt ? cryptoAesOfb.salt.toString(CryptoJS.enc.Base64) : '',
                iv: cryptoAesOfb.iv ? cryptoAesOfb.iv.toString(CryptoJS.enc.Base64) : '',
                'hmac-sha256': '',
                config: { mode: 'OFB', padding: 'NoPadding', iterations: 1 }
            }, null, 2);

        } catch (e) {
            console.error('Crypto.js 加密失敗:', e);
            alert('Crypto.js 加密失敗,請檢查輸入或控制台。');
        }

        // SJCL 加密
        try {
            // SJCL 預設為 GCM 模式,且其加密結果包含所有必要資訊
            const sjclOptions = {
                v: 1, // Version
                iter: 1000, // Iterations for PBKDF2
                ks: 128, // Key size in bits
                ts: 64, // Tag size in bits
                adata: "", // Authenticated data
                cipher: "aes" // Cipher name
            };

            const sjclCbcResult = sjcl.encrypt(password, plaintext, { ...sjclOptions, mode: 'cbc' });
            sjclModeCbc.textContent = sjclCbcResult;

            const sjclCcmResult = sjcl.encrypt(password, plaintext, { ...sjclOptions, mode: 'ccm' });
            sjclModeCcm.textContent = sjclCcmResult;

            const sjclCtrResult = sjcl.encrypt(password, plaintext, { ...sjclOptions, mode: 'ctr' });
            sjclModeCtr.textContent = sjclCtrResult;

            const sjclGcmResult = sjcl.encrypt(password, plaintext, { ...sjclOptions, mode: 'gcm' });
            sjclModeGcm.textContent = sjclGcmResult;

        } catch (e) {
            console.error('SJCL 加密失敗:', e);
            alert('SJCL 加密失敗,請檢查輸入或控制台。');
        }
    });

    // --- 點擊 pre 將內容複製到解密區 ---
    const preElements = document.querySelectorAll('pre.breakable');
    preElements.forEach(pre => {
        pre.addEventListener('click', () => {
            ejcEncryptText.value = pre.textContent;
            ejcEncryptText.focus(); // 讓使用者知道內容已被貼上
        });
    });

    // --- 解密功能 ---
    ejcDecryptBtn.addEventListener('click', () => {
        const encryptedText = ejcEncryptText.value;
        const password = ejcDecryptPw.value;

        if (!encryptedText || !password) {
            alert('請輸入加密結果和密碼!');
            return;
        }

        let decryptedResult = '';
        try {
            const parsedData = JSON.parse(encryptedText);

            // 判斷是 Crypto.js 還是 SJCL 的加密結果
            if (parsedData.config && parsedData.config.mode) {
                // Crypto.js 解密
                const decrypted = CryptoJS.AES.decrypt(encryptedText, password);
                decryptedResult = decrypted.toString(CryptoJS.enc.Utf8);
            } else if (parsedData.iv && parsedData.salt && parsedData.ct && parsedData.cipher === 'aes') {
                // SJCL 解密
                decryptedResult = sjcl.decrypt(password, encryptedText);
            } else {
                alert('無法識別加密結果的格式,請確認!');
                return;
            }

            ejcDecryptResult.value = decryptedResult;
        } catch (e) {
            console.error('解密失敗:', e);
            ejcDecryptResult.value = '解密失敗!請檢查密碼或加密結果的格式。';
        }
    });
});
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

grok2317:

代码: 全选

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加密與解密</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <script src="https://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
            max-width: 600px;
            margin: 0 auto;
            background-color: #f4f4f4;
        }
        h2, h4 {
            color: #333;
        }
        textarea, input, button {
            display: block;
            width: 100%;
            margin-bottom: 10px;
            padding: 10px;
            font-size: 16px;
        }
        textarea {
            height: 100px;
            resize: vertical;
        }
        input[type="password"] {
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        button {
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background-color: #0056b3;
        }
        pre {
            background-color: #fff;
            border: 1px solid #ddd;
            padding: 10px;
            white-space: pre-wrap;
            word-wrap: break-word;
            cursor: pointer;
            margin-bottom: 10px;
            border-radius: 4px;
        }
        pre:hover {
            background-color: #f0f0f0;
        }
        @media (max-width: 600px) {
            body {
                padding: 10px;
            }
            textarea, input, button {
                font-size: 14px;
            }
        }
    </style>
</head>
<body>
    <h2>加密</h2>
    <h4>輸入明文與密碼</h4>
    <textarea id="ejc_text" placeholder="輸入明文"></textarea>
    <input id="ejc_encryptpw" type="password" placeholder="輸入加密密碼">
    <button type="button" id="ejc_encrypt">加密</button>

    <h4>CryptoJS AES 加密結果</h4>
    <pre id="ejc_aes_ecb">ECB 模式結果</pre>
    <pre id="ejc_aes_cbc">CBC 模式結果</pre>
    <pre id="ejc_aes_cfb">CFB 模式結果</pre>
    <pre id="ejc_aes_ctr">CTR 模式結果</pre>
    <pre id="ejc_aes_ofb">OFB 模式結果</pre>

    <h4>SJCL AES 加密結果</h4>
    <pre id="sjcl_mode_cbc">CBC 模式結果</pre>
    <pre id="sjcl_mode_ccm">CCM 模式結果</pre>
    <pre id="sjcl_mode_ctr">CTR 模式結果</pre>
    <pre id="sjcl_mode_gcm">GCM 模式結果</pre>

    <h2>解密</h2>
    <textarea id="ejc_encrypttext" placeholder="輸入加密結果(JSON格式)"></textarea>
    <input id="ejc_decryptpw" type="password" placeholder="輸入解密密碼">
    <button type="button" id="ejc_decrypt">解密</button>
    <textarea id="ejc_decryptresult" placeholder="解密結果" readonly></textarea>

    <script>
        // CryptoJS 模式映射
        const cryptoModes = {
            ecb: CryptoJS.mode.ECB,
            cbc: CryptoJS.mode.CBC,
            cfb: CryptoJS.mode.CFB,
            ctr: CryptoJS.mode.CTR,
            ofb: CryptoJS.mode.OFB
        };

        // 加密按鈕事件
        document.getElementById('ejc_encrypt').addEventListener('click', () => {
            const text = document.getElementById('ejc_text').value;
            const password = document.getElementById('ejc_encryptpw').value;
            if (!text || !password) {
                alert('請輸入明文和密碼');
                return;
            }

            // CryptoJS 加密
            for (const [modeName, mode] of Object.entries(cryptoModes)) {
                const salt = CryptoJS.lib.WordArray.random(16);
                const iv = modeName !== 'ecb' ? CryptoJS.lib.WordArray.random(16) : '';
                const key = CryptoJS.PBKDF2(password, salt, { keySize: 256/32, iterations: 1000 });
                const encrypted = CryptoJS.AES.encrypt(text, key, {
                    iv: iv,
                    mode: mode,
                    padding: CryptoJS.pad.Pkcs7
                });
                const hmac = CryptoJS.HmacSHA256(encrypted.ciphertext, key).toString(CryptoJS.enc.Base64);
                const result = {
                    ct: encrypted.ciphertext.toString(CryptoJS.enc.Base64),
                    salt: salt.toString(CryptoJS.enc.Base64),
                    iv: iv ? iv.toString(CryptoJS.enc.Base64) : '',
                    'hmac-sha256': hmac,
                    config: {
                        mode: modeName.toUpperCase(),
                        padding: 'Pkcs7',
                        iterations: 1000,
                        keySize: 256
                    }
                };
                document.getElementById(`ejc_aes_${modeName}`).textContent = JSON.stringify(result, null, 2);
            }

            // SJCL 加密
            const sjclModes = ['cbc', 'ccm', 'ctr', 'gcm'];
            for (const mode of sjclModes) {
                const encrypted = sjcl.encrypt(password, text, { mode: mode, iter: 1000, ks: 128 });
                document.getElementById(`sjcl_mode_${mode}`).textContent = JSON.stringify(JSON.parse(encrypted), null, 2);
            }
        });

        // 點擊 pre 填充加密結果
        document.querySelectorAll('pre').forEach(pre => {
            pre.addEventListener('click', () => {
                document.getElementById('ejc_encrypttext').value = pre.textContent;
            });
        });

        // 解密按鈕事件
        document.getElementById('ejc_decrypt').addEventListener('click', () => {
            const encryptedText = document.getElementById('ejc_encrypttext').value;
            const password = document.getElementById('ejc_decryptpw').value;
            const resultArea = document.getElementById('ejc_decryptresult');

            if (!encryptedText || !password) {
                resultArea.value = '請輸入加密結果和密碼';
                return;
            }

            try {
                const data = JSON.parse(encryptedText);

                // 檢查是否為 SJCL 格式
                if ('v' in data && 'cipher' in data && data.cipher === 'aes') {
                    try {
                        const decrypted = sjcl.decrypt(password, JSON.stringify(data));
                        resultArea.value = decrypted;
                    } catch (e) {
                        resultArea.value = 'SJCL 解密失敗:' + e.message;
                    }
                    return;
                }

                // 假設為 CryptoJS 格式
                const { ct, salt, iv, config } = data;
                const key = CryptoJS.PBKDF2(password, CryptoJS.enc.Base64.parse(salt), {
                    keySize: config.keySize/32,
                    iterations: config.iterations
                });
                const decrypted = CryptoJS.AES.decrypt(
                    { ciphertext: CryptoJS.enc.Base64.parse(ct) },
                    key,
                    {
                        iv: iv ? CryptoJS.enc.Base64.parse(iv) : undefined,
                        mode: cryptoModes[config.mode.toLowerCase()],
                        padding: CryptoJS.pad.Pkcs7
                    }
                );
                const decryptedText = decrypted.toString(CryptoJS.enc.Utf8);
                if (!decryptedText) {
                    resultArea.value = 'CryptoJS 解密失敗:密碼錯誤或數據損壞';
                } else {
                    resultArea.value = decryptedText;
                }
            } catch (e) {
                resultArea.value = '解密失敗:無效的 JSON 格式或數據';
            }
        });
    </script>
</body>
</html>
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 3683
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 154 次
被圈友点赞: 178 次
联系:

Re: 正在研究js-md5

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

正浏览此版面之用户: Ahrefs [Bot], Google [Bot] 和 1 访客