李浩亮,劉永飛
(鄭州大學 信息工程學院,鄭州 450001)
CAS(Conditional Access System,條件接收系統)是一種加密系統方法總稱,通過這個系統可以實現網絡控制、收費、加密、管理等諸多功能,廣泛應用于視頻點播、電子銀行、網上超市、遠程教育等諸多環境。其與數字廣播系統獨立,但對商業的數字廣播系統來說,是其成功運營的基礎、增值服務的命脈,CAS系統須保證未授權用戶不能收看加密節目,而授權的用戶可以收看加密節目,同時可以對單用戶進行識別、控制,消除傳統網路電視的盲目性,是我國數字網絡改造的核心部分。CAS系統由兩部分組成:前端加擾管理系統和終端解擾子系統。機頂盒屬于終端設備,本文介紹的CAS系統屬于終端解擾子系統。
任何一款復雜電子設備,都離不開一款強大的操作系統支持,而Android系統起初是Google公司為移動設備開發的一套操作系統,但由于其開源、擁有OHA聯盟強大的后盾,而且具有獨特的系統架構以及Linux內核底層的穩定支撐,很快有許多其他產品廠商都紛紛開發出Android平臺,使其成為目前在大型嵌入式設備上最流行的操作系統。目前華為、中興等為代表的機頂盒廠商都在紛紛推出基于Android平臺的機頂盒。本文詳細介紹了機頂盒CAS終端子系統的設計過程和移植到Android平臺上的過程。
數字電視節目都是通過介質(地面、電纜、衛星)以TS流的形式傳播的。TS流依據 MPEG-2協議被分成長度188字節的ES包,每一個ES包都有自身識別的PID號,根據PID號的不同分成各種功能不同的表,其中對CAS系統有用的是ECM表和EMM表。EMM(Entitle Manager Message)表為授權管理信息表,里面主要包含每個用戶授權的節目數和對應的SK(Service Key)業務密鑰信息。ECM(Entitle Control Message)表為授權控制信息表,里面含有對解擾最重要的CW(Control Word)控制字,取得對應節目的CW之后,就可以交給安全模塊解擾,解擾后的明文CW就可以用來解擾加密節目,整個解密過程也就完成了。
CA解擾的過程如圖1所示。

圖1 CA解擾的過程
考慮到應用設計與底層硬件智能卡進行交互,且Android系統提供有NDK套件工具,使得底層的其他語言的API與Android應用層JAVA語言無縫對接,所以可以把CAS以庫的形式存放到Android中間層,供Android上層GUI調用。CAS系統的設計用到上述的ECM表和EMM表,但EMM表和ECM表要從PSI中的PMT、CAT表獲得其PID號。圖2、圖3是用專用工具截取的一段PMT和CAT表里面的CA信息。

圖2 CAT表中的ECM表

圖3 PMT表中的EMM表
從圖2可以看出此TS流中的CAT表中含有ca_descriptor描述符,并可以得出ECM的ca_pid為0x0562。而從圖3中可以看出,PMT表中含有的EMM表的ca_pid為0x0ffe。此時就可以設置操作demod來分配filter通道,過濾出 EMM、ECM 表的section_descriptor_table,來取得CA有關的信息。如果用戶要流暢地播放節目,機頂盒(Set-Top Box,STB)就要不斷地獲得密文CW送入智能卡中,從整個解碼過程中可以把整個CAS終端子系統分為3個模塊:EMM解析模塊、ECM解析模塊、智能卡任務模塊。Android系統采用的是Linux內核,保留了posix的pthread、message、memory pool等通用的 API,所以在設計3個模塊時,可以使用pthread_create()創建任務模塊;使用msgget()創建消息,實現3個任務模塊的通信與同步。
由圖1可知,TS流經tuner調諧,把高頻載波去掉,再經過demod解調,就可以根據PES包的PID號和TABLE_ID號設置其里面的filter。一般來說一個demod含有多個filter,在系統啟動開始就會分配PAT表的filter,有PAT表的setction_descriptor的描述就可以得到PMT表的PID,此時同樣分配PMT表的filter。如果此節目是加密節目,在其段描述符中就會含有EMM表的PID號,一旦找到EMM的PID號,就可以為EMM表分配filter。如果EMM里面的CA信息版本號和智能卡存儲的CA信息版本號一致,就舍棄此EMM;如果不一致,就重新改寫智能卡里面的CA用戶的信息。EMM任務模塊流程如圖4所示。

