Smart Card Guy

Smart Card, Java Card, PCI DSS, IoT Device Security

Java Card サンプルアプリ - Hello World

開発環境構築

開発環境の構築はこちらを参照。

smartcardguy.hatenablog.jp

Java Card Hello World

このプログラムはHello Worldというよりは、Echoプログラム。

Source Code

/**
 * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
 * 
 */

/*
 */

// /*
// Workfile:@(#)HelloWorld.java    1.7
// Version:1.7
// Date:01/03/06
//
// Archive:  /Products/Europa/samples/com/sun/javacard/samples/HelloWorld/HelloWorld.java
// Modified:01/03/06 12:13:08
// Original author:  Mitch Butler
// */
package com.sun.jcclassic.samples.helloworld;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;

/**
 */

public class HelloWorld extends Applet {
    private byte[] echoBytes;
    private static final short LENGTH_ECHO_BYTES = 256;

    /**
     * Only this class's install method should create the applet object.
     */
    protected HelloWorld() {
        echoBytes = new byte[LENGTH_ECHO_BYTES];
        register();
    }

    /**
     * Installs this applet.
     *
     * @param bArray
     *            the array containing installation parameters
     * @param bOffset
     *            the starting offset in bArray
     * @param bLength
     *            the length in bytes of the parameter data in bArray
     */
    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new HelloWorld();
    }

    /**
     * Processes an incoming APDU.
     *
     * @see APDU
     * @param apdu
     *            the incoming APDU
     * @exception ISOException
     *                with the response bytes per ISO 7816-4
     */
   @Override 
   public void process(APDU apdu) {
        byte buffer[] = apdu.getBuffer();

        // check SELECT APDU command
        if ((buffer[ISO7816.OFFSET_CLA] == 0) &&
                (buffer[ISO7816.OFFSET_INS] == (byte) (0xA4))) {
            return;
        }
       // Comments by ASJ 
       // ISO7816.OFFSET_CLA = 0, ISO7816.OFFSET_INS = 1

        short bytesRead = apdu.setIncomingAndReceive();
        short echoOffset = (short) 0;

        while (bytesRead > 0) {
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, echoBytes, echoOffset, bytesRead);
            echoOffset += bytesRead;
            bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
        }
       // Comments by ASJ 
       // ISO7816.OFFSET_CDATA (APDU command data offset) = 5


        apdu.setOutgoing();
        apdu.setOutgoingLength((short) (echoOffset + 5));

        // echo header
        apdu.sendBytes((short) 0, (short) 5);
        // echo data
        apdu.sendBytesLong(echoBytes, (short) 0, echoOffset);
    }

}

実行手順

Sample Deviceをスタート

f:id:blog-guy:20180630142313p:plain

スタートするとEclipseのConsoleに以下のように表示される。 f:id:blog-guy:20180630142549p:plain

1. cap-com.sun.jcclassic.samples.helloworld
  • Cap File Installation APDU Script
  • helloworld.capファイルにある下記のcapファイルをインストール
    • Header.cap
    • Directory.cap
    • Import.cap
    • Applet.cap
    • Class.cap
    • Method.cap
    • StaticField.cap
    • ConstantPool.cap
    • RefLocation.cap
  • 実行すると以下のようになる

f:id:blog-guy:20180630143139p:plain

f:id:blog-guy:20180630143222p:plain

2. create-com.sun.jcclassic.samples.helloworld.HelloWorld
  • Applet Instantiation APDU Script (Select Installer Applet - Create Applet)
  • 実行すると以下のようになる

f:id:blog-guy:20180630143328p:plain

解析
CMD>// Applet Instantiation APDU Script
//
// Package:     com.sun.jcclassic.samples.helloworld
// Package AID: //aid/A000000062/03010C01
// Applet:      HelloWorld
// Applet AID:  //aid/A000000062/03010C0101
//
// Select the installer applet
0x00 0xA4 0x04 0x00 0x09 0xA0 0x00 0x00 0x00 0x62 0x03 0x01 0x08 0x01 0x7F;
// RID : 0xA0 0x00 0x00 0x00 0x62
// Installer AppletのPackage ID : 0x03 0x01 0x08 0x01 
// (注意 : ここはHelloWorld Appletではなく、Installer Applet!)
// Applet SELECT command
// CLA : 00, INS : a4, P1 : 04 : P2 : 00, Lc : AID長さ, Data : AID 

APDU|CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 09, a0, 00, 00, 00, 62, 03, 01, 08, 01, Le: 00, SW1: 90, SW2: 00
// SW1: 90, SW2: 00 <= Success


// Create HelloWorld applet
0x80 0xB8 0x00 0x00 0x0C 0x0A 0xA0 0x00 0x00 0x00 0x62 0x03 0x01 0x0C 0x01 0x01 0x00 0x7F;
// Data field : 0x0A 0xA0 0x00 0x00 0x00 0x62 0x03 0x01 0x0C 0x01 0x01 0x00
// RID : 0xA0 0x00 0x00 0x00 0x62
// Installer AppletのPackage ID : 0c, 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 01, 01

APDU|CLA: 80, INS: b8, P1: 00, P2: 00, Lc: 0c, 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 01, 01, 00, Le: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 01, 01, SW1: 90, SW2: 00
3. helloworld

f:id:blog-guy:20180630143445p:plain

// send any APDU. HelloWorld will echo
0x80 0x10 0x01 0x02 0x05 0x01 0x02 0x03 0x04 0x05 0x7F;
APDU|CLA: 80, INS: 10, P1: 01, P2: 02, Lc: 05, 01, 02, 03, 04, 05, Le: 0a, 80, 10, 01, 02, 05, 01, 02, 03, 04, 05, SW1: 90, SW2: 00

解析

C-APDU (Card Acceptance DeviceからCardへのAPDUコマンド発行)

CLA: 80, INS: 10, P1: 01, P2: 02, Lc: 05, 01, 02, 03, 04, 05, Le: 0a

  • CLA : 80
  • INS : 10
  • P1 : 01, P2 : 02
  • Lc : 05 <= データのバイト数。5バイト
  • 01, 02, 03, 04, 05 <= データ
  • Le : 0a <= カードから0x0a(10)バイトが来る
R-APDU (CardからCard Acceptance DeviceへのAPDUコマンドResponse)

80, 10, 01, 02, 05, 01, 02, 03, 04, 05, SW1: 90, SW2: 00

  • 80
  • 10
  • 01, 02
  • 05
  • 01, 02, 03, 04, 05 <= Echoされたデータ
  • SW1: 90, SW2: 00 <= Status : Successful
AIDの定義

appletフォルダのapplet.optファイルに以下のように定義されている

-out EXP JCA CAP
-exportpath ../../../../../../api_export_files
-applet  0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0xc:0x1:0x1 com.sun.jcclassic.samples.helloworld.HelloWorld
com.sun.jcclassic.samples.helloworld
0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0xc:0x1 1.0
APDUコマンド詳細はこちら

smartcardguy.hatenablog.jp