-
Notifications
You must be signed in to change notification settings - Fork 11
/
NdefHostApduService.java
148 lines (124 loc) · 5.63 KB
/
NdefHostApduService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package com.example.ndefcard;
import java.util.Arrays;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
public class NdefHostApduService extends HostApduService {
// アプリケーション選択のC-APDU
private final static byte[] SELECT_APP = new byte[] {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00,
(byte)0x07, (byte)0xd2, (byte)0x76, (byte)0x00, (byte)0x00, (byte)0x85, (byte)0x01, (byte)0x01,
(byte)0x00,
};
// CCファイル選択のC-APDU)
private final static byte[] SELECT_CC_FILE = new byte[] {(byte)0x00, (byte)0xa4, (byte)0x00, (byte)0x0c,
(byte)0x02, (byte)0xe1, (byte)0x03,
};
// NDEFレコードファイル選択のC-APDU
private final static byte[] SELECT_NDEF_FILE = new byte[] {(byte)0x00, (byte)0xa4, (byte)0x00, (byte)0x0c,
(byte)0x02, (byte)0xe1, (byte)0x04,
};
// 成功時の Status Word (レスポンスで使用する)
private final static byte[] SUCCESS_SW = new byte[] {
(byte)0x90, (byte)0x00,
};
// 失敗時の Status Word (レスポンスで使用する)
private final static byte[] FAILURE_SW = new byte[] {
(byte)0x6a, (byte)0x82,
};
// CCファイルのデータ
private final static byte[] CC_FILE = new byte[] {
0x00, 0x0f, // CCLEN
0x20, // Mapping Version
0x00, 0x3b, // Maximum R-APDU data size
0x00, 0x34, // Maximum C-APDU data size
0x04, 0x06, // Tag & Length
(byte)0xe1, 0x04, // NDEF File Identifier
0x00, 0x32, // Maximum NDEF size
0x00, // NDEF file read access granted
(byte)0xff, // NDEF File write access denied
};
// NDEFレコードファイルに格納するURL
private static final String URL = "http://brightechno.com/blog/";
// NDEFレコードファイル用変数
private byte[] mNdefRecordFile;
// アプリが選択されているかどうかのフラグ
private boolean mAppSelected;
// CCファイルが選択されているかどうかのフラグ
private boolean mCcSelected;
// NDEFレコードファイルが選択されているかどうかのフラグ
private boolean mNdefSelected;
@Override
public void onCreate() {
super.onCreate();
// 状態のクリア
mAppSelected = false;
mCcSelected = false;
mNdefSelected = false;
// NDEFレコードファイルの生成
NdefRecord record = NdefRecord.createUri(URL);
NdefMessage ndefMessage = new NdefMessage(record);
int nlen = ndefMessage.getByteArrayLength();
mNdefRecordFile = new byte[nlen + 2];
mNdefRecordFile[0] = (byte)((nlen & 0xff00) / 256);
mNdefRecordFile[1] = (byte)(nlen & 0xff);
System.arraycopy(ndefMessage.toByteArray(), 0, mNdefRecordFile, 2, ndefMessage.getByteArrayLength());
}
/**
* NFC Forum Tag Type 4として振る舞う処理を行う。
* C-APDUを受け取り、対応するR-APDUを返す。
*/
@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
if (Arrays.equals(SELECT_APP, commandApdu)) {
// アプリ選択
mAppSelected = true;
mCcSelected = false;
mNdefSelected = false;
return SUCCESS_SW; // 成功
} else if (mAppSelected && Arrays.equals(SELECT_CC_FILE, commandApdu)) {
// CCファイル選択
mCcSelected = true;
mNdefSelected = false;
return SUCCESS_SW; // 成功
} else if (mAppSelected && Arrays.equals(SELECT_NDEF_FILE, commandApdu)) {
// NDEFファイル選択
mCcSelected = false;
mNdefSelected = true;
return SUCCESS_SW; // 成功
} else if (commandApdu[0] == (byte)0x00 && commandApdu[1] == (byte)0xb0) {
// READ_BINARY (ファイル読み出し)
// オフセットと長さを取り出す
int offset = (0x00ff & commandApdu[2]) * 256 + (0x00ff & commandApdu[3]);
int le = 0x00ff & commandApdu[4];
// R-APDU用のバッファを生成する
byte[] responseApdu = new byte[le + SUCCESS_SW.length];
if (mCcSelected && offset == 0 && le == CC_FILE.length) {
// CC選択時はオフセットが0、長さがファイル長(15)と一致していなければならない
System.arraycopy(CC_FILE, offset, responseApdu, 0, le);
System.arraycopy(SUCCESS_SW, 0, responseApdu, le, SUCCESS_SW.length);
return responseApdu;
} else if (mNdefSelected) {
if (offset + le <= mNdefRecordFile.length) {
System.arraycopy(mNdefRecordFile, offset, responseApdu, 0, le);
System.arraycopy(SUCCESS_SW, 0, responseApdu, le, SUCCESS_SW.length);
return responseApdu;
}
}
}
// エラーを返す
// 本来、ICカードアプリではエラー種別にあわせてエラーの値を変えなければ
// ならないが、ここでは省略して一種類のみを返している。
return FAILURE_SW;
}
/**
* カードアプリが非選択状態になった時に呼ばれる。
* 本アプリでは状態をリセットして初期状態に戻します。
*/
@Override
public void onDeactivated(int reason) {
mAppSelected = false;
mCcSelected = false;
mNdefSelected = false;
}
}