圖4 EMM任務模塊流程
在EMM任務模塊中,通過CAS_EMM_TASK()函數創建任務,在CAS_EMM_TASK()中調用CAS_EMM_ReceiveMessage()函數來接收EMM filter發送過來的CA信息。在沒有EMM流時,EMM任務一直掛起,而一旦filter發現EMM表,就會把EMM的CA信息發送到EMM任務中,同時關掉filter,避免其未處理完此EMM,而又接收新的EMM。此時EMM任務從掛起進入就緒態,從而處理來自filter的EMM信息,處理完之后,再次分配EMM的filter。
通過解讀CAT表可知,此節目表是否加密,如果加密則設置相應ECM的filter過濾出對應的ECM表,此時結合智能卡中存儲的EMM的CA信息,就可以判斷出用戶是否對此節目授權,若授權則取出智能卡中的SK業務密鑰,找出對應的奇偶控制字(CW),送入到智能卡中,通過智能卡系統解密出CW,送入到STB中實現數據、視頻、音頻的解碼。整個過程如圖5所示。

圖5 ECM任務模塊流程
在ECM任務模塊中,通過CAS_ECM_TASK()創建線程任務,在其內部調用CAS_ECM_ReceiveMessage()函數接收來自ECM的filter過濾出的CA信息;此時通過CAS_CARD_ReadMessage()讀取智能卡內部用戶授權信息,來判斷ECM是否有效且取出對應的密文的CW;而用CAS_ECM_SendToCard()函數把密文CW送入到智能卡中解密,解密出明文CW;用CAS_CW_SendToSTB()函數送入到機頂盒,此時解復用模塊接收到明文CW就可以得到解碼加密流了。
智能卡的通信標準有T0和T1兩種,T0按字節傳送,T1按塊傳送,而在設計過程中通常支持兩種協議。一般采用I2C總線通信,而智能卡內部一般沒有上拉電阻,所以在電路設計過程中,SCL和SDA的引腳處必須加上拉電阻,否則無法正常通信。根據通信協議,如果要對智能卡數據讀寫操作,首先要發送5字節的命令字,這5字節命令字依次為CLA、INS、P1、P2、P3,其中CLA為指令類型,INS為命令符,P1、P2為操作文件位置,P3為后續字符數。智能卡接收到命令符就可以根據命令種類對其后續數據進行操作,同時智能卡就可以發出兩個字節W1、W2的應答符。如果成功,W1、W2分別為0x90、0x00;如果不成功則會返回相應的代碼,以便給開發者提供調試。因為智能卡內部十分復雜,篇幅有限,所以想深入了解原理的話可以參考智能卡標準,這里僅介紹機頂盒操作智能卡過程的設計。
如圖6所示,在智能卡任務模塊中,在系統啟動之初,未進入文件系統之前,就要對智能卡進行初始化,分配內存池,強制為智能卡復位,從而選擇通信類型(T0或T1),全部完成之后就可以進入文件系統。通過CAS_CARD_TASK()為智能卡建立線程,在其線程內部使用CAS_CARD_ReceiveMessage()接收來自EMM或者ECM的命令字。如果合法,通過CAS_CARD_SendMessage()可以把應答字給其兩個模塊,同時通知其他兩個模塊發送操作數,若是EMM則到此結束,若為ECM則智能卡會把解密的CW 通過CAS_CARD_SendMessage()發送給機頂盒。

圖6 智能卡任務模塊流程
CAS系統除了最重要的解擾以外,還有其他重要的附屬功能,如郵件、在線付費、在線充值、節目點播、區域限制、用戶管理。這些信息都存儲在EMM表中,所以EMM和ECM表的解析也是一個十分重要的步驟,只有正確地提取出EMM中的CA信息,才能順利地進行下一步的操作。根據MPEG-2標準和PSI/SI協議,以及智能卡廠商的提供功能表,就能設計出EMM和ECM的解析函數。
表1列出了一個通用CA的描述符。

