# 密碼系統分析 ## 概述 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; // 驗證成功 } ```