前兩部分已完成 ASN.1 基礎建設與 TGT 請求產生,本文進入 KDC 回應處理、服務票據申請、安全上下文建立 的完整流程,並實作所需的底層 ASN.1 解析與加密輔助方法。
範例採用 Microsoft KDC (Windows Server)。須於 KDC 設定允許特定用戶 略過預驗證 (padata) 直接請求 TGT,以降低行動裝置運算負擔。詳細設定步驟請參考原始碼包內 readme.txt。
KerberosClient.getTicketResponse() 新增 Datagram 通訊邏輯:
Datagram dg = dc.newDatagram(ticketRequest, ticketRequest.length);
dc.send(dg);
// 接收回應
Datagram resp = dc.newDatagram(700);
dc.receive(resp);
byte[] ticketResponse = new byte[resp.getLength()];
System.arraycopy(resp.getData(), 0, ticketResponse, 0, resp.getLength());
同一方法同時支援 TGT 請求 (msg-type=10) 與服務票據請求 (msg-type=12),透過 kerberosTicket != null 判斷。
新增解析端方法:
isSequence(byte):檢查 Tag 0x30。getIntegerValue(byte[]):ASN.1 INTEGER (大端序) 轉 J2ME int (最多 4 byte)。isASN1Structure(byte, tagType, tagNumber):比對 Tag 類型與編號。getNumberOfLengthBytes(byte):解析長度欄位佔用位元組數。getLength(byte[], offset):計算指定位移處結構總長度 (含 Tag/Length/Value)。getASN1Structure(byte[], tagType, tagNumber):從序列中擷取指定 Tag 結構。getContents(byte[]):剝離 Tag/Length 回傳純 Value 位元組。encrypt/decrypt(key, data, iv):Bouncy Castle DES-CBC,IV 可選。getMD5DigestValue(data):Bouncy Castle MD5Digest 計算 16-byte 雜湊。decryptAndVerifyDigest(encData, key):完整解密 EncryptedData (Tag 0=etype, 1=kvno, 2=cipher) 流程:
getTicketAndKey(ticketResponse, decryptionKey) 統一處理 TGT 回應 (App Tag 11) 與服務票據回應 (App Tag 13):
ticket (Context Tag 5) 與 enc-part (Context Tag 6)。decryptAndVerifyDigest() 解密 enc-part 獲取 EncKDCRepPart (App Tag 25/26)。key (Context Tag 0) → EncryptionKey → keyvalue (Context Tag 1) → OCTET STRING 內容,即為會話金鑰或子會話金鑰。TicketAndKey 物件回傳。getTicketResponse() 進入 kerberosTicket != null 分支:
cksum (cksumtype=7=RSA-MD5)。getAuthenticationHeader() 產生 KRB_AP_REQ (App Tag 14),內含 TGT 與以會話金鑰加密的 Authenticator (App Tag 2),Authenticator 含 pvno、crealm、cname、cksum、cusec=0、ctime。authorDigestAndEncrypt(key, data):與 decryptAndVerifyDigest 互為逆操作。產生 8-byte confounder、16-byte 零校驗和、填充資料 → 串接 → 計算 MD5 → 回填校驗和 → DES-CBC 加密 → 包裝成 EncryptedData (etype=3, cipher=OCTET STRING)。getChecksumBytes(cksumData, cksumType):建構 Checksum SEQUENCE (cksumtype Tag 0, checksum Tag 1)。getAuthenticationHeader(ticket, realm, name, checksum, key, seqNum):依 seqNum 決定是否包含 subkey/seq-number,完整建構 KRB_AP_REQ。