国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java Card 技術(三)

2019-11-17 04:05:26
字體:
來源:轉載
供稿:網友
java Card 應用程序的元素

  請記住,Java Card 應用程序并不是獨立的,而是端到端應用程序的一部分:



圖 1. Java Card 應用程序的典型組件

  Java Card 應用程序通常由以下部分組成:

  提供后臺服務(例如保存在數據庫中的安全或者電子支付信息)訪問的 后臺應用程序。如何開發后臺應用程序超出了本文的范圍。

  主機應用程序 位于卡片外部的卡片終端,它可以使用許多接口(如 Java Card RMI、OpenCard Framework API 或安全性和信任服務應用編程接口 [SATSA])訪問智能卡上的 applet。

  卡片讀取器、卡片終端 或者 卡片接入設備 ,提供了主機應用程序和卡片內部 applet 之間的物理接口。

  卡片內部的物理接口是 Java Card applet 和 Java Card 框架。請注意,在訪問 applet 之前,主機應用程序必須提供證書并進行自我身份驗證。

  編寫主機應用程序 —— 訪問 Applet

  位于客戶端的主機應用程序處理用戶、Java Card applet 和提供器的后端應用程序之間的通信。主機程序訪問由 applet 所提供的服務。它存儲在終端或卡片接入設備上,例如工作站、銷售終端點( POS )、手機或者機頂盒。回想一下,主機和 applet 使用 ISO-7816 APDU 命令通過卡片讀取器或終端進行交互。

  通常,讀取器端應用程序使用 C 語言編寫,但是主機程序用 Java 編程語言或其他語言編寫,只要該語言準備了與 applet 交換的有效 ISO-7816 APDU 命令就沒有問題。

  目前,大多數經過部署的手機集成了智能卡讀取器,以便訪問與該讀取器捆綁的 SIM 卡片。使用即將引入的 JSR 177, 用于 J2ME 的安全性和信任服務應用編程接口(SATSA)、J2ME 設備的廣泛采用,我們能夠預計各種主機應用程序將使用移動設備上的 Java 技術編寫。SATSA 的意圖就是啟用 Java Card 主機應用程序來運行基于 J2ME 的設備。目前,JSR 177 處于 JCP 團體審查階段。

  當編寫客戶端應用程序時,有三個主要的 API 可以使用:OpenCard Framework、Java Card RMI Client API 和用于 J2ME 的安全性和信任服務應用編程接口(SATSA)。我們將逐一研究每一個應用程序編程接口。

  OpenCard Framework 簡介

  智能卡供應商通常不僅提供開發工具箱,還提供 API 以便支持讀取器端應用程序以及 Java Card applet。供應商提供的許多產品都支持 OpenCard Framework ( OCF )和基于 Java 的 API 集合,該集合隱藏了與不同供應商提供的卡片讀取器交互的一些細節。

  OpenCard 聯盟 是一群推動定義和采用 OpenCard Framework( 當前版本為1.2)的公司。OCF 的目標是向主機端應用程序的開發者提供跨不同的卡片讀取器供應商工作的 API。

  為了實現廠商無關性,OCF 定義了兩個軟件層:

  CardTerminal 層提供了卡片讀取器抽象,例如 CardTerminal ( 表示物理卡片讀取器 ) APDU、CommandADPU 和 ResponseAPDU。

  OCF 為您定義了許多標準卡片服務。其中兩個是 FileaccessCardService 和 SignatureCardService。一個特殊的類型是 applicationManagerCardService,提供生命周期管理方法以便安裝、注冊和刪除卡片內部的 applet。

  當編寫主機端基于 OCF 應用程序時,您基本上要將該應用程序分為兩個部分:

  主要的應用程序對象,它與終端或讀取器進行交互(初始化 OCF、等待卡片插入、中斷 OCF ),并公開高級卡片訪問方法,例如 getBalance()。

  Applet 代理,它實現實際的低級通道管理和 APDU I/O。當把來自應用程序的 APDU 細節隱藏起來的時候,該代理設計模式允許公開面向對象的接口。



