敬业的IT人 >> 编程开发 >> 其他语言 >> JavaCard小应用程序结构

JavaCard小应用程序结构

敬业的IT人 互联网 佚名 2008-1-4 14:14:54
    ·应用MFC开发高级应用程序
    ·在VC++应用程序中读取文本数据
    ·使用GWT开发AJAX应用程序
    ·在Ajax应用程序中实现数据交换
    ·DirectSound应用程序开发快速入门
    ·用Indy组件开发Socket应用程序
    ·MFC应用程序框架入门
    ·VFP基础教程 第十一章 应用
    ·用VC++建立Service服务应用程序
    ·用VC++编制FTP客户端应用程序

  Sun提供了两个模型用来设计JavaCard应用程序(javacard.framework.Applet):传统的JavaCard API和JavaCard Remote Method Invocatiborder="0" align="center" alt="JavaCard小应用程序结构" width="425" height="104" />
Figure 3. APDU 指令和响应流程

  每次JCRE接收一个APDU命令(通过卡片读取器从主应用程序,或者如果使用SunJava Card Development工具箱就通过apdutool),它调用小应用程序的process()方法,把输入命令当作一个参数传送给它(APDU命令输入缓冲中的参数)。process()方法然后:

  1.摘录APDU CLA和INS字段

  2.检索应用程序特定的P1、P2和数据字段

  3.处理APDU数据

  4.生成并发送一个响应

  5.优雅地返回,或者抛出相应的ISO异常

  在此时,JCRE发送合适的状态字回到主应用程序,通过读卡器。

  列表8显示一个样本process()方法。

/**
* Called by the JCRE to process an incoming APDU command. An
* applet is expected to perform the action requested and return
* response data if any to the terminal.
*
* Upon normal return from this method the JCRE sends the ISO-
* 7816-4-defined success status (90 00) in the APDU response. If
* this method throws an ISOException the JCRE sends the
* associated reason code as the response status instead.
* @param apdu is the incoming APDU.
* @throw ISOException if the process method fails.
*/
public void process(APDU apdu) throws ISOException {

// Get the incoming APDU buffer.
byte[] buffer = apdu.getBuffer();

// Get the CLA; mask out the logical-channel info.
buffer[ISO7816.OFFSET_CLA] =
(byte)(buffer[ISO7816.OFFSET_CLA] & (byte)0xFC);

// If INS is Select, return - no need to process select
// here.
if ((buffer[ISO7816.OFFSET_CLA] == 0) &&
(buffer[ISO7816.OFFSET_INS] == (byte)(0xA4)) )
return;

// If unrecognized class, return "unsupported class."
if (buffer[ISO7816.OFFSET_CLA] != MyAPPLET_CLA)
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

// Process (application-specific) APDU commands aimed at
// MyApplet.
switch (buffer[ISO7816.OFFSET_INS]) {

case VERIFY_INS:
verify(apdu);
break;

case GET_BALANCE_INS:
getBalance(apdu);
break;

default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break;
}
}
列表8、process()小应用程序生命周期方法进入讨论组讨论。
    ·应用MFC开发高级应用程序
    ·在VC++应用程序中读取文本数据
    ·使用GWT开发AJAX应用程序
    ·在Ajax应用程序中实现数据交换
    ·DirectSound应用程序开发快速入门
    ·用Indy组件开发Socket应用程序
    ·MFC应用程序框架入门
    ·VFP基础教程 第十一章 应用
    ·用VC++建立Service服务应用程序
    ·用VC++编制FTP客户端应用程序

  我们的process()方法调用getBalance()和verify()方法。列表9显示getBalance ()方法,处理get balance APDU并且返回保存在卡片中的余额。

