昨天講完 RFC 8216 規格定義的「#EXT-X-KEY 沒帶 IV 屬性時,要用媒體序號推算」,回頭檢查這個系列素材專案裡實際的實作,發現一個真實存在的落差。
async def get_aes_iv(encryption) -> bytes | None:
if encryption.iv is None:
return None
return bytes.fromhex(encryption.iv.replace("0x", ""))
這段程式碼在 IV 沒有明講時,直接回傳 None,而不是照規格用媒體序號推算。把 None 傳進 AES.new(key, AES.MODE_CBC, iv),底層加密函式庫會直接拋出錯誤(CBC 模式要求 IV 必須是固定長度的位元組),不會產出一份解密失敗但看起來正常的檔案——某種意義上這反而是比較安全的失敗方式:它會在下載階段就明確中斷,而不是悄悄產出一份內容錯誤的結果。
這個分支只有在遇到「#EXT-X-KEY 存在,但沒有帶 IV 屬性」的內容時才會被觸發。如果實際遇到的來源長期以來都會明講 IV,這個分支從來沒被真正走過,程式碼看起來一直「能動」,直到某天遇到一個沒明講 IV 的來源,才會第一次暴露出這個缺口。「這段程式碼跑了很久沒出過事」,不代表這段程式碼是對的,只代表還沒遇到觸發它的情境。
值得誠實面對的是:不是每個沒覆蓋到的規格細節都值得馬上補齊。如果目前實際遇到的所有來源都會明講 IV,補上這個分支的優先順序就不高;但至少要明確知道這個缺口存在,而不是誤以為自己已經完整實作了規格。這正是第二部一直在強調的:協定的行為細節,要對照規格文件確認過,不能只憑「目前跑起來沒出過事」就當作已經處理正確。
回想你的專案裡有沒有類似的情況——某個分支對應規格裡的一個邊界情況,但因為長期沒被觸發,你其實不確定它是不是真的實作正確?
明天離開加密話題,進入下載引擎的細節:每個片段各自重試,而不是整份清單重新下載一次。