表1 一個通用CA的描述符
由于每個智能卡廠商的填充數據不一樣,所以必須根據廠商的定義再去提取數據、處理數據。由于筆者參與設計的是某公司提供的智能卡,所以數據的格式也都以它為標準。最終設計包括12個源文件、5個頭文件。
CAS終端子系統起初設計由于涉及到與底層交互,采用的是C語言。如果想要使上層的JAVA環境調用其API,就要遵循JNI規范添加新的頭文件,使其應用層能夠方便地調用。同時Google在設計Android之初就提供了NDK套件,有著獨有的交叉編譯器,使得原有的許多C語言編寫的驅動、應用程序可十分方便地移植到Android系統中。
由于是在 Windows下進行開發,所以要在 Windows下模擬Linux的開發環境,需要下載cygwin工具,下載地址為 http://www.cygwin.com/setup.exe。安裝方法請參考相關文檔,這里就不贅述了。同樣也需要Android的NDK套件,下載地址為 http://developer.android.com/sdk/ndk/index.html;可以選擇最新的版本下載,下載完畢,直接解壓到同一路徑下。然后在cygwin的安裝目錄home/Administrator下的./bash_profile文件添加 NDK的路徑,就可以使用NDK下的ndk-build命令了,進入samples/hello-jni。在cygwin中調用ndk-build,如果出現如圖7所示的結果,則NDK的環境已經搭建成功。
筆者使用的是android-ndk-r7b版本,也是目前最新版本,其交叉編譯器位于其toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/arm-linux-android/bin中,庫的頭文件位于/platforms/android-xx/arch-arm/usr/include中,庫位于 platform/android-xx/arch-arm/usr/lib中。知道了編譯器和C庫的頭文件,就可以容易地編寫出makefile。在編寫makefile時需要注意,若用到了posix的pthread庫,則需要添加“LDFLAGS+=-lpthread”,否則在執行鏈接的時候會出現錯誤。編譯完成之后如圖8所示。

圖7 搭建成功后的顯示內容

圖8 編譯完成后的顯示結果
因為CAS子系統提供給外部使用的API達20多個,這里以CASTB_GetVersion()函數為例,其他都是如此實現。新建一個文件夾,命名為STBCA,在文件下建立兩個文件夾分別命名為JNI和SRC。JNI存放為CAS的JNI本地 API,源文件為castb_api_jni.c;SRC存放的是上層JAVA應用程序,根據JNI標準則需把CASTB_GetVersion()定義為“Java_com_jpf_stbca_STBCA_CASTB_Get-Version();”。只要調用3.2小節的中libCAS.a庫中的源函數就實現了對原函數的包裝,在同一目錄下添加android.mk,內容如下所示:


通過3.1小節的步驟就可以生成cas_jni.so庫,上層如果要調用cas_jni.so庫中的函數只要在JAVA文件中聲明 public native CASTB_GetVersion()函數,且使用“static{system.loadlibrary("cas_jni");}”把動態庫加載到連接器中,就完成了全部的設計。通過實踐,負責上層軟件編寫的同時能夠無縫地實現CAS系統API的調用。
本文詳細闡述了CAS子系統的開發過程和Android系統移植。在Android機頂盒的開發過程中,使用的是華為的H3716C平臺,筆者承擔了CAS系統和PSI/SI節目表解析的開發與移植。使用此CAS子系統播放加密節目,持續穩定地播放一周而且沒有出現馬賽克或卡現象,說明此CAS子系統比較穩定。但CAS是一套功能完整的獨立系統,而筆者只是重點探討解密的過程,許多其他功能未有涉及,若想深入了解CAS系統,請參考CAS系統標準。
[1]ANSI ISO/IEC 13818-1-2000信息技術.移動畫面和相關音頻信息的通用編碼系統[S].
[2]Download the Android NDK[OL].[2012-03].http://developer.android.com/sdk/ndk/index.html.
[3]韓超,梁泉.Android系統原理及開發要點詳解[M].北京:電子工業出版社,2010.