/**
* Retrieves and returns the balance stored in this card.
* @param apdu is the incoming APDU.
*/
private void getBalance(APDU apdu) {

// Get the incoming APDU buffer.
byte[] buffer = apdu.getBuffer();

// Set the data transfer direction to outbound and obtain
// the expected length of response (Le).
short le = apdu.setOutgoing();

// If the expected size is incorrect, send a wrong-length
// status word.
if (le != GET_BALANCE_RESPONSE_SZ)
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

// Set the actual number of bytes in the response data field.
apdu.setOutgoingLength((byte)GET_BALANCE_RESPONSE_SZ);

// Set the response data field; split the balance into 2
// separate bytes.
buffer[0] = (byte)(balance >> 8);
buffer[1] = (byte)(balance & 0xFF);

// Send the 2-byte balance starting at the offset in the APDU
// buffer.
apdu.sendBytes((short)0, (short)GET_BALANCE_RESPONSE_SZ);
}
列表9、处理Get Balance APDU

  getBalance ()方法通过调用APDU.getBuffer ()方法取得一个引用到APDU缓冲。在返回响应(当前余额)之前,小应用程序必须设置JCRE模式通过调用APDU.setOutgoing()方法来发送,方便地返回期望的响应大小。我们还必须设置响应数据字段中的字节的实际数字,通过调用APDU.setOutgoingLenth()。APDU缓冲中的响应事实上通过调用APDU.sendBytes ()发送。

  小应用程序不直接发送返回码(状态字);一旦小应用程序调用APDU.setOutgoing ()并且提供任何请求的信息,JCRE注意这个状态字。状态字的值依靠process()方法如何使返回到JCRE来变化。如果所有的已经正常运行,JCRE将返回9000,指明无错。你的小应用程序可以通过抛出一个定义在ISO7816接口中的异常返回一个错误代码。 在列表9中,如果期望响应的大小不正确,方法getBalance()抛出一个ISO7816.SW_WRONG_LENGTH代码。对于有效的状态码值,请参阅ISO7816接口的定义,或者回到本文第一部分的"响应APDU"。

  现在让我们看看在列表10中的verify()方法。因为我们定义的验证PIN APDU命令包含数据,verify()方法必须调用APDU.setIncomingAndReceive ()方法,设置JCRE为接收模式,然后接收输入数据。

/**
* Validates (verifies) the Owner's PIN number.
* @param apdu is the incoming APDU.
*/
private void verify(APDU apdu) {

// Get the incoming APDU buffer.
byte[] buffer = apdu.getBuffer();

// Get the PIN data.
byte bytesRead = (byte)apdu.setIncomingAndReceive();

// Check/verify the PIN number. Read bytesRead number of PIN
// bytes into the APDU buffer at the offset
// ISO7816.OFFSET_CDATA.
if (ownerPin.check(buffer, ISO7816.OFFSET_CDATA, byteRead)
== false )
ISOException.throwIt(SW_PINVERIFY_FAILED);
}
列表10、处理验证APDU

  这个方法通过调用APDU.getBuffer()取得一个到APDU缓冲的引用,调用APDU.setIncomingAndReceive()来接收命令数据,从输入的APDU缓冲中取得PIN数据,并且验证PIN。一个验证失败导致状态码6900被发送回主应用程序。

  有时输入的数据比填充到APDU缓冲中的数据要多,并且小应用程序必须大块的读取数据知道没有数据可以读取。在此情况下,我们必须首先调用APDU.setIncomingAndReceive(),然后重复地调用APDU.receiveBytes(),直到不再有数据可用。列表11显示如何读取大量输入数据。

...
byte[] buffer = apdu.getBuffer();
short bytes_left = (short) buffer[ISO.OFFSET_LC];
short readCount = apdu.setIncomingAndReceive();
while (bytes_left > 0) {

// Process received data in buffer; copy chunk to temp buf.
Util.arrayCopy(buffer, ISO.OFFSET_CDATA, tbuf, 0, readCount);
bytes_left -= readCount;
// Get more data
readCount = apdu.receiveBytes(ISO.OFFSET_CDDATA);
}
...
列表11、读取大量输入数据

  由于每个大块被读取,小应用程序可以把它添加到另一个缓冲中,否则仅仅处理它。进入讨论组讨论。
粤ICP备06119539号
Copyright CiscoSky.Org,Some Rights Reserved.
Email:me1228#tom.com