文章目錄
- 摘要
- 什麼是Java Card?
- Java Card的 生命週期
- Java Card虛擬機器的 生命週期
- Java Card applet和對象的 生命週期
- ava Card 2.0語言子集
- Java Card 2.0架構
- Java Card安全性
- Java Card內部工作原理
- 怎樣編寫Java Card小應用程式?
- 結論
- 參考資料
摘要
Java Card是能運行Java 程式的智慧卡。針對這種新的Java平台,Sun公司的JavaSoft部門已經制訂了Java Card 2.0 API技術規範,目前,已有若干授權方正在智慧卡上實現這種API。要編寫與2.0相容的Java Card 應用程式,開發人員需要從體繫結構上瞭解Java Card的內涵,其核心類的含義,以及如何針對智慧卡開發應用程式。本文將詳細討論Java Card技術,為您,即開發人員,提供 有關智慧卡內 Java平台 的系統體繫結構、應用編程介面和運行環境的技術指南。( 4,000字)
作者:Zhiqun Chen,Rinaldo Di Giorgio專稿
本文將首先簡單介紹智慧卡,並簡要回顧智慧卡標準ISO 7816。根據Java Developer (開發人員專欄)以前發表的有關智慧卡的文章,本文將首先回答這樣一個問題:"什麼是Java Card?",並簡單介紹Java Card系統體繫結構。然後,將集中討論與Java Card相關的若干問題(包括Java Card的生命週期;Java Card 2.0語言子集和API庫類;以及Java Card的安全性)。隨後還將討論Java Card運行環境和Java Card工作原理。最後舉例說明Java Card的應用:針對Java Card編寫的電子錢包應用程式。
本文中凡提到Java Card時均指Java Card 2.0。
什麼是智慧卡?
智慧卡與信用卡大小相同,可通過嵌入到其塑料基體中矽片上的電子電路來儲存和處理資訊。智慧卡主要分為兩類:包含有微處理器並具有讀、寫和計算功能的智慧卡(如小型微電腦)。另一類為沒有微處理器的記憶卡 ,它只能儲存資訊。記憶卡利用安全邏輯演算法控制對儲存空間的存取。
所有智慧卡都包括三類儲存空間:
永久不變儲存空間(persistent non-mutable memory);永久可變儲存空間(persistent mutable memory);和非永久可變儲存空間(non-persistent mutable memory)。ROM、EEPROM和RAM是目前智慧卡的三類儲存空間中使用最普遍的。永久儲存空間又稱非易失性儲存空間。在本文中我們將交替使用術語永久儲存空間和非易失性儲存空間。
國際標準組織規定的ISO 7816第1-7部分包括覆蓋智慧卡各個方面的一組標準。ISO 7816包括:
- 物理特性(第1部分)
- 尺寸和觸點位置(第2部分)
- 電子訊號和傳輸協議(第3部分)
- 行業間交換指令(第4部分)
- 應用程式識別碼符(第5部分)
- 行業間資料元素(第6部分)
- 行業間SCQL指令(第7部分)
表示智慧卡的物理特性,在ISO 7816第1部分中有規定。
Physical Characteristics ---物理特性
Magnetic Stripe ( Back of card ) ---磁條(卡的背面)
Contacts ---觸點
Embossing area --- 刻字區
Front of Card ---卡的正面
有關ISO 7816和智慧卡的詳細情況,請參見"智慧卡:入門"。
一般的說,智慧卡不包括電源,顯示屏,或鍵盤。它通過其8個觸點,利用串列通訊介面與外部世界互動。ISO 7816第2部分對智慧卡的尺寸和觸點位置有詳細規定。表示智慧卡的觸點。
Eight Contact Points --- 8個觸點
Power Supplier ---電源
Reset ---複位
Check ---檢查
Ground ---接地
Optional Contact ---可選觸點
Input/Output ---輸入/輸出
Optional Contacts ---可選觸點
智慧卡插入可能與另一台電腦相連的卡接收裝置(CAD)。卡接收裝置又可稱作終端、讀卡機和IFD (介面裝置)。 都具有相同的準系統,即向智慧卡提供電源和建立資料轉送串連。
當兩台電腦彼此進行通訊時,它們交換根據一系列協議構造的資料包。類似地,智慧卡也使用自己的資料包---稱作APDU (應用協議資料單元)與外部世界對話。APDU包含一條指令或響應資訊。在智慧卡的世界裡 採用的是主 從 模式,而智慧卡永遠扮演從動的角色。換句話說,智慧卡總是在等待來自終端的 命令APDU。隨後,它執行APDU規定的動作,並以一個 應答APDU向終端作出回答。智慧卡與終端之間互相交換 命令APDU和 應答APDU。
下表分別表示 命令APDU和 應答APDU的格式。ISO 7816第4部分對APDU的結構有專門描述。
命令APDU |
標題頭(必須) |
主體(可選) |
CLA |
INS |
P1 |
P2 |
Lc |
資料欄位 |
Le |
標題 頭對被選指令進行編碼。它包括4個欄位:類(CLA)、指令(INS)、和參數1和2 (P1和P2)。每個欄位包含一個位元組:
- CLA:類位元組。在很多智慧卡上,這個位元組用來表示應用程式。
- INS:指令位元組。這個位元組表示指令代碼。
- P1-P2:參數位元組。這些位元組對 命令APDU提供進一步說明。
Lc表示 命令APDU的資料欄位的位元組數;Le表示以下 應答APDU 的資料欄位希望的位元組數。
應答APDU |
主體(可選) |
尾部(必須) |
資料欄位 |
SW1 |
SW2 |
狀態 位元組 SW1和SW2表示 命令APDU在智慧卡中的處理狀態。
什麼是Java Card?
Java Card是能運行Java程式的智慧卡。Java Card 2.0技術規範刊登在http://www.javasoft.com/javacard上。它包括有關在智慧卡上建立Java Card虛擬機器和應用編程介面(API)的詳細資料。 最低系統要求為16 kbps唯讀記憶體(ROM)、8 kbps EEPROM和256位元組隨機存取儲存空間(RAM)。
Java Card上的系統體繫結構如下 頁圖所示。 其中:
Applet ---小應用程式
Industry Add on Classes ---企業添加類
javacard Framework --- Javacard架構
OS & Native Functions ---作業系統和本地功能
如 圖所示,Java Card虛擬機器是建立在特定整合電路(IC)和本機作業系統執行程式上的。JVM層利用一般語言和系統介面隱藏了製造商的專利技術。Java Card架構定義了一系列用來開發Java Card應用程式和為這些應用程式提供系統服務的應用程編程介面(API)。某特定 行業或特殊的商務應用可提供添加的庫,以提供服務或最佳化安全性和系統模型。Java Card應用程式 稱為applets。一個卡上可駐留多個applets。每個applets均被其AID (應用程式識別碼符)唯一標識,如ISO 7816第5部分的規定。
應該注意的重要的一點是,智慧卡不是個人電腦。它們只有有限的儲存空間資源和計算功能。使用者不應該簡單地認為Java Card 2.0是JDK的簡化版本。
Java Card的 生命週期
Java Card的 生命週期從本機作業系統、Java Card虛擬機器、API類庫和可選的applets被 寫入ROM時開始。將一個可處理進入 命令的永久性組件 寫入晶片的非可變儲存空間,這一過程又稱作掩模(masking)。
在安裝入您的錢包之前,Java Card需要經過初始化和個人化。初始化指在卡的非可變儲存空間內裝入一般資料。這種資料對很多智慧卡都是相同的,而並非某種卡所特有的;例如發行商或製造商的名稱。
下一個步驟,個人化,指將卡分配予某個人。這個過程可通過物理個人化或電子個人化完成。物理個人化指在卡的塑料表面上壓印或雷射壓印您的名字和卡號。電子個人化指在卡的非可變儲存空間中裝載個人資料,例如您的個人密鑰、名字和個人身份代碼。
各廠家和發行商所採用的初始化和個人化的方法不盡相同。對這兩個過程來說,通常都是用EEPROM (一類非可變儲存空間)儲存資料。
現在,Java Card就可以使用了。您可以從發行商 處購買Java Card,也可從零售商 處購買Java Card。零售商銷售的卡是通用型的,一般都沒有經過個人化。
現在,您可以把您的Java Card插入讀卡機,並向駐留在卡上的applet發送 命令APDU,或向卡內下載其它applet或資料。
除非Java Card失效或因某種不可恢複的錯誤而被閉鎖,否則Java Card就能一直使用下去。
Java Card虛擬機器的 生命週期
與PC或工作站上的Java虛擬機器(JVM)不同,Java Card虛擬機器可永遠工作。
即使電源斷開(即卡從讀卡機上取下),儲存在卡上的多數資訊也必須儲存下來。Java Card虛擬機器可在EEPROM上建立能儲存永久資訊的對象。Java Card虛擬機器的執行壽命就是卡的壽命。在沒有電源的情況下,虛擬機器按照無限的刻度工作。
Java Card applet和對象的 生命週期
Applet的生命週期始自它正確安裝並被註冊到系統的註冊表中,而當它被從 註冊表中刪除時其生命週期就結束了。被刪除的applet的空間可能被再次使用,也可能不再使用,這取決於卡上是否實現了垃圾收集功能。卡上的applet只有當被終端明確選擇後才會 處於啟用 狀態。
對象是在永久儲存空間(如EEPROM )中建立的。如果不被其它永久對象所引用,對象就可能丟失或被當做垃圾收集。但向EEPROM寫入的速度要比向RAM寫入的速度慢1000倍。
某些對象經常被使用,其欄位的內容就不必是永久的。Java Card支援RAM中的瞬態(暫時)對象。如果某個對象被宣布為瞬態 ,則其內容就不能 寫入永久儲存空間。
ava Card 2.0語言子集
Java Card程式當然是用Java編寫的。它們 可以用一般的Java編譯器來編譯。因為儲存空間資源和計算能力有限,所以Java Card並不能支援Java語言技術規範中規定的所有語言功能。特別地,Java Card不支援:
- 動態類裝載
- 安全管理器
- 線程和同步
- 對象複製
- 對象回收(finalization)
- 長基礎資料型別 (Elementary Data Type)( float、double、long、和char )
所以支援這些功能的關鍵詞 被省略也就不足為奇了。在有更大儲存空間的更進階智慧卡上,由虛擬機器的實現者決定 是否支援32位整數類型及post-issuance applet的native方法。Post-issuance applet即在卡被發放給持卡人後安裝在Java Card上的applet。
Java Card 2.0架構
智慧卡在市場上已經出現20多年了,多數智慧卡一般都可與ISO 7816第1-7部分和/或EMV相容。我們在前面已經談到ISO 7816。什麼是EMV呢?即EMV,它是由Europay、Mastercard和Visa等公司規定的基於ISO 7816系列的標準,是具有可滿足金融業特定要求的附加專利功能的標準。設計Java Card架構的目的是能輕鬆支援智慧卡系統和應用程式。它隱藏了智慧卡體繫結構的細節,並為Java Card應用程式開發人員提供了相對簡單和直接的編程介面。
Java Card架構套件括4個包:
包名 |
說明 |
javacard.framework |
這是JavaCard的核心包。它定義諸如applet和個人身份代碼(PIN)等類,這些類是Java Card程式和APDU、系統和Util (為Java Card程式、APDU提供運行時 服務和系統服務等,如APDU處理和對象共用等)的基本構件。 |
javacardx.framework |
這個包可為與ISO 7816-4相容的檔案系統提供物件導向的設計。它支援ISO 7816規定的基本檔案(EF)、專用檔案(DF)和面向檔案的APDU。 |
javacardx.crypto和javacardx.cryptoEnc |
這兩個包支援智慧卡所要求的密碼功能。 |
Java Cardx包符合Java命名原則,是Java Card架構的延伸。您 並非 必須在智慧卡上支援這些包。
Java Card安全性
Java applets受Java安全性的限制,但Java Card系統的安全性模式在很多方面與標準Java有所不同。
Java Card不支援安全管理器類。語言 的安全性原則是由虛擬機器實施的。
Java applets建立可儲存和處理資料的對象。對象由建立該對象的applet所擁有。即使applet 有對某個對象的引用,它也不能調用該對象的方法,除非它擁有該對象,或該對象已確定共用。某個applet可與另一個applet或所有applets共用其對象。
applet是Java Card內的獨立實體。其選擇、執行和功能不受駐留在同一張卡上的其它applet的影響。
Java Card內部工作原理
在Java Card內部,JCRE ( Java Card運行環境)引用Java Card虛擬機器和Java Card架構中的類。Java Card內的每個applet都與JCRE賦予的特定AID關聯。
當一個applet 被正確裝入卡的永久儲存空間,並與Java Card架構和卡上的其它庫關聯後,作為applet安裝過程的最後一步,JCRE就調用該applet 的安裝方法。install是一種公用靜態方法, 它被applet類實現以建立 applet的執行個體,並 在JCRE中為其註冊。因為儲存空間是有限的,所以 較好的編程方法就是 在此時建立和初始化applet在其生命期內需要的對象。
駐留在卡上的applet 只有在被明確選擇後才會被啟用。終端向JCRE發送一個" SELECT APDU " 命令。JCRE暫停當前被選的applet ,並調用該applet的deselect方法進行必要的清理。隨後,JCRE把AID已在" SELECT APDU "中規定的applet 標記為當前被選的applet,並調用新被選中的applet 的select方法。select方法使applet 做好接受APDU 命令的準備。JCRE將隨後的APDU 命令發送給當前被選的applet,直到它接收到下一個" SELECT APDU " 命令為止。
怎樣編寫Java Card小應用程式?
示範如何建立Java Card 2.0 applet 的最好方法就是通過範例。下例為可儲存電子現金的電子錢包應用程式。該錢包可處理read_balance、deposit和debit等APDU指令。只有知道錢包所有人的個人身份代碼(PIN)才能進入錢包。
這個例子被製作成兩欄的格式:左欄包括Java代碼及Java風格的註解;右欄提供對左欄 代碼的詳盡解釋。
package bank.purse |
Java Card與標準Java一樣也支援包和標識符名稱慣例 |
import javacard.framework.* ; import javacardx.framework.* ; |
|
public class Wallet extends Applet { /* constants declaration */ |
一個applet是 javacard.framework.Applet 的繼成類的執行個體 |
// code of CLA byte in the command APDU header final static byte Wallet_CLA = (byte)0xB0; |
CLA標識該應用程式 |
// code of INS byte in the command APDU header final static byte Deposit = (byte)0x10; final static byte Debit = (byte)0x20; final static byte Balance = (byte)0x30; final static byte Validate = (byte)0x40; |
INS標識應用程式指令 |
// maximum number of incorrect tries before the PIN is blocked final static byte PinTryLimit = (byte)0x03; // maximum size PIN final static byte MaxPinSize = (byte)0x04; |
PIN對象參數 |
// status word (SW1-SW2) to signal that the balance become neagtive; final static short SW_NEGATIVE_BALANCE = (short)0x6910; |
Applet特定靜態字 |
/* instance variables declaration */ OwnerPIN pin; byte balance; byte buffer[ ]; // APDU buffer |
|
private Wallet( ) { // It is good programming practice to allocate // all the memory that an applet need during its // lifetime inside the constructor pin = new OwnerPIN(PinTryLimit, MaxPinSize); balance = 0; register( ); } // end of the constructor |
private構造 方法---類Wallet的執行個體由其install方法 執行個體化 applet 通過調用Applet類中所定義的register 方法向JCRE登記註冊。現在 對外部 而言,applet 是可見的。 |
public static void install(APDU apdu) { // create a Wallet applet instance new Wallet( ); } // end of install method |
在applet安裝過程的最後一步,方法install被JCRE調用 |
public boolean select( ) { |
|
// returns true to JCRE to indicate that the applet // is ready to accept incoming APDUs . return true; } // end of select method |
這個方法被JCRE調用,表示該applet已被選擇。它執行處理以下APDU資訊所需要的必要初始化 |
public void process(APDU apdu) { // APDU object carries a byte array (buffer) to // transfer incoming and outgoing APDU header // and data bytes between card and CAD buffer = apdu.getBuffer( ); |
在applet被成功選擇之後,JCRE向此方法發送進入的APDU。 APDU對象被JCRE擁有和維護。它封裝了底層的基本傳輸協議 (如ISO7816-3規定的T0或T1 )的細節並提供了通用介面。 |
// verify that if the applet can accept this // APDU message if(buffer[ISO.OFFSET_CLA] !== Wallet_CLA) ISOException.throwIt (ISO.SW_CLA_NOT_SUPPORTED); |
當發生錯誤時,applet可能決定中止過程,並拋出一個包含狀態字(SW1 SW2)的例外,狀態字用於表示卡的處理狀態。 |
switch (buffer[ISO.OFFSET_INS]) { case Balance: getBalance(apdu); return; case Debit: debit(apdu); return; case Deposit: deposit(apdu); return; case Validate: validate(apdu); return; default: ISOException.throwIt (ISO.SW_INS_NOT_SUPPORTED);} } // end of process method |
process方法的主要功能是執行APDU規定的動作,並向終端返回正確的響應。 INS位元組 指定需要執行的動作的類型 |
private void deposit(APDU apdu) { // access authentication if( ! pin.isValidated( ) ) ISOException.throwIt( ISO.SW_PIN_REQUIRED); // Lc byte denotes the number of bytes in the data // field of the command APDU byte numBytes = (byte) (buffer[ISO.OFFSET_LC]); // indicate that this APDU has incoming data and // receive data sharing from the offset // ISO.OFFSET_CDATA byte byteRead = (byte) (apdu.setIncomingAndReceive( ) ); // It is an error if the number of data bytes read does // not match the number in Lc byte if(byteRead != 1) ISOException.throwIt(ISO.SW_WRONG_LENGTH); // increase the balance by amount specified in the // data field of the command APDU balance = (byte) (balance + buffer[ISO.OFFSET_CDATA]); // return successfully return; } // end of deposit method |
參數APDU對象包含一個資料欄位,它 指定 存款的金額。 在從JCRE接收到APDU對象後,APDU緩衝器中有前5個位元組(CLA、INS、P1、P2、Lc/Le )可用。其在APDU緩衝器中的位移量在類ISO中規定。因為資料欄位是可選的,所以applet需要 顯式通知JCRE 擷取額外 的資料位元組。 卡與CAD之間的通訊是在命令APDU和應答APDU對之間交換的。在存錢( deposit ) 例子中, 應答APDU不包含資料欄位。JCRE使用狀態字0×9000 (正常處理)構成正確的應答APDU。applet開發人員不必關心構造正確的 應答APDU的細節。 當JCRE捕捉到一個exception (表示在處理指示時有錯誤)時,JCRE會使用Exception中包含的狀態字構造 應答APDU 。 |
private void debit(APDU apdu) { // access authentication if( ! pin.isValidated( ) ) ISOException.throwIt(ISO.SW_PIN_REQUIRED); byte numBytes = (byte) (buffer[ISO.OFFSET_LC]); byte byteRead = (byte) (apdu.setIncomingAndReceive( ) ); if(byteRead != 1) ISOException.throwIt(ISO.SW_WRONG_LENGTH); // balance can not be negative if(balance - buffer[ISO.OFFSET_CDATA]) <0) ISOException.throwIt(SW_NEGATIVE_BALANCE); balance = (byte) (balance - buffer[ISO.OFFSET_CDATA]); } // end of debit method |
在debit方法中,APDU對象包含一個資料欄位, 該資料欄位 指定了提款的金額。 |
private void getBalance(APDU apdu) { // access authentication if(! Pin.isValidated( ) ) ISOException.throwIt(ISO.SW_PIN_REQUIRED); // inform system that the applet has finished processing // the command and the system should now prepare to // construct a response APDU which contains data field apdu.setOutgoing( ); // indicate the number of bytes in the data field apdu.setOutgoingLength(byte)1); // move the data into the APDU buffer starting at offset 0 buffer[0] = balance; // send 1 byte of data at offset 0 in the APDU buffer } // end of getBalance method |
getBalance在 應答APDU的資料欄位中返回錢包的餘額。 因為應答APDU響應中的資料欄位是可選的,所以applet 需要 顯式 告訴JCRE 它要返回的資料。JCRE使用APDU對象緩衝器內的數組和正確的狀態字構造一個完整的 應答APDU 。 |
private void validate(APDU apdu) { // retrieve the PIN data which requires to be validated // the user interface data is stored in the data field of the APDU byte byteRead = (byte) (apdu.setIncomingAnd Receive( ) ); // validate user interface and set the validation falg in the user interface // object to be true if the validation succeeds. // if user interface validation fails, PinException would be // thrown from pin.check( ) method pin.check(buffer, ISO.OFFSET_CDATA, byteRead); } // end of validate method } // end of class Wallet |
PIN是智慧卡常用的保護資料免遭越權使用的方法。 PIN中記錄自上次正確的PIN確認後不成功的嘗試次數。如果不成功的嘗試次數超過PIN規定的允許最大嘗試次數,則卡就被閉鎖。 在成功選擇applet後,首先必須使PIN生效,然後才能在applet上執行其它指令。 |
結論
本文首先介紹了智慧卡的一些基本概念,然後闡述了Java Card 2.0的技術和開發Java Card應用程式的方法。Java Card applet是用一般的Java 編譯器編譯的。 編譯器的輸出結果(class 檔案)被輸入Java Card轉換器,後者 增強了Java Card 2.0 語言子集的相容性,可執行名字解析和初始地址連結,並最佳化Java位元組代碼 使之更適合 在Java Card虛擬機器上運行。轉換器的輸出結果被下載到Java Card上。本文對轉換器和applet 安裝協議沒有詳細說明,因為這些協議尚未標準化。我們 希望在今後的文章中能夠闡述這方面的問題。
Java Card為Java世界添加了一種新的平台。Java Card的廣泛採用和部署需要市場的推動、更多的應用程式和工具 的開發及時間。同時,在今後幾年裡,Java Card的使用數量將增加到上百萬。也就是說,您不久就會使用隨身攜帶的錢包裡的小卡片來儲存個人資訊和下載應用程式了。
參考資料
- 有關智慧卡Java Developer系列文章的第一篇文章是"智慧卡入門"
http://www.javaworld.com/jw-12-1997/jw-12-javadev.html
- 有關與Java Card相關的商業機會,請參見"把貨幣交給Java Card API "
http://www.javaworld.com/javaworld/jw-02-1998/jw-02-javacard.html
- 有關在Java Card 1.0 API上開發應用程式的方法,請參見" Java Card速成"
http: //www.javaworld.com/javaworld/jw-02-1998/jw-02-javadev.html
- Java Card網站JavaSoft
http://www.sun.com/products/javacard/
- Java商業網站
http://java.sun.com/products/commerce/
- Javasoft部的Java Card技術總監Joshua Susser對本文進行了審閱並提供了技術指導,謹在此向他表示衷心感謝。