3 | // Package: CardEdgeApplet
4 | // Description: CardEdge implementation with JavaCard
5 | //
6 | // BEGIN LICENSE BLOCK
7 | // Copyright (C) 2006 Red Hat, Inc.
8 | // All rights reserved.
9 | //
10 | // Redistribution and use in source and binary forms, with or without
11 | // modification, are permitted provided that the following conditions
12 | // are met:
13 | //
14 | // 1. Redistributions of source code must retain the above copyright
15 | // notice, this list of conditions and the following disclaimer.
16 | // 2. Redistributions in binary form must reproduce the above copyright
17 | // notice, this list of conditions and the following disclaimer in the
18 | // documentation and/or other materials provided with the distribution.
19 | // 3. The name of the author may not be used to endorse or promote products
20 | // derived from this software without specific prior written permission.
21 | //
22 | // Changes to this license can be made only by the copyright author with
23 | // explicit written consent.
24 | //
25 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 | // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 | // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 | // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 |
36 | // Alternatively, the contents of this file may be used under the terms of
37 | // the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
38 | // case the provisions of the LGPL are applicable instead of those above. If
39 | // you wish to allow use of your version of this file only under the terms
40 | // of the LGPL, and not to allow others to use your version of this file
41 | // under the terms of the BSD license, indicate your decision by deleting
42 | // the provisions above and replace them with the notice and other
43 | // provisions required by the LGPL. If you do not delete the provisions
44 | // above, a recipient may use your version of this file under the terms of
45 | // either the BSD license or the LGPL.
46 | //
47 | // You should have received a copy of the GNU Lesser General Public
48 | // License along with this library; if not, write to the Free Software
49 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
50 | // END LICENSE_BLOCK
51 |
52 | package com.redhat.ckey.applet;
53 |
54 | import javacard.framework.ISOException;
55 | import javacard.framework.JCSystem;
56 | import javacard.framework.Util;
57 |
58 | /**
59 | * ASN1 parser Class
60 | *
61 | * This Simplistic ASN.1 parser does not interpret tags, it simply finds
62 | * elements based on where their fields are supposed to wind up at.
63 | *
64 | *
65 | * Object fields:
66 | *
67 | * short[] newSize; // way to get around java's restrictions on pass by ref.
68 | * byte[] data
69 | *
70 | *
71 | * @author Robert Relyea
72 | * @version 0.0.1
73 | *
74 | */
75 | public class ASN1
76 | {
77 | public static final short SW_BAD_DER_DATA = (short)0x9cd0;
78 | private final short NEXT = 0;
79 | private final short SIZE = 1;
80 | private final short END = 2;
81 | private short[] params;
82 |
83 | public ASN1()
84 | {
85 | params=JCSystem.makeTransientShortArray((short)3,
86 | JCSystem.CLEAR_ON_DESELECT);
87 | }
88 |
89 | public short GetEnd()
90 | {
91 | return params[END];
92 | }
93 |
94 | public short GetSize()
95 | {
96 | return params[SIZE];
97 | }
98 |
99 | public short GetNext()
100 | {
101 | return params[NEXT];
102 | }
103 |
104 | public byte GetTag(byte buf[], short offset, short end)
105 | {
106 | if (end <= offset) {
107 | ISOException.throwIt(SW_BAD_DER_DATA);
108 | }
109 | return buf[offset];
110 | }
111 |
112 | public short Unwrap(byte buf[], short offset, short end, short dbg)
113 | {
114 | byte tag;
115 | byte len;
116 | short length = 0;
117 |
118 | if (end < (short)(offset+2)) {
119 | ISOException.throwIt(SW_BAD_DER_DATA);
120 | }
121 | tag = buf[offset++];
122 | if (tag == 0) {
123 | ISOException.throwIt(SW_BAD_DER_DATA);
124 | }
125 | len = buf[offset++];
126 | length = Util.makeShort((byte)0,len);
127 |
128 | if ((len & 0x80) != 0) {
129 | short count = Util.makeShort((byte)0,(byte)(len & 0x7f));
130 | if (end < (short)(offset+count)) {
131 | ISOException.throwIt(SW_BAD_DER_DATA);
132 | }
133 | if (count > 2) {
134 | ISOException.throwIt(SW_BAD_DER_DATA);
135 | }
136 | length = 0;
137 | while (count-- > 0) {
138 | length = (short)((length << 8)
139 | | Util.makeShort((byte)0,buf[offset++]));
140 | }
141 | }
142 | params[SIZE] = length;
143 | params[NEXT] = ((short)(offset+length));
144 | params[END] = ((short)(offset+length));
145 | return offset;
146 | }
147 |
148 | public short Skip(byte buf[], short offset, short end, short dbg)
149 | {
150 | Unwrap(buf,offset,end,dbg);
151 | return params[NEXT];
152 | }
153 |
154 | public short UnwrapBitString(byte buf[], short offset, short end, short dbg)
155 | {
156 | if (buf[offset] != 0) {
157 | ISOException.throwIt(SW_BAD_DER_DATA);
158 | }
159 | if (end < (short)(offset+1)) {
160 | ISOException.throwIt(SW_BAD_DER_DATA);
161 | }
162 | params[SIZE]--;
163 | return (short)(offset+1);
164 | }
165 |
166 | public short Signed2Unsigned(byte buf[], short offset, short end, short dbg)
167 | {
168 | short startOffset = offset;
169 | short startSize=params[SIZE];
170 | for (; offset < end && buf[offset] == 0 ; offset++){
171 | params[SIZE]--;
172 | }
173 | if (offset >= end) {
174 | ISOException.throwIt(SW_BAD_DER_DATA);
175 | }
176 | return offset;
177 | }
178 | }
179 |
180 |
181 |
--------------------------------------------------------------------------------
/src/org/aispring/javacard/ndef/UtilTLV.java:
--------------------------------------------------------------------------------
1 | /*
2 | * IsoApplet: A Java Card PKI applet aimiing for ISO 7816 compliance.
3 | * Copyright (C) 2014 Philip Wendland (wendlandphilip@gmail.com)
4 | *
5 | * This program is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program; if not, write to the Free Software Foundation,
17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.aispring.javacard.ndef;
21 |
22 | import javacard.framework.Util;
23 |
24 | /**
25 | * \brief Utility class for TLV-related operations.
26 | *
27 | * This code originally comes from IsoApplet by Philip Wendland.
28 | *
29 | * It has been modified to eliminate the use of exceptions.
30 | */
31 | public final class UtilTLV {
32 |
33 | /** \brief Find the position of the tag at level 1.
34 | *
35 | * \attention This method only searches level 1 of TLV encoded arrays (i.e. no nested TLVs are searched).
36 | *
37 | * \param tlv The array containing the TLV-encoded object to search.
38 | *
39 | * \param tlvOffset The position at which the TLV structure begins.
40 | *
41 | * \param tlvLength The length of the TLV structure.
42 | *
43 | * \param tag The tag to search for.
44 | *
45 | * \return The position of the tag.
46 | *
47 | * \throw NotFoundException If the tag could not be found.
48 | *
49 | * \throw InvalidArgumentsException Malformatted TLV data.
50 | */
51 | public static short findTag(byte[] tlv, short tlvOffset, short tlvLength, byte tag) {
52 | short tagPos = tlvOffset;
53 | short len;
54 |
55 | while(tagPos < (short)(tlvLength+tlvOffset-1)) {
56 | if(tlv[tagPos] == tag) {
57 | return tagPos;
58 | }
59 | len = decodeLengthField(tlv, (short)(tagPos+1));
60 | // Increase the position by: T length (1), L length, V length.
61 | // I.e. look at the next Tag, jump over current L and V field.
62 | // This saves execution time and ensures that no byte from V is misinterpreted.
63 | tagPos += 1 + getLengthFieldLength(len) + len;
64 | }
65 | return -1;
66 | }
67 |
68 | /**
69 | * \brief Check the consistency of the TLV structure.
70 | *
71 | * Basically, we jump from one tag to the next. At the end, we must be at the position
72 | * where the next tag would be, if it was there. If the position is any other than that,
73 | * the TLV structure is not consistent.
74 | *
75 | * \param tlv The array containing the TLV-encoded object to search.
76 | *
77 | * \param offset The position at which the TLV structure begins.
78 | *
79 | * \param length The length of the TLV structure.
80 | *
81 | * \return True if the TLV structure is valid, else false.
82 | */
83 | public static boolean isTLVconsistent(byte[] tlv, short offset, short length) {
84 | short pos = offset;
85 | short len;
86 |
87 | while(pos < (short)(length+offset-1)) {
88 | len = decodeLengthField(tlv, (short)(pos+1));
89 | if(len < -1) {
90 | return false;
91 | }
92 | pos += 1 + getLengthFieldLength(len) + len;
93 | }
94 | return (pos == (short)(offset+length));
95 | }
96 |
97 | /**
98 | * \brief Decode the length field of a TLV-entry.
99 | *
100 | * The length field itself can be 1, 2 or 3 bytes long:
101 | * - If the length is between 0 and 127, it is 1 byte long.
102 | * - If the length is between 128 and 255, it is 2 bytes long.
103 | * The first byte is 0x81 to indicate this.
104 | * - If the length is between 256 and 65535, it is 3 bytes long.
105 | * The first byte is 0x82, the following 2 contain the actual length.
106 | * Note: Only lengths up to 0x7FFF (32767) are supported here, because a short in Java is signed.
107 | *
108 | * \param buf The buffer containing the length field.
109 | *
110 | * \param offset The offset at where the length field starts.
111 | *
112 | * \param length The length of the buffer (buf). This is to prevent that the index gets out of bounds.
113 | *
114 | * \return The (positive) length encoded by the length field, or in case of an error, -1.
115 | *
116 | * \throw InvalidArgumentsException If offset is too big for a signed Java short
117 | * If the first byte of the length field is invalid
118 | */
119 | public static short decodeLengthField(byte[] buf, short offset) {
120 | if(buf[offset] == (byte)0x82) { // 256..65535
121 | // Check for short overflow
122 | // (In Java, a short is signed: positive values are 0000..7FFF)
123 | if(buf[(short)(offset+1)] < 0) { // 80..FF
124 | return -1;
125 | }
126 | return Util.getShort(buf, (short)(offset+1));
127 | } else if(buf[offset] == (byte)0x81) {
128 | return (short) ( 0x00FF & buf[(short)(offset+1)]);
129 | } else if(buf[offset] > 0) { // 00..7F
130 | return (short) ( 0x007F & buf[offset]);
131 | } else {
132 | return -1;
133 | }
134 | }
135 |
136 | /**
137 | * \brief Get the length of the length field of a TLV-entry.
138 | *
139 | * \attention Not the length of the value-field is returned,
140 | * but the length of the length field itself.
141 | *
142 | * \see decodeLengthField()
143 | *
144 | * \param length The decoded length from the TLV-entry.
145 | *
146 | * \return The length of the length field.
147 | *
148 | * \throw InvalidArgumentsException If the length would overflow the signed
149 | * short of Java.
150 | */
151 | public static short getLengthFieldLength(short length) {
152 | if(length < 0) {
153 | return -1;
154 | } else if(length < 128) {
155 | return 1;
156 | } else if(length < 256) {
157 | return 2;
158 | } else {
159 | return 3;
160 | }
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/src/com/btchip/applet/poc/Base58.java:
--------------------------------------------------------------------------------
1 | /*
2 | *******************************************************************************
3 | * BTChip Bitcoin Hardware Wallet Java Card implementation
4 | * (c) 2013 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Affero General Public License as
8 | * published by the Free Software Foundation, either version 3 of the
9 | * License, or (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Affero General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Affero General Public License
17 | * along with this program. If not, see .
18 | *******************************************************************************
19 | */
20 |
21 | package com.btchip.applet.poc;
22 |
23 | import javacard.framework.Util;
24 |
25 | /**
26 | * Base 58 encoding and decoding
27 | * @author BTChip
28 | *
29 | */
30 | public class Base58 {
31 |
32 | public static short encode(byte[] in, short inOffset, short inLength, byte[] out, short outOffset, byte[] scratch, short scratchOffset) {
33 | short zeroCount = (short)0, j, startAt;
34 | while ((zeroCount < inLength) && (in[(short)(inOffset + zeroCount)] == 0)) {
35 | ++zeroCount;
36 | }
37 | Util.arrayCopyNonAtomic(in, inOffset, scratch, scratchOffset, inLength);
38 | j = (short)(2 * inLength);
39 | startAt = zeroCount;
40 | while(startAt < inLength) {
41 | short remainder = 0;
42 | short divLoop;
43 | for (divLoop = startAt ; divLoop < inLength; divLoop++) {
44 | short digit256 = (short)(scratch[(short)(scratchOffset + divLoop)] & 0xff);
45 | short tmpDiv = (short)(remainder * 256 + digit256);
46 | scratch[(short)(scratchOffset + divLoop)] = (byte)(tmpDiv / 58);
47 | remainder = (short)(tmpDiv % 58);
48 | }
49 | if (scratch[(short)(scratchOffset + startAt)] == 0) {
50 | ++startAt;
51 | }
52 | out[(short)(outOffset + --j)] = (byte)ALPHABET[remainder];
53 | }
54 | while ((j < ((short)(2 * inLength))) && (out[(short)(outOffset + j)] == ALPHABET[0])) {
55 | ++j;
56 | }
57 | while (--zeroCount >= 0) {
58 | out[(short)(outOffset + --j)] = (byte)ALPHABET[0];
59 | }
60 | short resultLength = (short)((2 * inLength) - j);
61 | Util.arrayCopyNonAtomic(out, (short)(outOffset + j), out, outOffset, resultLength);
62 | return (short)(outOffset + resultLength);
63 | }
64 |
65 | public static short decode(byte[] in, short inOffset, short inLength, byte[] out, short outOffset, byte[] scratch, short scratchOffset) {
66 | try {
67 | short zeroCount = (short)0, j, startAt;
68 | for (short i=0; i 128) {
71 | return (short)-1;
72 | }
73 | byte base58Value = BASE58TABLE[value];
74 | if (base58Value == (byte)0xff) {
75 | return (short)-1;
76 | }
77 | scratch[(short)(scratchOffset + i)] = base58Value;
78 | }
79 | while ((zeroCount < inLength) && (scratch[(short)(scratchOffset + zeroCount)] == 0)) {
80 | ++zeroCount;
81 | }
82 | j = inLength;
83 | startAt = zeroCount;
84 | while (startAt < inLength) {
85 | short remainder = 0;
86 | short divLoop;
87 | for (divLoop = startAt ; divLoop < inLength; divLoop++) {
88 | short digit256 = (short)(scratch[(short)(scratchOffset + divLoop)] & 0xff);
89 | short tmpDiv = (short)(remainder * 58 + digit256);
90 | scratch[(short)(scratchOffset + divLoop)] = (byte)(tmpDiv / 256);
91 | remainder = (short)(tmpDiv % 256);
92 | }
93 | if (scratch[(short)(scratchOffset + startAt)] == 0) {
94 | ++startAt;
95 | }
96 | out[(short)(outOffset + --j)] = (byte)remainder;
97 | }
98 | while ((j < inLength) && (out[(short)(outOffset + j)] == 0)) {
99 | j++;
100 | }
101 | short resultLength = (short)(inLength - (j - zeroCount));
102 | Util.arrayCopyNonAtomic(out, (short)(outOffset + j - zeroCount), out, outOffset, resultLength);
103 | return resultLength;
104 | }
105 | catch(Throwable t) {
106 | return (short)-1;
107 | }
108 | }
109 |
110 | private static final byte BASE58TABLE[] = {
111 | (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
112 | (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
113 | (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0x0,(byte)0x1,(byte)0x2,(byte)0x3,(byte)0x4,(byte)0x5,(byte)0x6,(byte)0x7,(byte)0x8,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
114 | (byte)0x9,(byte)0xa,(byte)0xb,(byte)0xc,(byte)0xd,(byte)0xe,(byte)0xf,(byte)0x10,(byte)0xff,(byte)0x11,(byte)0x12,(byte)0x13,(byte)0x14,(byte)0x15,(byte)0xff,(byte)0x16,(byte)0x17,(byte)0x18,(byte)0x19,(byte)0x1a,(byte)0x1b,(byte)0x1c,(byte)0x1d,
115 | (byte)0x1e,(byte)0x1f,(byte)0x20,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0x21,(byte)0x22,(byte)0x23,(byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,(byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,(byte)0xff,(byte)0x2c,
116 | (byte)0x2d,(byte)0x2e,(byte)0x2f,(byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,(byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,(byte)0x38,(byte)0x39,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff
117 | };
118 |
119 | private static final byte ALPHABET[] = {
120 | '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
121 | 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a',
122 | 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's',
123 | 't', 'u', 'v', 'w', 'x', 'y', 'z'
124 | };
125 | }
126 |
127 |
--------------------------------------------------------------------------------
/src/sos/passportapplet/KeyStore.java:
--------------------------------------------------------------------------------
1 | /*
2 | * passportapplet - A reference implementation of the MRTD standards.
3 | *
4 | * Copyright (C) 2006 SoS group, Radboud University
5 | *
6 | * This library is free software; you can redistribute it and/or
7 | * modify it under the terms of the GNU Lesser General Public
8 | * License as published by the Free Software Foundation; either
9 | * version 2.1 of the License, or (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | * Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public
17 | * License along with this library; if not, write to the Free Software
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 | *
20 | * $Id: FileSystem.java 143 2006-08-03 15:52:19Z ceesb $
21 | */
22 | package sos.passportapplet;
23 |
24 | import javacard.framework.JCSystem;
25 | import javacard.security.DESKey;
26 | import javacard.security.ECPrivateKey;
27 | import javacard.security.ECPublicKey;
28 | import javacard.security.KeyBuilder;
29 | import javacard.security.RSAPrivateKey;
30 | import javacard.security.RSAPublicKey;
31 |
32 | /**
33 | * Class that implements a Very Simple key store.
34 | *
35 | * @author ceesb
36 | *
37 | */
38 | public class KeyStore {
39 | public static final byte KEY_A = 0;
40 | public static final byte KEY_B = 1;
41 |
42 | private DESKey sm_kMac_a, sm_kMac_b, sm_kMac;
43 | private DESKey ma_kMac_a, ma_kMac_b, ma_kMac;
44 | private DESKey ma_kEnc, sm_kEnc;
45 | private byte mode;
46 | RSAPrivateKey rsaPrivateKey;
47 | RSAPublicKey rsaPublicKey;
48 |
49 | byte[] tmpKeys;
50 | ECPrivateKey ecPrivateKey;
51 | ECPublicKey ecPublicKey;
52 |
53 | KeyStore(byte mode) {
54 | this.mode = mode;
55 | sm_kEnc = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_RESET,
56 | KeyBuilder.LENGTH_DES3_2KEY,
57 | false);
58 | ma_kEnc = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
59 | KeyBuilder.LENGTH_DES3_2KEY,
60 | false);
61 |
62 | switch(mode) {
63 | case PassportCrypto.JCOP41_MODE:
64 | case PassportCrypto.PERFECTWORLD_MODE:
65 | rsaPrivateKey = (RSAPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_1024, false);
66 | rsaPublicKey = (RSAPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_1024, false);
67 | ecPrivateKey = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_F2M_PRIVATE, KeyBuilder.LENGTH_EC_F2M_163, false);
68 | ecPublicKey = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_F2M_PUBLIC, KeyBuilder.LENGTH_EC_F2M_163, false);
69 | break;
70 | }
71 |
72 | switch(mode) {
73 | case PassportCrypto.PERFECTWORLD_MODE:
74 | sm_kMac = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_RESET,
75 | KeyBuilder.LENGTH_DES3_2KEY,
76 | false);
77 | ma_kMac = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
78 | KeyBuilder.LENGTH_DES3_2KEY,
79 | false);
80 | break;
81 | case PassportCrypto.CREF_MODE:
82 | case PassportCrypto.JCOP41_MODE:
83 | sm_kMac_a = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_RESET,
84 | KeyBuilder.LENGTH_DES,
85 | false);
86 | sm_kMac_b = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_RESET,
87 | KeyBuilder.LENGTH_DES,
88 | false);
89 | ma_kMac_a = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
90 | KeyBuilder.LENGTH_DES,
91 | false);
92 | ma_kMac_b = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
93 | KeyBuilder.LENGTH_DES,
94 | false);
95 | break;
96 | }
97 | tmpKeys = JCSystem.makeTransientByteArray((short)32, JCSystem.CLEAR_ON_DESELECT);
98 | }
99 |
100 |
101 | public DESKey getMacKey() {
102 | if(PassportApplet.hasMutuallyAuthenticated()) {
103 | return sm_kMac;
104 | }
105 | else {
106 | return ma_kMac;
107 | }
108 | }
109 |
110 | public DESKey getMacKey(byte aOrb) {
111 | if(PassportApplet.hasMutuallyAuthenticated()) {
112 | if(aOrb == KEY_A) {
113 | return sm_kMac_a;
114 | }
115 | else {
116 | return sm_kMac_b;
117 | }
118 | }
119 | else {
120 | if(aOrb == KEY_A) {
121 | return ma_kMac_a;
122 | }
123 | else {
124 | return ma_kMac_b;
125 | }
126 | }
127 | }
128 |
129 | public DESKey getCryptKey() {
130 | if(PassportApplet.hasMutuallyAuthenticated()) {
131 | return sm_kEnc;
132 | }
133 | else {
134 | return ma_kEnc;
135 | }
136 | }
137 |
138 | public void setMutualAuthenticationKeys(byte[] kMac, short kMac_offset, byte[] kEnc, short kEnc_offset) {
139 | ma_kEnc.setKey(kEnc, kEnc_offset);
140 | switch(mode) {
141 | case PassportCrypto.PERFECTWORLD_MODE:
142 | ma_kMac.setKey(kMac, kMac_offset);
143 | break;
144 | case PassportCrypto.CREF_MODE:
145 | case PassportCrypto.JCOP41_MODE:
146 | ma_kMac_a.setKey(kMac, kMac_offset);
147 | ma_kMac_b.setKey(kMac, (short)(kMac_offset + 8));
148 | break;
149 | }
150 | }
151 |
152 | public void setSecureMessagingKeys(byte[] kMac, short kMac_offset, byte[] kEnc, short kEnc_offset) {
153 | sm_kEnc.setKey(kEnc, kEnc_offset);
154 | switch(mode) {
155 | case PassportCrypto.PERFECTWORLD_MODE:
156 | sm_kMac.setKey(kMac, kMac_offset);
157 | break;
158 | case PassportCrypto.CREF_MODE:
159 | case PassportCrypto.JCOP41_MODE:
160 | sm_kMac_a.setKey(kMac, kMac_offset);
161 | sm_kMac_b.setKey(kMac, (short)(kMac_offset + 8));
162 | break;
163 | }
164 | }
165 | }
166 |
167 |
--------------------------------------------------------------------------------
/src/com/btchip/applet/poc/BTChipNFCForumApplet.java:
--------------------------------------------------------------------------------
1 | /*
2 | *******************************************************************************
3 | * BTChip Bitcoin Hardware Wallet Java Card implementation
4 | * (c) 2013 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Affero General Public License as
8 | * published by the Free Software Foundation, either version 3 of the
9 | * License, or (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Affero General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Affero General Public License
17 | * along with this program. If not, see .
18 | *******************************************************************************
19 | */
20 |
21 | package com.btchip.applet.poc;
22 |
23 | import javacard.framework.APDU;
24 | import javacard.framework.Applet;
25 | import javacard.framework.ISO7816;
26 | import javacard.framework.ISOException;
27 | import javacard.framework.JCSystem;
28 | import javacard.framework.Util;
29 |
30 | /**
31 | * Applet simulating an NFC Forum Type 4 tag for the second factor validation
32 | * @author BTChip
33 | *
34 | */
35 | public class BTChipNFCForumApplet extends Applet {
36 |
37 | public BTChipNFCForumApplet() {
38 | scratch = JCSystem.makeTransientByteArray((short)1, JCSystem.CLEAR_ON_DESELECT);
39 | FILE_DATA = new byte[500];
40 | // Header initialization
41 | short offset = 0;
42 | offset += (short)2;
43 | FILE_DATA[offset++] = (byte)0xC1; // beginning of well known record, short record bit not set
44 | FILE_DATA[offset++] = (byte)0x01;
45 | FILE_DATA[offset++] = (byte)0x00; // start of 4 bytes length
46 | FILE_DATA[offset++] = (byte)0x00;
47 | offset += (short)2;
48 | Util.arrayCopyNonAtomic(LANG, (short)0, FILE_DATA, offset, (short)LANG.length);
49 | BTChipPocApplet.writeIdleText();
50 | }
51 |
52 | public static void writeHeader(short textSize) {
53 | short offset = (short)0;
54 | Util.setShort(FILE_DATA, offset, (short)(textSize + 1 + 5 + 4 + 2 + 1)); // prefix with size of full record
55 | offset += (short)(2 + 4);
56 | Util.setShort(FILE_DATA, offset, (short)(textSize + 1 + 5)); // size of text record payload
57 | }
58 |
59 | @Override
60 | public boolean select() { // only grant access on the contactless interface
61 | return (BTChipPocApplet.isContactless());
62 | }
63 |
64 | @Override
65 | public void process(APDU apdu) throws ISOException {
66 | if (selectingApplet()) {
67 | return;
68 | }
69 | byte[] buffer = apdu.getBuffer();
70 | if (buffer[ISO7816.OFFSET_CLA] != NFCFORUM_CLA) {
71 | ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
72 | }
73 | switch(buffer[ISO7816.OFFSET_INS]) {
74 | case INS_SELECT: {
75 | apdu.setIncomingAndReceive();
76 | short selectedFile = Util.getShort(buffer, ISO7816.OFFSET_CDATA);
77 | switch(selectedFile) {
78 | case EF_CONTAINER:
79 | scratch[OFFSET_SELECTED_FILE] = SELECTED_FILE_CONTAINER;
80 | break;
81 | case EF_NDEF:
82 | scratch[OFFSET_SELECTED_FILE] = SELECTED_FILE_NDEF;
83 | break;
84 | default:
85 | ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
86 | }
87 | }
88 | break;
89 |
90 | case INS_READ: {
91 | short offset = Util.makeShort(buffer[ISO7816.OFFSET_P1], buffer[ISO7816.OFFSET_P2]);
92 | if (scratch[OFFSET_SELECTED_FILE] == SELECTED_FILE_NONE) {
93 | ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
94 | }
95 | byte[] fileData = null;
96 | switch(scratch[OFFSET_SELECTED_FILE]) {
97 | case SELECTED_FILE_CONTAINER:
98 | fileData = CONTAINER_DATA;
99 | break;
100 | case SELECTED_FILE_NDEF:
101 | fileData = FILE_DATA;
102 | break;
103 | }
104 | if (offset >= (short)fileData.length) {
105 | ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
106 | }
107 | short sizeRead = (short)(buffer[ISO7816.OFFSET_LC] & 0xff);
108 | short blockLength = (((short)(offset + sizeRead) > (short)fileData.length) ? (short)(fileData.length - offset) : sizeRead);
109 | Util.arrayCopyNonAtomic(fileData, offset, buffer, (short)0, blockLength);
110 | apdu.setOutgoingAndSend((short)0, blockLength);
111 | }
112 | break;
113 |
114 | }
115 | }
116 |
117 | public static void install (byte bArray[], short bOffset, byte bLength) throws ISOException {
118 | new BTChipNFCForumApplet().register(bArray, (short)(bOffset + 1), bArray[bOffset]);
119 | }
120 |
121 | public static final byte OFFSET_TEXT = (byte)15;
122 |
123 | private static final byte NFCFORUM_CLA = (byte)0x00;
124 | private static final byte INS_SELECT = (byte)0xA4;
125 | private static final byte INS_READ = (byte)0xB0;
126 |
127 | private static final short EF_CONTAINER = (short)0xE103;
128 | private static final short EF_NDEF = (short)0xE104;
129 |
130 | private static final byte SELECTED_FILE_NONE = (byte)0x00;
131 | private static final byte SELECTED_FILE_CONTAINER = (byte)0x01;
132 | private static final byte SELECTED_FILE_NDEF = (byte)0x02;
133 |
134 | private static final byte OFFSET_SELECTED_FILE = (byte)0x00;
135 |
136 | private static final byte CONTAINER_DATA[] = {
137 | (byte)0x00, (byte)0x0F, // length
138 | (byte)0x20, // mapping version 2.0
139 | (byte)0x00, (byte)0xFF, // max R-APDU data size
140 | (byte)0x00, (byte)0xFF, // max C-APDU data size
141 | (byte)0x04, (byte)0x06, // NDEF File Control TL
142 | (byte)0xE1, (byte)0x04, // EF_NDEF
143 | (byte)0x01, (byte)0xF4, // Max NDEF size (update with FILE_DATA size)
144 | (byte)0x00, // Read always
145 | (byte)0xFF // Write never
146 | };
147 |
148 | private static final byte LANG[] = {
149 | (byte)'T', (byte)0x05, (byte)'e', (byte)'n', (byte)'-', (byte)'U', (byte)'S' // en-US text record
150 | };
151 |
152 | public static byte FILE_DATA[];
153 |
154 | private static byte scratch[];
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/src/sos/passportapplet/CREFPassportCrypto.java:
--------------------------------------------------------------------------------
1 | /*
2 | * passportapplet - A reference implementation of the MRTD standards.
3 | *
4 | * Copyright (C) 2006 SoS group, Radboud University
5 | *
6 | * This library is free software; you can redistribute it and/or
7 | * modify it under the terms of the GNU Lesser General Public
8 | * License as published by the Free Software Foundation; either
9 | * version 2.1 of the License, or (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | * Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public
17 | * License along with this library; if not, write to the Free Software
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 | *
20 | * $Id: CREFPassportCrypto.java 945 2009-05-12 08:31:57Z woj76 $
21 | */
22 |
23 | package sos.passportapplet;
24 |
25 | import javacard.framework.ISO7816;
26 | import javacard.framework.ISOException;
27 | import javacard.framework.JCSystem;
28 | import javacard.framework.Util;
29 | import javacard.security.CryptoException;
30 | import javacard.security.DESKey;
31 | import javacard.security.Signature;
32 | import javacardx.crypto.Cipher;
33 |
34 | /**
35 | * This class is a hack. It (probably) implements
36 | * => encrypt/decrypt of ALG_DES_CBC_NOPAD using ALG_DES_CBC_ISO9797_M2
37 |
38 | * This is because ALG_DES_CBC_NOPAD and ALG_DES_MAC8_ISO9797_1_M2_ALG3 do not
39 | * exist on CREF.
40 | *
41 | * @author Cees-Bart Breunesse
42 | * @author Ronny Wichers Schreur
43 | *
44 | * @version $Revision: 945 $
45 | */
46 | public class CREFPassportCrypto extends JCOP41PassportCrypto implements ISO7816 {
47 | private byte padding;
48 |
49 | protected void init() {
50 | ciph = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
51 |
52 | sig = Signature.getInstance(Signature.ALG_DES_MAC8_ISO9797_M2,
53 | false);
54 | }
55 |
56 | CREFPassportCrypto(KeyStore keyStore) {
57 | super(keyStore);
58 |
59 | tempSpace_decryptDES = JCSystem.makeTransientByteArray((short) 16,
60 | JCSystem.CLEAR_ON_RESET);
61 | tempSpace_doMacFinal = JCSystem.makeTransientByteArray((short) 24,
62 | JCSystem.CLEAR_ON_RESET);
63 | }
64 |
65 | private short decryptDESusingDESCBCM2(DESKey key, byte[] in,
66 | short in_offset, byte[] out, short out_offset, short length) {
67 | if ((ciph.getAlgorithm() != Cipher.ALG_DES_CBC_ISO9797_M2)
68 | || ((short) (length + out_offset + 16) > (short) (out.length))
69 | || ((short) (length + in_offset) > (short) in.length))
70 | ISOException.throwIt((short) 0x6d69);
71 |
72 | ciph.init(key, Cipher.MODE_ENCRYPT);
73 | ciph.doFinal(ZERO,
74 | (short) 0,
75 | (short) 8,
76 | tempSpace_decryptDES,
77 | (short) 0);
78 |
79 | ciph.init(key, Cipher.MODE_DECRYPT);
80 | short written = ciph.update(in, in_offset, length, out, out_offset);
81 | written += ciph.doFinal(tempSpace_decryptDES,
82 | (short) 0,
83 | (short) (16),
84 | out,
85 | (short) (out_offset + written));
86 |
87 | return (short)(written - 8); // FIXME: hack, compensate for padding
88 | }
89 |
90 | private static byte[] tempSpace_decryptDES;
91 | private static final byte[] ZERO = { 0, 0, 0, 0, 0, 0, 0, 0 };
92 | private DESKey k;
93 | private byte[] tempSpace_doMacFinal;
94 |
95 | private void decryptInit(DESKey k) {
96 | this.k = k;
97 | }
98 |
99 | private void encryptInit(DESKey k) {
100 | this.k = k;
101 | }
102 |
103 | public void decryptInit() {
104 | k=keyStore.getCryptKey();
105 | }
106 |
107 | public short decrypt(byte[] ctext, short ctext_offset, short ctext_len,
108 | byte[] ptext, short ptext_offset) {
109 | CryptoException.throwIt((short)0x6d66);
110 | return 0;
111 | }
112 |
113 | public short encrypt(byte[] ctext, short ctext_offset, short ctext_len,
114 | byte[] ptext, short ptext_offset) {
115 | CryptoException.throwIt((short)0x6d66);
116 | return 0;
117 | }
118 |
119 | public short decryptFinal(byte[] ctext, short ctext_offset, short ctext_len,
120 | byte[] ptext, short ptext_offset) {
121 | return decryptDESusingDESCBCM2(k, ctext, ctext_offset, ptext, ptext_offset, ctext_len);
122 | }
123 |
124 | public short encryptInit(byte padding, byte[] plainText, short plaintextOffset, short plaintextLength) {
125 | return encryptInit(keyStore.getCryptKey(), padding, plainText, plaintextOffset, plaintextLength);
126 |
127 | }
128 |
129 | private short encryptInit(DESKey k, byte padding, byte[] plainText, short plaintextOffset, short plaintextLength) {
130 | this.k = k;
131 | this.padding = padding;
132 | return plaintextLength;
133 | }
134 |
135 | public short encryptFinal(byte[] ptext, short ptext_offset, short ptext_len,
136 | byte[] ctext, short ctext_offset) {
137 |
138 | ciph.init(k, Cipher.MODE_ENCRYPT);
139 | short len = ciph.doFinal(ptext, ptext_offset, ptext_len, ctext, ctext_offset);
140 |
141 | if(padding == PAD_INPUT) {
142 | // ALG_DES_CBC_ISO9797_M2 does padding
143 | return len;
144 | }
145 | else if (padding == DONT_PAD_INPUT) {
146 | return (short)(len - 8); // FIXME: hack
147 | }
148 | return 0;
149 | }
150 |
151 | public void createMacFinal(byte[] msg, short msg_offset, short msg_len,
152 | byte[] mac, short mac_offset) {
153 | DESKey kA = keyStore.getMacKey(KeyStore.KEY_A);
154 | DESKey kB = keyStore.getMacKey(KeyStore.KEY_B);
155 |
156 | // updateMac(msg, msg_offset, msg_len);
157 | sig.sign(msg, msg_offset, msg_len, mac, mac_offset);
158 |
159 | decryptInit(kB);
160 | short tempmac_offset = 0;
161 | //macCiphECB.init(kB, Cipher.MODE_DECRYPT);
162 | decryptFinal(mac, mac_offset, (short)8, tempSpace_doMacFinal, tempmac_offset );
163 | //macCiphECB.doFinal(mac, mac_offset, (short)8, mac, mac_offset);
164 |
165 | encryptInit(kA);
166 | //macCiphECB.init(kA, Cipher.MODE_ENCRYPT);
167 | encryptFinal(tempSpace_doMacFinal, tempmac_offset, (short)8, tempSpace_doMacFinal, tempmac_offset);
168 | //macCiphECB.doFinal(mac, mac_offset, (short)8, mac, mac_offset);
169 |
170 | Util.arrayCopyNonAtomic(tempSpace_doMacFinal, tempmac_offset, mac, mac_offset, (short)8);
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/src/openemv/EMVStaticData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 Digital Security group, Radboud University
3 | *
4 | * This library is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU Lesser General Public
6 | * License as published by the Free Software Foundation; either
7 | * version 2.1 of the License, or (at your option) any later version.
8 | *
9 | * This library is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * Lesser General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Lesser General Public
15 | * License along with this library; if not, write to the Free Software
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 | */
18 |
19 | package openemv;
20 |
21 | import javacard.framework.ISOException;
22 | import javacard.framework.Util;
23 |
24 | /* Class to record all the static data of an EMV applet, ie. the card details that
25 | * do not change over time (such as PAN, expiry date, etc.), with the exception
26 | * of the cryptographic keys.
27 | *
28 | * This static data is organised in the simplest possible way, using some public byte
29 | * arrays to record exact APDUs that the card has to produce.
30 | *
31 | * This class does not offer personalisation support - everything is hard-coded.
32 | *
33 | * @author joeri (joeri@cs.ru.nl)
34 | * @author erikpoll (erikpoll@cs.ru.nl)
35 | *
36 | */
37 |
38 | public class EMVStaticData implements EMVConstants {
39 |
40 | private final byte[] theAFL = new byte[]{ (byte)0x08, 0x01, 0x03, 0x01}; // AFL from Dutch bank cards;
41 |
42 | /** Returns the 4 byte AFL (Application File Locator) */
43 | public byte[] getAFL(){
44 | return theAFL;
45 | }
46 |
47 | /** Returns the 2 byte AIP (Application Interchange Profile)
48 | * See Book 3, Annex C1 for details
49 | * */
50 | public short getAIP() {
51 | return 0x5800;
52 | // 4000 SDA supported
53 | // 1000 Cardholder verification supported
54 | // 0800 Terminal risk management is to be performed
55 | }
56 |
57 | private final byte[] fci = new byte[]{
58 | 0x6F, // FCI Template
59 | 0x25, // Length
60 | (byte)0x84, 0x07, (byte)0xA0, 0x00, 0x00, 0x00, 0x04, (byte)0x80, 0x02, // Dedicated File name
61 | (byte)0xA5, 0x1A, // File Control Information Proprietary Template
62 | 0x50, 0x0E, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x43, 0x6F, 0x64, 0x65, 0x20, 0x41, 0x75, 0x74, // Application Label
63 | (byte)0x87, 0x01, 0x00, // Application Priority Indicator
64 | 0x5F, 0x2D, 0x04, 0x6E, 0x6C, 0x65, 0x6E // Language Preference
65 | };
66 |
67 | // File for EMV-CAP
68 | private final byte[] record1 = new byte[]{
69 | 0x70, // Read record message template
70 | 0x00, // Record length
71 | (byte)0x8C, 0x21, (byte)0x9F, 0x02, 0x06, (byte)0x9F, 0x03, 0x06, (byte)0x9F, 0x1A, 0x02, (byte)0x95, 0x05, 0x5F, 0x2A, 0x02, (byte)0x9A, 0x03, (byte)0x9C, 0x01, (byte)0x9F, 0x37, 0x04, (byte)0x9F, 0x35, 0x01, (byte)0x9F, 0x45, 0x02, (byte)0x9F, 0x4C, 0x08, (byte)0x9F, 0x34, 0x03, // Card Risk Management Data Object List 1
72 | (byte)0x8D, 0x0C, (byte)0x91, 0x0A, (byte)0x8A, 0x02, (byte)0x95, 0x05, (byte)0x9F, 0x37, 0x04, (byte)0x9F, 0x4C, 0x08, // Card Risk Management Data Object List 2
73 | 0x5A, 0x05, 0x12, 0x34, 0x56, 0x78, (byte)0x90, // 5A Primary account number
74 | 0x5F, 0x34, 0x01, 0x02, // Bank identifier code
75 | (byte)0x8E, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, // Cardholder Verification Method (CVM) List (Always transaction_data PIN performed by ICC)
76 | (byte)0x9F, 0x55, 0x01, (byte)0x80, // Unknown field
77 | (byte)0x9F, 0x56, 0x0C, 0x00, 0x00, 0x7F, (byte)0xFF, (byte)0xFF, (byte)0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bit filter
78 | };
79 |
80 | /*
81 | // File for EMV
82 | private final byte[] record1 = new byte[]{
83 | 0x70, // Read record message template
84 | 0x00, // Record length
85 | // Mandatory data objects
86 | 0x5F, 0x24, 0x03, // Application Expiry Date
87 | 0x5A, 0x05, 0x12, 0x34, 0x56, 0x78, (byte)0x90, // 5A Primary account number
88 | (byte)0x8C, 0x21, (byte)0x9F, 0x02, 0x06, (byte)0x9F, 0x03, 0x06, (byte)0x9F, 0x1A, 0x02, (byte)0x95, 0x05, 0x5F, 0x2A, 0x02, (byte)0x9A, 0x03, (byte)0x9C, 0x01, (byte)0x9F, 0x37, 0x04, (byte)0x9F, 0x35, 0x01, (byte)0x9F, 0x45, 0x02, (byte)0x9F, 0x4C, 0x08, (byte)0x9F, 0x34, 0x03, // Card Risk Management Data Object List 1
89 | (byte)0x8D, 0x18, (byte)0x91, 0x0A, (byte)0x8A, 0x02, (byte)0x95, 0x05, (byte)0x9F, 0x37, 0x04, (byte)0x9F, 0x4C, 0x08, // Card Risk Management Data Object List 2
90 | // Other data
91 | (byte)0x8E, 0x02, 0x01, 0x00, // Cardholder Verification Method (CVM) List (Always transaction_data PIN performed by ICC)
92 | (byte)0x9F, 0x4A, 0x01, (byte)0x82, // Static Data Authentication Tag List
93 | };
94 | */
95 |
96 | private final byte[] record2 = new byte[]{
97 | 0x70, // Read record message template
98 | 0x00, // Record length
99 | // Data required for DDA/CDA
100 | (byte)0x8F, 0x00, // Certification Authority Public Key Index
101 | (byte)0x90, 0x00, // Issuer Public Key Certificate
102 | (byte)0x92, 0x00, // Issuer Public Key Remainder
103 | (byte)0x9F, 0x32, 0x00, // Issuer Public Key Exponent
104 | };
105 |
106 | private final byte[] record3 = new byte[]{
107 | 0x70, // Read record message template
108 | 0x00, // Record length
109 | // Data required for DDA/CDA (continued)
110 | (byte)0x9F, 0x46, 0x00, // ICC Public Key Certificate
111 | (byte)0x9F, 0x47, 0x00, // ICC Public Key Exponent
112 | (byte)0x9F, 0x48, 0x00, // ICC Public Key Remainder
113 | (byte)0x9F, 0x49, 0x03, (byte)0x9F, 0x37, 0x04, // Dynamic Data Authentication Data Object List (DDOL)
114 | };
115 |
116 | /** Return the length of the data specified in the CDOL1
117 | *
118 | */
119 | public short getCDOL1DataLength() {
120 | return 0x2B;
121 | //return 43;
122 | }
123 |
124 | /** Return the length of the data specified in the CDOL2
125 | *
126 | */
127 | public short getCDOL2DataLength() {
128 | return 0x1D;
129 | //return 29;
130 | }
131 |
132 | public byte[] getFCI() {
133 | return fci;
134 | }
135 |
136 | public short getFCILength() {
137 | return (short)fci.length;
138 | }
139 |
140 | /** Provide the response to INS_READ_RECORD in the response buffer
141 | *
142 | */
143 | public void readRecord(byte[] apduBuffer, byte[] response){
144 | if(apduBuffer[OFFSET_P2] == 0x0C && apduBuffer[OFFSET_P1] == 0x01) { // SFI 1, Record 1
145 | Util.arrayCopyNonAtomic(record1, (short)0,
146 | response, (short)0, (short)record1.length);
147 | response[1] = (byte)(record1.length - 2);
148 | }
149 | else if(apduBuffer[OFFSET_P2] == 0x0C && apduBuffer[OFFSET_P1] == 0x02) { // SFI 1, Record 2
150 | Util.arrayCopyNonAtomic(record2, (short)0,
151 | response, (short)0, (short)record2.length);
152 | response[1] = (byte)(record2.length - 2);
153 | }
154 | else if(apduBuffer[OFFSET_P2] == 0x0C && apduBuffer[OFFSET_P1] == 0x03) { // SFI 1, Record 3
155 | Util.arrayCopyNonAtomic(record3, (short)0,
156 | response, (short)0, (short)record3.length);
157 | response[1] = (byte)(record3.length - 2);
158 | }
159 | else {
160 | // File does not exist
161 | ISOException.throwIt(SW_FILE_NOT_FOUND);
162 | }
163 | }
164 |
165 |
166 | }
167 |
--------------------------------------------------------------------------------