From 482be9db5f70a7d2a78f4e22b611c75647c940d6 Mon Sep 17 00:00:00 2001 From: accusys Date: Sun, 29 Mar 2026 00:54:38 +0800 Subject: [PATCH] Add password system analysis document --- GC_PasswordSystem.md | 256 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 GC_PasswordSystem.md diff --git a/GC_PasswordSystem.md b/GC_PasswordSystem.md new file mode 100644 index 0000000..3ba0e18 --- /dev/null +++ b/GC_PasswordSystem.md @@ -0,0 +1,256 @@ +# 密碼系統分析 + +## 概述 + +RAIDGuard X 使用密碼系統來控制對 RAID 控制器的訪問權限。以下是密碼相關的功能: + +## 密碼類型 + +| 密碼類型 | 說明 | 預設值 | +|-----------|------|--------| +| 控制器密碼 | 連線到控制器時驗證 | `00000000` | +| 進階功能密碼 | 用於進階功能 (如 Update Firmware) | `WANGWANG` 或 `=AU4@A83` | + +## 密碼驗證流程 + +### 1. 密碼檢查 (PwdCheck) + +``` +使用者操作進階功能 + → PwdCheck(loc) + → 檢查 sPwd[SN] 是否為空 + → 若為空,彈出密碼輸入對話框 (dlgPasswordCheck) + → 驗證密碼正確性 + → 成功後才允許執行 +``` + +### 2. 密碼輸入對話框 (dlgPasswordCheck) + +```java +// dlgPasswordCheck.java +public void jbOk_actionPerformed() { + // 取得使用者輸入的密碼 (8 字元) + String inputPwd = jpPwd.getSelectedText(); + + // 儲存到 PageDataDB.sPwd[] + PageDataDB.sPwd[SNToNo(sSN)] = inputPwd + " "; + + // 發送密碼到控制器驗證 + // OpCode: 0x1D + // SubOp: 0x08 + // 密碼: raw char values (無轉換) + bCmds[3] = 0x1D; // OpCode + bCmds[4] = 0x08; // Length + bCmds[5-12] = password bytes (charAt(i)) +} +``` + +## 密碼發送機制 + +### OpCode: 0x1D - SEND_PASSWORD + +**CDB 結構:** + +| Offset | 值 | 說明 | +|--------|-----|------| +| 0 | 0x00 | Phase Code | +| 1 | 0x00 | Request Code | +| 2 | 0x00 | Controller No | +| 3 | 0x1D | OpCode - SEND_PASSWORD | +| 4 | 0x08 | Length (8 bytes) | +| 5-12 | password | 8 bytes password | + +### 密碼位元組轉換 + +**有兩種不同的轉換方式:** + +#### 方式 1: dlgPasswordCheck (直接發送) +```java +// 密碼直接作為 char 發送 +bCmds[5] = (byte) password.charAt(0); +bCmds[6] = (byte) password.charAt(1); +// ... +``` + +#### 方式 2: SendCmd.sendPassword (減法轉換) +```java +// 密碼字元減去 0x30 +pwdBytes[i] = (byte) (password.charAt(i) - 0x30); + +// Example: +// '0' (0x30) → 0x00 +// '1' (0x31) → 0x01 +// '9' (0x39) → 0x09 +// 'A' (0x41) → 0x11 +``` + +## 密碼儲存 + +### PageDataDB.sPwd[] + +```java +// 全域密碼儲存陣列 +public static String sPwd[] = new String[iMaxHosts]; + +// 根據序號查詢密碼索引 +public static int SNToNo(String sSN) { + // 查詢 sSNToNo[][] 對應表 + // 回傳該 SN 的密碼陣列索引 +} + +// 儲存密碼 +PageDataDB.sPwd[SNToNo(sSN)] = "00000000"; +``` + +### 密碼對應表 + +``` +sSNToNo[i][0] = 控制器序號 (String) +sSNToNo[i][1] = 密碼索引 (String "0"-"15") +``` + +## 預設密碼 + +### 預設控制器密碼 +``` +預設值: "00000000" (8 個零) +``` + +### 進階功能密碼 + +在 `PageDataDB.GetPlayMenu()` 中檢查: +```java +if (sPwd[SNToNo(sSN)].trim().equals("=AU4@A83") || + sPwd[SNToNo(sSN)].trim().equals("WANGWANG")) { + // 啟用進階功能 (Play Menu) +} +``` + +| 密碼 | 用途 | +|------|------| +| `00000000` | 預設控制器連線密碼 | +| `WANGWANG` | 啟用 Play Menu 進階功能 | +| `=AU4@A83` | 啟用 Play Menu 進階功能 (另一組) | + +## 需要密碼的功能 + +以下功能需要密碼驗證: + +| 功能 | 密碼類型 | +|------|----------| +| Update System Code (Firmware) | 控制器密碼 | +| Update Boot Code | 控制器密碼 | +| Update BIOS/EFI | 控制器密碼 | +| Update Expander Code | 控制器密碼 | +| Dump Controller Log | 控制器密碼 | +| Shutdown Controller | 控制器密碼 | +| Play Menu | 進階密碼 (`WANGWANG` 或 `=AU4@A83`) | + +## 密碼對話框 + +### dlgPasswordCheck + +``` +┌────────────────────────────────────────┐ +│ Password Check │ +│ │ +│ [________________] │ +│ (Default Password: 00000000) │ +│ │ +│ [OK] [Cancel] │ +└────────────────────────────────────────┘ +``` + +### 密碼欄位設定 + +```java +// 固定長度 8 字元 +jpPwd.setDocument(new FixedSizePlainDocument(8)); +jpPwd.setSelectionEnd(8); + +// 密碼可視 (不遮蔽) +// jpPwd.setEchoChar('*'); +``` + +## Code Flow + +### 密碼驗證流程 + +``` +1. 使用者點擊功能 (如 Update Firmware) +2. frmMain.jmXXX_actionPerformed() +3. PageDataDB.PwdCheck(loc) +4. + a. 若 sPwd[SN] 已有密碼 → 自動使用 + b. 若 sPwd[SN] 為空 → 彈出 dlgPasswordCheck +5. + a. 驗證成功 → bPwdCheckPass = true → 執行功能 + b. 驗證失敗 → bPwdCheckPass = false → 拒絕執行 +``` + +### 密碼發送流程 + +``` +1. dlgPasswordCheck.jbOk_actionPerformed() +2. 取得輸入密碼 → 儲存到 sPwd[SN] +3. 建立 CmdQueue 命令 +4. + a. dlgPasswordCheck: 使用 raw char (無轉換) + b. SendCmd.sendPassword: 使用 char - 0x30 轉換 +5. 發送到控制器 (OpCode 0x1D) +6. 等待回應 +7. 驗證成功 → 刷新頁面資料 +``` + +## 關鍵類 + +| 類別 | 檔案 | 功能 | +|------|------|------| +| `PageDataDB` | PageDataDB.java | 密碼儲存與驗證 | +| `dlgPasswordCheck` | dlgPasswordCheck.java | 密碼輸入對話框 | +| `SendCmd` | InBandAPI/SendCmd.java | 密碼發送通訊 | + +## 參考程式碼 + +### SendCmd.sendPassword() +```java +public void sendPassword(String sIP, String sSN) { + // 取得密碼 + String rawPwdStr = PageDataDB.sPwd[SNToNo(sSN)]; + + // 密碼轉換: char - 0x30 + byte[] pwdBytes = new byte[8]; + for (int i = 0; i < 8; i++) { + pwdBytes[i] = (byte) (rawPwdStr.charAt(i) - 0x30); + } + + // 發送 + // OpCode: 0x1D + // Length: 0x08 + // Data: pwdBytes[0..7] + this.send(sIP, sSN, (byte) 0x1D, (byte) 0x08, + pwdBytes[0], pwdBytes[1], pwdBytes[2], pwdBytes[3], + pwdBytes[4], pwdBytes[5], pwdBytes[6], pwdBytes[7]); +} +``` + +### PageDataDB.PwdCheck() +```java +public static int PwdCheck(Point loc) { + if (sSN.trim().equals("")) { + return 0x00; // 無控制器 + } + + if (sPwd[SNToNo(sSN)].equals("")) { + // 彈出密碼輸入對話框 + dlgPasswordCheck dlgPwdCheck = new dlgPasswordCheck(); + dlgPwdCheck.setVisible(true); + + if (dlgPwdCheck.bPwdCheckPass == false) { + return 0x00; // 驗證失敗 + } + } + + return 0x01; // 驗證成功 +} +```