圖 2. OCF 應用程序的結構

  總而言之,OCF 應用程序有一個或多個 main 對象,它們在主機上或者在執行的線程上創建。這些 main 應用程序對象公開特定于應用程序的高級調用,最終將它們委托給 applet 代理。這些對象利用 OCF 應用程序入口點的 SmartCard 對象,啟用應用程序初始化并中斷 OCF,并等待卡片被插入。main 對象可以實現即將看到的 CTListener,這個偵聽器提供卡片插入和拔出等類似事件的異步通知。



  您可以使用同步或異步模型編寫應用程序。

  在同步模型中,主機應用程序初始化 OCF,然后等待卡片被插入。然后它執行主機應用程序邏輯,當操作完成時,中斷 OCF:

...
try {
// Initialize OCF
SmartCard.start();
// Wait for a smart card
CardRequest cr = new CardRequest(CardRequest.NEWCARD, null,
OCFCardAccessor.class);
SmartCard myCard = SmartCard.waitForCard(cr);
// Main client work is done here...
...
} catch (Exception e){
// Handle exception
} finally {
try {
// Shut down OCF
SmartCard.shutdown();
} catch (Exception e) {
e.PRintStackTrace();
}
}
...


  清單 1. 同步 OCF 應用程序的典型結構

  如果您喜歡使用異步方法,您選定的類必須實現 CTListener 接口,且在初始化階段,進行自我注冊來通知類似插入和拔出這樣的卡片終端事件通知。下列應用程序主干通過初始化 OCF 并注冊偵聽器開始,然后為重要事件定義回調方法。

public class MyHostSideApp implements CTListener
...
public MyHostSideApp() {
try {
// Initialize the framework
SmartCard.start ();
// Register this as a Card Terminal Event Listener
CardTerminalRegistry.getRegistry().addCTListener(this);
} catch (Exception e) {
// handle error...
}
}
public void cardInserted(CardTerminalEvent ctEvent) {
...
}
public void cardRemoved(CardTerminalEvent ctEvent) {
...
}
...
}






  清單 3. 基于偵聽器的放大 OCF 應用程序。

  接下來是一個來自 applet 代理的引用。OCF 應用程序將服務調用委托給實現( 復雜 ) APDU 管理片斷的 applet 代理:

public class MyCardProxy extends AppletProxy {
// My APDU definitions.
final static byte MyAPPLET_CLA = (byte)0x80;
final static byte VERIFY_INS = (byte)0x20;
final static byte GET_BALANCE_INS = (byte) 0x30;
final static short GET_BALANCE_RESPONSE_SZ = 2;
protected final static int OK = 0x9000;
final static short SW_PINVERIFY_FAILED = (short)0x6900;
/**
* Reusable command APDU for getting an information
* entry field.
*/
private CommandAPDU getBalanceAPDU = new CommandAPDU(14);
...
/** Application identifier of the BusinessCard applet */
private static final ApplicationID MY_CARD_AID =
new ApplicationID(new byte[] { (byte)0xD4,
(byte)0x55,
(byte)0x00,
(byte)0x00,
(byte)0x22,
(byte)0x00,
(byte)0x00,
(byte)0x00,
(byte)0xFF});
/**
* Create a MyCardProxy instance.
*
* @param scheduler The Scheduler from which channels
* have to be obtained.
* @param card The SmartCard object to which this
* service belongs.
* @param blocking Currently not used.
*
* @throws opencard.core.service.CardServiceException
* Thrown when instantiation fails.
*/
protected void initialize(CardServiceScheduler scheduler,
SmartCard card, boolean blocking)
throws CardServiceException {
super.initialize(MY_CARD_AID, scheduler, card, blocking);
try {
// Allocate the card channel. This gives us
// exclusive access to the card until we release the
// channel.
allocateCardChannel();
// Get the Card State.
...
} finally {
releaseCardChannel();
}
}
/**
* Gets the balance.
* @return The balance.
*/
public String getBalance()
throws CardServiceInvalidCredentialException,
CardServiceOperationFailedException,
CardServiceInvalidParameterException,
CardServiceUnexpectedResponseException,
CardServiceException,
CardTerminalException {
try {
allocateCardChannel();
// Set up the command APDU and send it to the card.
getBalanceAPDU.setLength(0);
getBalanceAPDU.append(MyAPPLET_CLA); // Class
getBalanceAPDU.append(GET_BALANCE_INS); // Instr'n
getBalanceAPDU.append((byte) 0x00); // P1
getBalanceAPDU.append((byte) 0x00); // P2
getBalanceAPDU.append((byte) 0x00); // Lc
getBalanceAPDU.append((byte) 0x00); // Le
// Send command APDU and check the response.
ResponseAPDU response =
sendCommandAPDU(getCardChannel(), MY_CARD_AID,
getBalanceAPDU);
switch (response.sw() & 0xFFFF) {
case OK :
return new String(response.data());
default :
throw new
CardServiceUnexpectedResponseException
("RC=" + response.sw());
}
} finally {
releaseCardChannel();
}
}
...
}


  清單 4. Applet 代理示例

  在 OpenCard Framework 1.2 編程人員指南 中您會找到關于  OCF 使用的更多信息。還可以參考 OpenCard Framework 參考實現 中的示例文件。

  本文中未涉及,但是值得一提的是主機端 API,稱作 Global Platform。Global Platform Card Committee 提供了補充 Java Card API 的卡片 API 集合,除其他內容以外,還提供了卡片管理功能。這些規范都在2.1.1版本中。

  Java Card RMI 客戶機 API

  前面你已經學到了如何編寫一個基于 JCRMI 的 applet。如果您的 Java Card applet 基于 JCRMI,您可以使用 Java Card RMI Client API編寫一個主機應用程序,訪問智能卡中保存的 apple 對象。

  對于智能卡管理和訪問,JCRMI Client API 需要一個卡片終端和諸如剛剛描述的 OpenCard Framework 這樣的服務 API。

  當我們把這兩個 API 放在一起時,我們得到一個非常簡單、非常完整的面向對象編程模型,有以下幾個優點:

  不必知道智能卡和卡片讀取器的細節

  不必知道低級的 APDU 通信

  便于設計和維護的代碼,從而縮短開發時間

  JCRMI Client API 在下面的軟件包中定義:

  com.sun.javacard.javax.smartcard.rmiclient 包含核心 JCRMI Client API。它定義了以下內容:

  JCRMI 樁模塊用來訪問智能卡的 CardAccessor 接口

  CardObjectFactory 類,用于 JCRMI 樁模塊生成實現的基類。這個類的實例與一個 Java Card applet 選擇會話有關。

  客戶機應用程序使用的 JavaCardRMIConnect 類,用于初始化一個 JCRMI 會話并且獲得初始的遠程引用。

  許多 Java Card 的異常子類,例如 APDUExceptionSubclass、CardExceptionSubclass、CardRuntimeExceptionSubclass、CryptoExceptionSubclass、ISOExceptionSubclass、PINExceptionSubclass、PINException、ServiceExceptionSubclass、SystemExceptionSubclass、TransactionExceptionSubclass 和 UserExceptionSubclass。



  javacard.framework 定義了許多客戶機上的許多可以被再次拋出的 Java Card 異常:APDUException、CardException、CardRuntimeException、ISOException、PINException、SystemException、TransactionException 和 UserException。

  javacard.framework.service 定義了 ServiceException,表示與服務框架有關的異常。

  javacard.security 定義了 CryptoException,用來表示一個有關加密的異常。

  生成 RMI 客戶機樁模塊

  您選擇使用標準的 Java RMI 編譯程序(rmic)生成客戶機樁模塊。您必須使用下面格式的命令運行 rmic,用于你的 applet 中的每個遠程類:

rmic -v1.2 -classpath path -d output_dir class_name


  ......其中:

  -v1.2 是一個 Java Card RMI 客戶機框架所需要的標記。

  -classpath path 確定到遠程類的路徑。

  output_dir 是存放結果樁模塊的目錄

  class_name 是遠程類的名稱。

  然而,推薦生成 RMI 客戶機樁模塊的方法使用 J2SE SDK 1.3 中的 動態代理 生成機制。當您選擇 JCRMI applet 的時候,如果使用 CardObjectFactory 子類型 JCCardProxyFactory 的話,JavaCard RMI Client API 的 2.2 版本將為你自動生成樁模塊,你不必再生成任何樁模塊!這個方法在清單 5 中加以說明。

  用法限制

  因為 Java Card 是一個有限制的運行時環境,我們可以發現關于 JCRMI 實際支持的限制。Java Card 不支持序列化和 JCRMI 參數,并且返回值也有限制:

  每個到遠程方法的參數必須是 Java Card 支持的類型之一,不包括 char, double, float, long 或者多維數組。對 int 的支持為可選的。

  任何遠程方法的返回值必須是受支持的類型之一,或者 void,或者一個遠程接口類型。

  JCRMI 客戶機應用程序

  因為 JCRMI Client API 依靠 OCF 用于卡片管理和通信,所以 JCRMI 客戶機應用程序類似您前面看到的 OCF 主機應用程序。

  下面的代碼片斷首先初始化 OCF,并且等待智能卡被插入。然后它創建一個 OCFCardAccessor 實現,用于把我們的 JCRMI 連接到卡片上,如有必要,客戶機樁模塊將動態生成,applet 被選中,我們取得了遠程引用,最后我們實現到 getBalance() 的遠程調用:

...
try {
// Initialize OCF
SmartCard.start();
// Wait for a smart card
CardRequest cr = new CardRequest(CardRequest.NEWCARD, null,
OCFCardAccessor.class);
SmartCard myCard = SmartCard.waitForCard(cr);
// Get an OCFCardAccessor for Java Card RMI
CardAccessor ca = (CardAccessor)
myCard.getCardService(OCFCardAccessor.class, true);
// Create a Java Card RMI instance
JavaCardRMIConnect jcRMI = new JavaCardRMIConnect(ca);
// Create a Java Card Proxy Factory that is used for dynamic
// proxy generation.
CardObjectFactory factory = new JCCardProxyFactory(ca);
// select the Java Card applet
jcRMI.selectApplet(MY_APPLET_AID, factory);
// Get the initial reference
MyRemoteInterface myRemoteInterface =
(MyRemoteInterface) jcRMI.getInitialReference();
if(myRemoteInterface == null) {
throw new
Exception("Received null instead of the initial ref");
}
// Invoke the remote getBalance() method
short balance = myRemoteInterface.getBalance();
}
catch(UserException e) {
// Handle exception
...
}
catch (Exception e){
// Handle exception
...
} finally {
// Clean up
try{
SmartCard.shutdown();
}catch (Exception e){
System.out.println(e);
}
}




  清單 5. 示例 JCRMI 客戶機

  如您所見,您必須要做的是減少代碼并大幅度簡化代碼。

  用于 J2ME 的安全性和信任服務應用編程接口

  SATSA 是一套用于 J2ME 的新的可選軟件包,定義一個客戶端 API 來訪問 安全元素:例如智能卡這樣的設備。在本節中,我將僅僅介紹 SATSA 的通信部分;本文中將不介紹 SATSA PKI 和加密 API。

  SATSA 通信 API 被分解成下面幾部分:

  SATSA-APDU 定義一個 API,用于和遵循 ISO-7816-4 的智能卡進行通信。這個可選軟件包由單獨的 javax.microedition.io.APDUConnection 軟件包組成。

  SATSA-JCRMI 定義了 Java Card RMI 客戶機 API。這個可選軟件包由下面的 Java 軟件包組成:

  javax.microedition.io.JavaCardRMIConnection

  javax.microedition.jcrmi.RemoteRef

  javax.microedition.jcrmi.RemoteStub

  java.rmi.Remote

  java.rmi.RemoteException

  javacard.framework.service.ServiceException

  javacard.framework.CardRuntimeException

  javacard.framework.ISOException

  javacard.framework.APDUException

  javacard.framework.CardException

  javacard.framework.PINException

  javacard.framework.SystemException

  javacard.framework.TransactionException

  javacard.framework.UserException

  javacard.security.CryptoException

  SATSA 將 J2ME 和 Java Card 平臺緊密地結合在一起。SATSA 使用 CLDC 1.0 Generic Connection Framework(GCF)用于基于 J2ME 的設備和智能卡之間的通信,如下所示:



圖 3. 通用連接框架和 SATSA 連接

  因為 SATSA 基于 GCF,開發使用手機上的智能卡的 MIDlet 相對不容易,但是對于 J2ME 開發人員來說很熟悉。

  SATSA 考慮到用于 Java Card 應用程序的兩個總體編程模型:APDU-消息傳遞模型和 Java Card RMI 面向對象分布式模型。SATSA 為了每一個模型定義了一個新的 GCF 連接類型:

  APDUConnection 允許一個 J2ME 應用程序使用 ISO-7816 APDU 協議以便與智能卡應用程序交換 APDU。

  JavaCardRMIConnection 允許一個 J2ME 應用程序使用 Java Card RMI 來調用智能卡上的遠程方法。

  指定 SATSA 的連接類型

  所有的 GCF 連接都使用 Connector.open() 方法創建。Connector.open() 的一個參數是指示要創建的連接類型的 URL。CLDC GCF 使用下面的格式定義這個 URL 為一個字符串:

scheme:[target][params]  


  ......其中:

  scheme 是要創建的連接類型(和要使用的協議)。

  target 一般是某種網絡地址。

  params 是可選參數,表達形式是名稱=值,通過分號隔開。

  對于 SATSA,URL 的格式是:

protocol:[slotID]; AID  


  ......其中:

  protocol 要么是 apdu,用于基于 APDU 的連接,要么是 jcrmi,用于基于 JCRMI 的連接。

  slotID 是指示卡片插入的插槽。slotID 字段是可選的;默認值為 0。

  AID 是用于智能卡應用程序的應用程序標識符。AID 是一個由句號分隔開的 5 到 16 個十六進制字節值的字符串;例如,“ A0.0.0.67.4.7.1F.3.2C.3”。

  使用 APDUConnection

  APDUConnection 定義允許我們使用 GCF 與遵循 ISO-7816 的卡片進行通信的各種方法。它定義了三個方法是:

  enterPIN() 提示用戶輸入一個個人識別號碼。

  exchangeAPDU() 與智能卡應用程序交換 APDU。這個調用直到一個響應從智能卡返回的時候(或者處理被中斷)才會阻斷。



  getATR() 返回智能卡發送的 Answer To Reset(ATR) 消息,作為重置操作的響應。

  下面的代碼片斷顯示如何打開一個 APDUConnection,如何關閉它,以及如何交換一個命令 APDU 并且接收一個 APDU 響應:

...
try {
// Create an APDUConnection
String url = "apdu:0;AID=A1.0.0.67.4.7.1F.3.2C.5";
APDUConnection ac = (APDUConnection) Connector.open(url);
// Send a command APDU and receive a response APDU
byte[] responseAPDU = ac.exchangeAPDU(commandAPDU);
...
// Close connection.
ac.close();
} catch(IOException e){
...
}
...


  清單6. 使用 SATSA-APDU

  SATSA 使 APDU 通信簡單化。請注意,這個 APDU 命令和響應的格式和您在本系列文章的第 2 部分的“編寫客戶端 JavaCard Applet”一節中看到的相同,告訴您如何編寫一個基于 APDU 消息傳遞的 Java Card Applet。

  使用 JavaCardRMIConnection

  JavaCardRMIConnection 定義允許我們使用 Java Card RMI 程序設計模型的方法。JavaCardRMIConnection 定義了方法 getInitialReference(),為初始遠程引用返回樁模塊對象。

...
try {
// Create a JavaCardRMIConnection
String url = "jcrmi:0;AID=A0.0.0.67.4.7.1F.3.2C.3";
JavaCardRMIConnection jc = (JavaCardRMIConnection)
Connector.open(url);
MyRemoteObject robj = (MyRemoteObject)
jc.getInitialReference();
...
short balance = robj.getBalance();
...
// Close connection
jc.close();
} catch (Exception e) {
...
}
...


  清單7. 使用 SATSA-JCRMI

  采用上面所說的 SATSA-JCRMI 應用編程接口,允許我們調用本系列文章的第 2 部分中所定義的 getBalance() 方法,向你說明如何編寫一個基于 RMI 的 JavaCard applet。


  清單 2. 異步 OCF 應用程序的典型結構

  當卡片被插入時,運行時調用 cardInserted() 方法,當卡片被拔出時,運行時調用 cardRemoved() 方法。在更為充實的下列清單中,插入卡片將初始化 applet 代理的創建,拔出卡片將觸發 applet 代理的清除。清單還顯示了用于信用卡余額的請求被委托給代理。

import opencard.core.event.CTListener;
import opencard.core.event.CardTerminalEvent;
import opencard.core.service.SmartCard;
import opencard.core.service.CardService;
...
public class MyHostSideApp implements CTListener
{
public void MyHostSideApp() {
try {
// Initialize the framework
SmartCard.start ();
// Register this as a Card Terminal Event Listener
CardTerminalRegistry.getRegistry().addCTListener(this);
} catch (Exception e) {
// Handle error.
...
}
}
/**
* Card insertion event. Get new card and card service
* @param ctEvent The card insertion event.
*/
public void cardInserted(CardTerminalEvent ctEvent) {
try {
// Get a SmartCard object
card = SmartCard.getSmartCard(ctEvent);
// Get the card proxy instance.
myCardProxy = (MyCardProxy)
card.getCardService(MyCardProxy.class, true);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Card removal event. Invalidate card and card service.
* @param ctEvent The card removal event.
*/
public synchronized void cardRemoved(CardTerminalEvent ctEvent) {
card = null;
myCardProxy = null;
// Initialize the framework
SmartCard.shutdown();
}
/**
* Get balance from the smart card.
*/
public int getBalance() {
try {
// Get mutex to prevent other Card Services from modifying
// data. Delegate the call to the applet proxy.
card.beginMutex();
return Integer.parseInt(myCardProxy.getBalance());
} catch (Throwable e) {
return 0;
} finally {
// End mutual exclusion
card.endMutex();
}
}
...

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 祁阳县| 抚州市| 南康市| 如东县| 鹤山市| 金门县| 兴安盟| 若尔盖县| 吉林省| 玉溪市| 辽阳县| 洛阳市| 醴陵市| 麦盖提县| 开化县| 绍兴市| 平谷区| 新宾| 夹江县| 东平县| 科尔| 洮南市| 华坪县| 桦甸市| 内乡县| 新竹市| 大安市| 兴和县| 汤阴县| 临夏市| 绥滨县| 灵台县| 曲松县| 密山市| 日土县| 浠水县| 全南县| 炉霍县| 桓仁| 双柏县| 黄龙县|