├── .gitignore
├── .gitmodules
├── .travis.yml
├── LICENSE
├── README.md
├── applet-demo
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── app
│ └── demo
│ ├── DemoApplet.java
│ ├── TempBuffer.java
│ └── TempStack.java
├── build.xml
├── install.script
├── library-auth
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── auth
│ ├── AuthContext.java
│ ├── AuthMethod.java
│ ├── AuthMethodCaller.java
│ ├── AuthMethodMedium.java
│ ├── AuthProtocol.java
│ └── AuthProtocolSecret.java
├── library-ber
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── openjavacard
│ │ └── lib
│ │ └── ber
│ │ ├── BERHandler.java
│ │ ├── BERLength.java
│ │ ├── BERReader.java
│ │ ├── BERSource.java
│ │ ├── BERTag.java
│ │ └── BERWriter.java
│ └── test
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── ber
│ ├── BERReaderTest.java
│ └── BERWriterTest.java
├── library-codec
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── codec
│ ├── Base64Codec.java
│ ├── Decoder.java
│ ├── Encoder.java
│ └── HexCodec.java
├── library-ctlv
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── ctlv
│ ├── ATR.java
│ └── CTLV.java
├── library-cvmpin
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── cvmpin
│ └── CVMPIN.java
├── library-debug
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── debug
│ ├── Debug.java
│ ├── DebugException.java
│ ├── DebugProtocol.java
│ └── DebugService.java
├── library-fortuna
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── fortuna
│ ├── FortunaRandom.java
│ └── LongNum.java
├── library-isofs
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── isofs
│ ├── DF.java
│ ├── EF.java
│ ├── EFCyclicFixed.java
│ ├── EFLinearFixed.java
│ ├── EFLinearVariable.java
│ ├── EFRecords.java
│ ├── EFTransparent.java
│ ├── ISOConfig.java
│ ├── ISOExtensions.java
│ ├── ISOFile.java
│ ├── ISOFileCreator.java
│ ├── ISOFileSystem.java
│ ├── ISOSession.java
│ └── MF.java
├── library-oath
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── oath
│ ├── HOTPGenerator.java
│ ├── HOTPVerifier.java
│ ├── LongNum.java
│ ├── OATHCipher.java
│ ├── OATHConfig.java
│ ├── TOTPClock.java
│ └── TOTPGenerator.java
├── library-password
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── password
│ ├── PasswordHash.java
│ └── PasswordPolicy.java
├── library-rsa
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── rsa
│ ├── MGF1.java
│ └── RSAOAEPCipher.java
├── library-string
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── string
│ ├── ASCII.java
│ ├── StringStatistics.java
│ └── StringWriter.java
├── library-tlv
└── src
│ └── main
│ └── java
│ └── org
│ └── openjavacard
│ └── lib
│ └── tlv
│ ├── TLVBuilder.java
│ ├── TLVConstructed.java
│ ├── TLVNode.java
│ └── TLVPrimitive.java
├── openjavacard-libraries.iml
└── uninstall.script
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/**
3 | */build/**
4 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ext/ant-javacard"]
2 | path = ext/ant-javacard
3 | url = https://github.com/martinpaljak/ant-javacard.git
4 | [submodule "ext/javacard-sdks"]
5 | path = ext/javacard-sdks
6 | url = https://github.com/martinpaljak/oracle_javacard_sdks.git
7 | [submodule "ext/globalplatform-exports"]
8 | path = ext/globalplatform-exports
9 | url = https://github.com/OpenJavaCard/globalplatform-exports.git
10 | [submodule "ext/jcardsim"]
11 | path = ext/jcardsim
12 | url = https://github.com/licel/jcardsim
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - openjdk8
4 | install:
5 | - true
6 | script:
7 | - ant clean
8 | - ant test
9 | - ant javadoc
10 | addons:
11 | apt:
12 | packages:
13 | - ant
14 | - ant-optional
15 | - junit4
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## OpenJavaCard Libraries
2 |
3 | This is a set of reusable libraries for the JavaCard environment.
4 |
5 | CAUTION: All completely experimental at this point.
6 |
7 | [](https://travis-ci.org/OpenJavaCard/openjavacard-libraries)
8 |
9 | ### Project
10 |
11 | For more information about this overall project, see our [website](https://openjavacard.org/).
12 |
13 | You can follow us on [Twitter](https://twitter.com/openjavacardorg) and chat with us on [Gitter](https://gitter.im/openjavacard/general).
14 |
15 | ### Overview
16 |
17 | | Name | Description | Status |
18 | | --------------------- |------------------------------------ | ------------ |
19 | | library-auth | Authentication framework | Experiment |
20 | | library-ber | BER-TLV processing | Usable |
21 | | library-codec | Codec library | Experiment |
22 | | library-ctlv | Compact-TLV utilities | Experiment |
23 | | library-cvmpin | CVM PIN wrapper | Experiment |
24 | | library-debug | Debug utilities | Experiment |
25 | | library-fortuna | Fortuna PRNG | Usable |
26 | | library-isofs | ISO7816 filesystem | Experiment |
27 | | library-oath | OATH authentication | Experiment |
28 | | library-password | Password authentication | Experiment |
29 | | library-rsa | RSA supplementary ciphers | Experiment |
30 | | library-string | String processing | Experiment |
31 | | library-tlv | TLV object representation | Experiment |
32 | | --------------------- |------------------------------------ | ------------ |
33 |
34 | ### Components
35 |
36 | * BER-TLV library
37 | * Callback-based TLV parsing
38 | * Builder-based TLV writing
39 | * Supports 2-byte tags
40 | * Flexible interface
41 | * Allocation-free design
42 | * Compact-TLV library
43 | * Minimalist implementation
44 | * Can construct historical bytes for ATR
45 | * Fortuna PRNG implementation
46 | * Well-Known algorithm
47 | * Refuses operation without seed
48 | * RSA library
49 | * OAEP encryption
50 | * MGF1 masking
51 | * String library
52 | * Character type functions
53 | * String statistics utility
54 | * Password library
55 | * Salt and hash
56 |
57 | ### Hacks And Intentions
58 |
59 | * ISO filesystem library
60 | * lots of code exists
61 | * nothing usable yet
62 | * Authentication library
63 | * some code exists
64 | * modularize authentication
65 | * support key derivation
66 | * TLV object representation
67 | * OATH cipher suite
68 | * Blinding ciphers (pseudonymous buddy matching)
69 | * CBOR implementation
70 | * we would love to have one
71 | * Codec library
72 | * hex, base64...
73 |
--------------------------------------------------------------------------------
/applet-demo/src/main/java/org/openjavacard/app/demo/DemoApplet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.app.demo;
21 |
22 | import javacard.framework.APDU;
23 | import javacard.framework.Applet;
24 | import javacard.framework.ISO7816;
25 | import javacard.framework.ISOException;
26 | import javacard.framework.JCSystem;
27 | import javacard.framework.Util;
28 | import org.openjavacard.lib.ber.BERHandler;
29 | import org.openjavacard.lib.ber.BERReader;
30 | import org.openjavacard.lib.ber.BERSource;
31 | import org.openjavacard.lib.ber.BERTag;
32 | import org.openjavacard.lib.ber.BERWriter;
33 | import org.openjavacard.lib.fortuna.FortunaRandom;
34 | import org.openjavacard.lib.fortuna.LongNum;
35 | import org.openjavacard.lib.password.PasswordHash;
36 | import org.openjavacard.lib.string.StringStatistics;
37 |
38 | /**
39 | *
40 | */
41 | public final class DemoApplet extends Applet implements ISO7816 {
42 |
43 | private static final byte CLA_PROPRIETARY = (byte) 0x80;
44 |
45 | private static final byte INS_FORTUNA_RESET = (byte) 0x00;
46 | private static final byte INS_FORTUNA_SEED = (byte) 0x02;
47 | private static final byte INS_FORTUNA_GENERATE = (byte) 0x04;
48 |
49 | private static final byte INS_LONGNUM_GET = (byte) 0x10;
50 | private static final byte INS_LONGNUM_SET = (byte) 0x12;
51 | private static final byte INS_LONGNUM_ADD = (byte) 0x14;
52 | private static final byte INS_LONGNUM_SUB = (byte) 0x16;
53 |
54 | private static final byte INS_BER_PARSE = (byte) 0x20;
55 | private static final byte INS_BER_WRITE = (byte) 0x22;
56 | private static final byte INS_BER_COPY = (byte) 0x24;
57 |
58 | private static final byte INS_DEBUG_MEMORY = (byte) 0x30;
59 | private static final byte INS_DEBUG_MESSAGE = (byte) 0x32;
60 |
61 | private static final byte INS_STRING_STATS = (byte) 0x40;
62 |
63 | private static final byte INS_PASS_CHECK = (byte) 0x50;
64 | private static final byte INS_PASS_UPDATE = (byte) 0x52;
65 | private static final byte INS_PASS_RESET = (byte) 0x54;
66 | private static final byte INS_PASS_UNBLOCK = (byte) 0x056;
67 |
68 | private static final byte INS_CTLV_BUILD = (byte) 0x60;
69 |
70 | /**
71 | * Installation method for the applet
72 | */
73 | public static void install(byte[] buf, short off, byte len) {
74 | short pos = off;
75 | // find AID (used for install)
76 | byte lenAID = buf[pos++];
77 | short offAID = pos;
78 | pos += lenAID;
79 | // ignore the rest (control data and install data)
80 |
81 | // instantiate and initialize the applet
82 | DemoApplet applet = new DemoApplet();
83 | // register the applet
84 | applet.register(buf, offAID, lenAID);
85 | }
86 |
87 | //private final Debug mDebug;
88 |
89 | private final TempBuffer mBuffer;
90 |
91 | private final byte[] mTmp;
92 |
93 | private final FortunaRandom mFortuna;
94 |
95 | private final LongNum mLongNum;
96 |
97 | private final BERReader mReader;
98 | private final BERWriter mWriter;
99 | private final ParseHandler mParseHandler;
100 |
101 | private final PasswordHash mPasswordHash;
102 |
103 | private final StringStatistics mStringStats;
104 |
105 | /**
106 | * Main constructor
107 | */
108 | private DemoApplet() {
109 | //mDebug = Debug.getInstance(this);
110 | mBuffer = new TempBuffer((short) 128, JCSystem.CLEAR_ON_DESELECT);
111 | mTmp = JCSystem.makeTransientByteArray((short) 32, JCSystem.CLEAR_ON_DESELECT);
112 | mFortuna = new FortunaRandom();
113 | mLongNum = new LongNum((byte) 8, JCSystem.CLEAR_ON_DESELECT);
114 | mReader = new BERReader((byte) 4, JCSystem.CLEAR_ON_DESELECT);
115 | mWriter = new BERWriter((byte) 32, (byte) 4, (short) 128, JCSystem.CLEAR_ON_DESELECT);
116 | mParseHandler = new ParseHandler();
117 | mStringStats = new StringStatistics(JCSystem.CLEAR_ON_DESELECT);
118 | mPasswordHash = new PasswordHash((byte) 8, (byte) 32, (byte) 5, JCSystem.CLEAR_ON_DESELECT);
119 | }
120 |
121 | /**
122 | * Applet select handler
123 | *
124 | * @return true if select okay
125 | */
126 | public final boolean select() {
127 | return true;
128 | }
129 |
130 | /**
131 | * Applet deselect handler
132 | */
133 | public final void deselect() {
134 | }
135 |
136 | /**
137 | * Process an APDU
138 | *
139 | * @param apdu to be processed
140 | * @throws ISOException on error
141 | */
142 | public final void process(APDU apdu) throws ISOException {
143 | byte[] buffer = apdu.getBuffer();
144 | byte cla = buffer[OFFSET_CLA];
145 | byte ins = buffer[OFFSET_INS];
146 |
147 | // handle selection of the applet
148 | if (selectingApplet()) {
149 | return;
150 | }
151 |
152 | // give the debugger a chance
153 | //if (mDebug.process(apdu)) {
154 | // return;
155 | //}
156 |
157 | // secure messaging is not supported
158 | if (apdu.isSecureMessagingCLA()) {
159 | ISOException.throwIt(SW_SECURE_MESSAGING_NOT_SUPPORTED);
160 | }
161 |
162 | mBuffer.clear();
163 |
164 | // process commands to the applet
165 | if (cla == CLA_PROPRIETARY) {
166 | switch (ins) {
167 | case INS_FORTUNA_RESET:
168 | processFortunaReset(apdu);
169 | break;
170 | case INS_FORTUNA_SEED:
171 | processFortunaSeed(apdu);
172 | break;
173 | case INS_FORTUNA_GENERATE:
174 | processFortunaGenerate(apdu);
175 | break;
176 | case INS_LONGNUM_GET:
177 | processLongNumGet(apdu);
178 | break;
179 | case INS_LONGNUM_SET:
180 | processLongNumSet(apdu);
181 | break;
182 | case INS_LONGNUM_ADD:
183 | processLongNumAdd(apdu);
184 | break;
185 | case INS_LONGNUM_SUB:
186 | processLongNumSub(apdu);
187 | break;
188 | case INS_BER_PARSE:
189 | processBerParse(apdu);
190 | break;
191 | case INS_BER_WRITE:
192 | processBerWrite(apdu);
193 | break;
194 | case INS_BER_COPY:
195 | processBerCopy(apdu);
196 | break;
197 | case INS_STRING_STATS:
198 | processStringStats(apdu);
199 | break;
200 | case INS_PASS_CHECK:
201 | processPassCheck(apdu);
202 | break;
203 | case INS_PASS_UPDATE:
204 | processPassUpdate(apdu);
205 | break;
206 | case INS_PASS_RESET:
207 | processPassReset(apdu);
208 | break;
209 | case INS_PASS_UNBLOCK:
210 | processPassUnblock(apdu);
211 | break;
212 | case INS_DEBUG_MEMORY:
213 | processDebugMemory(apdu);
214 | break;
215 | case INS_DEBUG_MESSAGE:
216 | processDebugMessage(apdu);
217 | break;
218 | default:
219 | ISOException.throwIt(SW_INS_NOT_SUPPORTED);
220 | }
221 | } else {
222 | ISOException.throwIt(SW_CLA_NOT_SUPPORTED);
223 | }
224 | }
225 |
226 | private final void processFortunaReset(APDU apdu) {
227 | mFortuna.reset();
228 | }
229 |
230 | private final void processFortunaSeed(APDU apdu) {
231 | byte[] buffer = apdu.getBuffer();
232 | byte length = buffer[OFFSET_LC];
233 | mFortuna.setSeed(buffer, (short) 0, (short) length);
234 | }
235 |
236 | private final void processFortunaGenerate(APDU apdu) {
237 | byte[] buffer = apdu.getBuffer();
238 | short request = Util.getShort(buffer, OFFSET_P1);
239 | mFortuna.generateData(buffer, (short) 0, request);
240 | apdu.setOutgoingAndSend((short) 0, request);
241 | }
242 |
243 | private final void processLongNumGet(APDU apdu) {
244 | sendLongNum(apdu);
245 | }
246 |
247 | private final void processLongNumSet(APDU apdu) {
248 | byte[] buffer = apdu.getBuffer();
249 | byte length = buffer[OFFSET_LC];
250 | mLongNum.set(buffer, OFFSET_CDATA, length);
251 | sendLongNum(apdu);
252 | }
253 |
254 | private final void processLongNumAdd(APDU apdu) {
255 | byte[] buffer = apdu.getBuffer();
256 | byte p1 = buffer[OFFSET_P1];
257 | mLongNum.add(p1);
258 | sendLongNum(apdu);
259 | }
260 |
261 | private final void processLongNumSub(APDU apdu) {
262 | byte[] buffer = apdu.getBuffer();
263 | byte p1 = buffer[OFFSET_P1];
264 | mLongNum.sub(p1);
265 | sendLongNum(apdu);
266 | }
267 |
268 | private final void sendLongNum(APDU apdu) {
269 | byte[] buffer = apdu.getBuffer();
270 | short length = mLongNum.getLength();
271 | mLongNum.get(buffer, (short) 0, length);
272 | apdu.setOutgoingAndSend((short) 0, length);
273 | }
274 |
275 | private final void processDebugMemory(APDU apdu) {
276 | //mDebug.logMemory();
277 | }
278 |
279 | private final void processDebugMessage(APDU apdu) {
280 | byte[] buffer = apdu.getBuffer();
281 | short code = Util.getShort(buffer, ISO7816.OFFSET_P1);
282 | short len = apdu.setIncomingAndReceive();
283 | //mDebug.logMessage(code, buffer, ISO7816.OFFSET_CDATA, (byte) len);
284 | }
285 |
286 | private final void processBerParse(APDU apdu) {
287 | byte[] buffer = apdu.getBuffer();
288 | short len = (short) (buffer[OFFSET_LC] & 0xFF);
289 | mReader.parse(buffer, OFFSET_CDATA, len, mParseHandler);
290 | Util.arrayCopyNonAtomic(mBuffer.getBuffer(), (short) 0, buffer, (short) 0, mBuffer.getFill());
291 | apdu.setOutgoingAndSend((short) 0, mBuffer.getFill());
292 | }
293 |
294 | private final void processBerWrite(APDU apdu) {
295 | byte[] buffer = apdu.getBuffer();
296 | short len = apdu.setIncomingAndReceive();
297 |
298 | Util.arrayCopyNonAtomic(buffer, (short) 0, mTmp, (short) 0, (short) 4);
299 |
300 | mWriter.begin((short) 128);
301 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
302 |
303 | mWriter.buildPrimitive(BERTag.TYPE_OCTETSTRING, mTmp, (short) 0, (short) 4);
304 | mWriter.buildPrimitive(BERTag.TYPE_OCTETSTRING, mTmp, (short) 0, (short) 4);
305 |
306 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
307 | mWriter.buildPrimitive(BERTag.TYPE_OCTETSTRING, mTmp, (short) 0, (short) 4);
308 | mWriter.buildPrimitive(BERTag.TYPE_OCTETSTRING, mTmp, (short) 0, (short) 4);
309 | mWriter.endConstructed();
310 |
311 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
312 | mWriter.buildPrimitive(BERTag.TYPE_OCTETSTRING, mTmp, (short) 0, (short) 4);
313 | mWriter.buildPrimitive(BERTag.TYPE_OCTETSTRING, mTmp, (short) 0, (short) 4);
314 | mWriter.endConstructed();
315 |
316 | mWriter.endConstructed();
317 |
318 | mWriter.finishAndSend(apdu);
319 | }
320 |
321 | private final void processBerCopy(APDU apdu) {
322 | byte[] buffer = apdu.getBuffer();
323 | short len = apdu.setIncomingAndReceive();
324 | mWriter.begin((short) buffer.length);
325 | mReader.parse(buffer, OFFSET_CDATA, len, mWriter);
326 | mWriter.finishAndSend(apdu);
327 | }
328 |
329 | private final class ParseHandler implements BERHandler {
330 |
331 | public boolean handlePrimitive(BERSource source, byte depth, short tag, byte[] dataBuf, short dataOff, short dataLen) {
332 | mBuffer.put((byte) 0x53);
333 | mBuffer.put(depth);
334 | mBuffer.put(tag);
335 | mBuffer.put(dataLen);
336 | return true;
337 | }
338 |
339 | public boolean handleBeginConstructed(BERSource source, byte depth, short tag) {
340 | mBuffer.put((byte) 0x53);
341 | mBuffer.put(depth);
342 | mBuffer.put(tag);
343 | mBuffer.put((byte) 0);
344 | return true;
345 | }
346 |
347 | public boolean handleFinishConstructed(BERSource source, byte depth, short tag) {
348 | return true;
349 | }
350 |
351 | }
352 |
353 | private void processStringStats(APDU apdu) {
354 | byte[] buffer = apdu.getBuffer();
355 | short len = apdu.setIncomingAndReceive();
356 | mStringStats.reset();
357 | mStringStats.update(buffer, ISO7816.OFFSET_CDATA, (byte) len);
358 | }
359 |
360 | private void processPassCheck(APDU apdu) {
361 | byte[] buffer = apdu.getBuffer();
362 | short len = apdu.setIncomingAndReceive();
363 | mPasswordHash.check(buffer, OFFSET_CDATA, (byte)len);
364 | }
365 |
366 | private void processPassUpdate(APDU apdu) {
367 | byte[] buffer = apdu.getBuffer();
368 | short len = apdu.setIncomingAndReceive();
369 | mPasswordHash.update(buffer, OFFSET_CDATA, (byte)len);
370 | }
371 |
372 | private void processPassReset(APDU apdu) {
373 | mPasswordHash.reset();
374 | }
375 |
376 | private void processPassUnblock(APDU apdu) {
377 | mPasswordHash.resetAndUnblock();
378 | }
379 |
380 | }
381 |
--------------------------------------------------------------------------------
/applet-demo/src/main/java/org/openjavacard/app/demo/TempBuffer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.app.demo;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 | import javacard.framework.JCSystem;
25 | import javacard.framework.Util;
26 |
27 | public class TempBuffer {
28 |
29 | private final byte[] mBuffer;
30 |
31 | private final short[] mVars;
32 | private final static short VAR_FILL = 0;
33 | private final static short NUM_VARS = 1;
34 |
35 | public TempBuffer(short size) {
36 | mBuffer = new byte[size];
37 | mVars = new short[NUM_VARS];
38 | }
39 |
40 | public TempBuffer(short size, byte clearOn) {
41 | mBuffer = JCSystem.makeTransientByteArray(size, clearOn);
42 | mVars = JCSystem.makeTransientShortArray(NUM_VARS, clearOn);
43 | }
44 |
45 | private void fault() {
46 | ISOException.throwIt(ISO7816.SW_UNKNOWN);
47 | }
48 |
49 | private short checkSpace(short request) {
50 | short fill = mVars[VAR_FILL];
51 | short newOffset = (short)(fill + request);
52 | if(newOffset < 0) {
53 | fault();
54 | }
55 | if(newOffset > mBuffer.length) {
56 | fault();
57 | }
58 | return fill;
59 | }
60 |
61 | public byte[] getBuffer() {
62 | return mBuffer;
63 | }
64 |
65 | public short getFill() {
66 | return mVars[VAR_FILL];
67 | }
68 |
69 | public short getSpace() {
70 | return (short)(mBuffer.length - mVars[VAR_FILL]);
71 | }
72 |
73 | public void clear() {
74 | Util.arrayFillNonAtomic(mBuffer, (short)0, (short)mBuffer.length, (byte)0);
75 | mVars[VAR_FILL] = 0;
76 | }
77 |
78 | public short put(byte b) {
79 | short fill = checkSpace((short)1);
80 | mBuffer[fill++] = b;
81 | mVars[VAR_FILL] = fill;
82 | return fill;
83 | }
84 |
85 | public short put(short b) {
86 | short fill = checkSpace((short)2);
87 | fill = Util.setShort(mBuffer, fill, b);
88 | mVars[VAR_FILL] = fill;
89 | return fill;
90 | }
91 |
92 | public short put(byte[] buf, short off, short len) {
93 | short fill = checkSpace(len);
94 | Util.arrayCopyNonAtomic(buf, off, mBuffer, fill, len);
95 | fill += len;
96 | mVars[VAR_FILL] = fill;
97 | return fill;
98 | }
99 |
100 | public short put(byte[] buf) {
101 | return put(buf, (short)0, (short)buf.length);
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/applet-demo/src/main/java/org/openjavacard/app/demo/TempStack.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.app.demo;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 | import javacard.framework.JCSystem;
25 | import javacard.framework.Util;
26 |
27 | public class TempStack {
28 |
29 | private final short mMaxObjects;
30 | private final short mMaxBytes;
31 |
32 | private short mUsage;
33 | private short mCurrent;
34 |
35 | private final byte[] mBuffer;
36 | private final short[] mOffsets;
37 | private final short[] mLengths;
38 |
39 | public TempStack(short maxObjects, short maxBytes, byte clearOn) {
40 | mMaxObjects = maxObjects;
41 | mMaxBytes = maxBytes;
42 | mUsage = 0;
43 | mCurrent = 0;
44 | mBuffer = JCSystem.makeTransientByteArray(maxBytes, clearOn);
45 | mOffsets = JCSystem.makeTransientShortArray(maxObjects, clearOn);
46 | mLengths = JCSystem.makeTransientShortArray(maxObjects, clearOn);
47 | }
48 |
49 | private void fault() {
50 | ISOException.throwIt(ISO7816.SW_UNKNOWN);
51 | }
52 |
53 | public byte[] getBuffer() {
54 | return mBuffer;
55 | }
56 |
57 | public short allocate(short length) {
58 | short newUsage = (short)(mUsage + length);
59 | if(mUsage >= mMaxBytes) {
60 | fault();
61 | }
62 | if(mCurrent >= mMaxObjects) {
63 | fault();
64 | }
65 | if(newUsage > mMaxBytes) {
66 | fault();
67 | }
68 | short result = mUsage;
69 | mOffsets[mCurrent] = mUsage;
70 | mLengths[mCurrent] = length;
71 | mUsage = newUsage;
72 | mCurrent++;
73 | return result;
74 | }
75 |
76 | public void free(short offset, short length) {
77 | if(mCurrent <= 0) {
78 | fault();
79 | }
80 | if(mOffsets[mCurrent] != offset) {
81 | fault();
82 | }
83 | if(mLengths[mCurrent] != length) {
84 | fault();
85 | }
86 | Util.arrayFillNonAtomic(mBuffer, offset, length, (byte)0);
87 | mOffsets[mCurrent] = 0;
88 | mLengths[mCurrent] = 0;
89 | mUsage -= length;
90 | mCurrent--;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/install.script:
--------------------------------------------------------------------------------
1 | # print card information
2 | gp-info
3 |
4 | # load everything in one go
5 | gp-load --reload \
6 | build/javacard/openjavacard-lib-ber.cap \
7 | build/javacard/openjavacard-lib-string.cap \
8 | build/javacard/openjavacard-lib-fortuna.cap \
9 | build/javacard/openjavacard-lib-password.cap \
10 | build/javacard/openjavacard-lib-debug.cap \
11 | build/javacard/openjavacard-lib-ctlv.cap \
12 | build/javacard/openjavacard-app-demo.cap
13 |
14 | # install demo applet
15 | gp-install --reinstall --package D276000177100210010001 --module D27600017710021001000101 --aid D27600017710011001
16 |
17 | # list result
18 | gp-list
19 |
--------------------------------------------------------------------------------
/library-auth/src/main/java/org/openjavacard/lib/auth/AuthContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.auth;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 |
25 | public class AuthContext {
26 |
27 | private final static byte MAX_METHODS = 16;
28 |
29 | private final AuthMethod[] mMethods;
30 |
31 | public AuthContext() {
32 | mMethods = new AuthMethod[MAX_METHODS];
33 | }
34 |
35 | public byte addMethod(AuthMethod method) {
36 | return (byte)0;
37 | }
38 |
39 | public void require(short mask) {
40 | boolean success = true;
41 | for(byte i = 0; i < MAX_METHODS; i++) {
42 | short flag = (short)(1 << i);
43 | boolean required = ((short)(flag & mask)) != 0;
44 | AuthMethod method = mMethods[i];
45 | boolean okay = method.verify();
46 | success &= okay || !required;
47 | }
48 | if(!success) {
49 | ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
50 | }
51 | }
52 |
53 | public void requireAndDerive(short mask,
54 | byte[] saltBuf, short saltOff, short saltLen,
55 | byte[] dkeyBuf, short dkeyOff, short dkeyLen) {
56 | require(mask);
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/library-auth/src/main/java/org/openjavacard/lib/auth/AuthMethod.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.auth;
21 |
22 | public abstract class AuthMethod {
23 |
24 | public abstract boolean verify();
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/library-auth/src/main/java/org/openjavacard/lib/auth/AuthMethodCaller.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.auth;
21 |
22 | import javacard.framework.AID;
23 | import javacard.framework.JCSystem;
24 | import javacard.framework.Util;
25 |
26 | public class AuthMethodCaller extends AuthMethod {
27 |
28 | private final byte[] mAID;
29 |
30 | public AuthMethodCaller(byte[] buf, short off, byte len) {
31 | mAID = new byte[len];
32 | Util.arrayCopyNonAtomic(buf, off, mAID, (short)0, len);
33 | }
34 |
35 | public boolean verify() {
36 | AID client = JCSystem.getPreviousContextAID();
37 | return client.partialEquals(mAID, (short)0, (byte)mAID.length);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/library-auth/src/main/java/org/openjavacard/lib/auth/AuthMethodMedium.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.auth;
21 |
22 | import javacard.framework.APDU;
23 |
24 | public class AuthMethodMedium extends AuthMethod {
25 |
26 | public static AuthMethodMedium getContactInstance() {
27 | return new AuthMethodMedium(APDU.PROTOCOL_MEDIA_DEFAULT);
28 | }
29 |
30 | public static AuthMethodMedium getContactlessInstance() {
31 | return new AuthMethodMedium(APDU.PROTOCOL_MEDIA_CONTACTLESS_TYPE_A, APDU.PROTOCOL_MEDIA_CONTACTLESS_TYPE_B);
32 | }
33 |
34 | private final byte[] mAllowedMedia;
35 |
36 | public AuthMethodMedium(byte allowedMedium) {
37 | mAllowedMedia = new byte[] {allowedMedium};
38 | }
39 |
40 | public AuthMethodMedium(byte allowedMediumA, byte allowedMediumB) {
41 | mAllowedMedia = new byte[] {allowedMediumA, allowedMediumB};
42 | }
43 |
44 | public boolean verify() {
45 | boolean result = false;
46 | byte medium = (byte)(APDU.getProtocol() & APDU.PROTOCOL_MEDIA_MASK);
47 | for(short idx = 0; idx < mAllowedMedia.length; idx++) {
48 | if(medium == mAllowedMedia[idx]) {
49 | result |= true;
50 | }
51 | }
52 | return result;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/library-auth/src/main/java/org/openjavacard/lib/auth/AuthProtocol.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.auth;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 |
25 | public abstract class AuthProtocol extends AuthMethod {
26 |
27 | public static final byte DEFAULT_MAX_TRIES = 3;
28 |
29 | private final byte mMaxTries;
30 |
31 | private byte mBadTries;
32 |
33 | protected AuthProtocol(byte maxTries) {
34 | mMaxTries = maxTries;
35 | mBadTries = 0;
36 | }
37 |
38 | protected AuthProtocol() {
39 | this(DEFAULT_MAX_TRIES);
40 | }
41 |
42 | public boolean verify() {
43 | return false;
44 | }
45 |
46 | protected void beginAttempt() {
47 | if(mBadTries >= mMaxTries) {
48 | ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
49 | }
50 | mBadTries++;
51 | }
52 |
53 | protected void continueAttempt() {
54 | }
55 |
56 | protected void attemptFailure() {
57 | ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
58 | }
59 |
60 | protected void attemptSuccess() {
61 | mBadTries = 0;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/library-auth/src/main/java/org/openjavacard/lib/auth/AuthProtocolSecret.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.auth;
21 |
22 | import javacard.framework.JCSystem;
23 | import javacard.framework.Util;
24 | import javacard.security.AESKey;
25 | import javacard.security.KeyBuilder;
26 | import javacard.security.MessageDigest;
27 | import javacard.security.RandomData;
28 | import javacardx.crypto.Cipher;
29 |
30 | public class AuthProtocolSecret extends AuthProtocol {
31 |
32 | private static final short short0 = (short)0;
33 |
34 | private final RandomData mRandom;
35 | private final MessageDigest mHash;
36 | private final Cipher mCipher;
37 | private final AESKey mKey;
38 | private final short mLength;
39 |
40 | private final byte[] mCheckSalt;
41 | private final byte[] mCheckHash;
42 | private final byte[] mCheckTemp;
43 |
44 | private final byte[] mCryptSalt;
45 | private final byte[] mCryptHash;
46 |
47 | private final byte[] mKeyEncrypted;
48 | private final byte[] mKeyPlain;
49 |
50 | public AuthProtocolSecret(RandomData random) {
51 | mRandom = random;
52 | mHash = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
53 | mCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
54 | mKey = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, (short)256, false);
55 | byte hashLen = mHash.getLength();
56 | mLength = hashLen;
57 | mCheckSalt = new byte[hashLen];
58 | mCheckHash = new byte[hashLen];
59 | mCheckTemp = JCSystem.makeTransientByteArray(hashLen, JCSystem.CLEAR_ON_DESELECT);
60 | mCryptSalt = new byte[hashLen];
61 | mCryptHash = JCSystem.makeTransientByteArray(hashLen, JCSystem.CLEAR_ON_DESELECT);
62 | mKeyEncrypted = new byte[hashLen];
63 | mKeyPlain = JCSystem.makeTransientByteArray(hashLen, JCSystem.CLEAR_ON_DESELECT);
64 | }
65 |
66 | public void check(byte[] buf, short off, short len) {
67 | beginAttempt();
68 | // compute the possible check hash into the temp buffer
69 | mHash.reset();
70 | mHash.update(mCheckSalt, short0, mLength);
71 | mHash.doFinal(buf, off, len, mCheckTemp, short0);
72 | // check the hash
73 | if(Util.arrayCompare(mCheckTemp, short0, mCheckHash, short0, mLength) == 0) {
74 | attemptSuccess();
75 | } else {
76 | attemptFailure();
77 | }
78 | // now compute the encryption key
79 | mHash.reset();
80 | mHash.update(mCryptSalt, short0, mLength);
81 | mHash.doFinal(buf, off, len, mCryptHash, short0);
82 | mKey.setKey(mCryptHash, short0);
83 | // and decrypt the secret
84 | mCipher.init(mKey, Cipher.MODE_DECRYPT);
85 | mCipher.doFinal(mKeyEncrypted, short0, mLength, mKeyPlain, short0);
86 | }
87 |
88 | public void update(byte[] buf, short off, short len) {
89 | // generate new salts
90 | mRandom.generateData(mCheckSalt, short0, mLength);
91 | mRandom.generateData(mCryptSalt, short0, mLength);
92 | // compute the new check hash
93 | mHash.reset();
94 | mHash.update(mCheckSalt, short0, mLength);
95 | mHash.doFinal(buf, off, len, mCheckHash, short0);
96 | // compute the new crypt hash
97 | mHash.reset();
98 | mHash.update(mCryptSalt, short0, mLength);
99 | mHash.doFinal(buf, off, len, mCryptHash, short0);
100 | // encrypt the existing secret with the new key
101 | mKey.setKey(mCryptHash, short0);
102 | mCipher.init(mKey, Cipher.MODE_ENCRYPT);
103 | mCipher.doFinal(mKeyPlain, short0, mLength, mKeyEncrypted, short0);
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/library-ber/src/main/java/org/openjavacard/lib/ber/BERHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.ber;
21 |
22 | /**
23 | * Interface for BER-TLV processing handlers
24 | */
25 | public interface BERHandler {
26 |
27 | /**
28 | * Handle a primitive object
29 | * @param source feeding the tag
30 | * @param depth of occurrence
31 | * @param tag of object
32 | * @param dataBuf containing value
33 | * @param dataOff of value in dataBuf
34 | * @param dataLen of value in dataBuf
35 | * @return true if accepted
36 | */
37 | boolean handlePrimitive(BERSource source, byte depth, short tag,
38 | byte[] dataBuf, short dataOff, short dataLen);
39 |
40 | /**
41 | * Handle start of a constructed object
42 | * @param source feeding the tag
43 | * @param depth of occurrence
44 | * @param tag of object
45 | * @return true if accepted
46 | */
47 | boolean handleBeginConstructed(BERSource source, byte depth, short tag);
48 |
49 | /**
50 | * Handle end of a constructed object
51 | * @param source feeding the tag
52 | * @param depth of occurrence
53 | * @param tag of object
54 | * @return true if accepted
55 | */
56 | boolean handleFinishConstructed(BERSource source, byte depth, short tag);
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/library-ber/src/main/java/org/openjavacard/lib/ber/BERLength.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.ber;
21 |
22 | import javacard.framework.Util;
23 |
24 | /**
25 | * Constants and functions related to BER length values
26 | */
27 | public final class BERLength {
28 |
29 | /* Length byte flag that indicates a long length */
30 | private static final byte LENGTH_LONG_FLAG = (byte)0x80;
31 | /* Length byte mask for long-case length */
32 | private static final byte LENGTH_SIZE_MASK = (byte)0x7F;
33 |
34 | /** @return true if the given first byte indicates short form */
35 | public static boolean isShortForm(byte firstByte) {
36 | return (firstByte & LENGTH_LONG_FLAG) == 0;
37 | }
38 |
39 | /** @return true if the given first byte indicates long form */
40 | public static boolean isLongForm(byte firstByte) {
41 | return (firstByte & LENGTH_LONG_FLAG) != 0;
42 | }
43 |
44 | /** @return length represented by the given short-form first byte */
45 | public static byte shortFormLength(byte firstByte) {
46 | return (byte)(firstByte & LENGTH_SIZE_MASK);
47 | }
48 |
49 | /** @return length of long-form length indicated by given first byte */
50 | public static byte longFormBytes(byte firstByte) {
51 | return (byte)(firstByte & LENGTH_SIZE_MASK);
52 | }
53 |
54 | /** @return number of bytes required to represent given length */
55 | public static byte lengthSize(short length) {
56 | if(length <= 127) {
57 | return 1;
58 | } else {
59 | return 3;
60 | }
61 | }
62 |
63 | /** Put a length into the given buffer */
64 | public static short putLength(byte[] buf, short off, short length) {
65 | if(length <= 127) {
66 | buf[off++] = (byte)length;
67 | } else {
68 | buf[off++] = (byte)0x82;
69 | off = Util.setShort(buf, off, length);
70 | }
71 | return off;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/library-ber/src/main/java/org/openjavacard/lib/ber/BERReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.ber;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 | import javacard.framework.JCSystem;
25 |
26 | /**
27 | * Reader for BER-TLV data
28 | *
29 | * This is an intricately designed BER parser for JavaCard that
30 | * supports full non-strict parsing of some variant of BER.
31 | *
32 | * The interface is based on a callback interface, allowing a
33 | * client of this utility to parse a complete recursive TLV
34 | * structure without any memory allocation.
35 | *
36 | * It is strongly recommended to keep instances of this class
37 | * permanently available by using a global reference. Doing so
38 | * prevents memory allocation, which should improve card life
39 | * and be safer from a security standpoint.
40 | *
41 | * All buffer handling is performed via a stack-based reference to
42 | * the buffer. This allows parsing directly from the APDU buffer,
43 | * which can not be referenced even from transient arrays.
44 | *
45 | * All internal state is kept in transient variables to prevent state
46 | * leaks and to harden this code against memory-based DoS.
47 | *
48 | */
49 | public final class BERReader implements BERSource {
50 |
51 | /* Fixed: maximum depth allowed */
52 | private final byte mMaxDepth;
53 |
54 | /* Transient: parser variables */
55 | private final short[] mVars;
56 | /* Number of transient variables */
57 | private static final byte NUM_VAR = 4;
58 | /* Variable: initial offset into buffer */
59 | private static final byte VAR_BUF_OFF = 0;
60 | /* Variable: initial length of buffer */
61 | private static final byte VAR_BUF_LEN = 1;
62 | /* Variable: current parsing position */
63 | private static final byte VAR_POSN = 2;
64 | /* Variable: current recursion depth */
65 | private static final byte VAR_DEPTH = 3;
66 |
67 | /* Transient: parser tag stack */
68 | private final short[] mTagStk;
69 | /* Transient: parser return stack */
70 | private final short[] mOffStk;
71 |
72 | /**
73 | * Construct transient-state BER reader
74 | * @param maxDepth maximum depth of TLV structures
75 | */
76 | public BERReader(byte maxDepth, byte clearOn) {
77 | mMaxDepth = maxDepth;
78 | mVars = JCSystem.makeTransientShortArray(NUM_VAR, clearOn);
79 | mTagStk = JCSystem.makeTransientShortArray(maxDepth, clearOn);
80 | mOffStk = JCSystem.makeTransientShortArray(maxDepth, clearOn);
81 | }
82 |
83 | /**
84 | * Parse a block of BER data
85 | * @param buf to parse from
86 | * @param off to start at
87 | * @param len of data
88 | * @param handler to call with results
89 | */
90 | public final void parse(byte[] buf, short off, short len, BERHandler handler) {
91 | // initialize state
92 | mVars[VAR_BUF_OFF] = off;
93 | mVars[VAR_BUF_LEN] = len;
94 | mVars[VAR_POSN] = 0;
95 | mVars[VAR_DEPTH] = 0;
96 | // parse nodes while input lasts
97 | parseMultiple(buf, handler, len);
98 | }
99 |
100 | /**
101 | * Internal: recursively parse multiple BER objects
102 | * @param buf we are reading from
103 | * @param handler to call for every element
104 | * @param end position to parse to
105 | */
106 | private void parseMultiple(byte[] buf, BERHandler handler, short end) {
107 | /* parse children */
108 | while(mVars[VAR_POSN] < end) {
109 | parseOne(buf, handler);
110 | if(mVars[VAR_POSN] > end) {
111 | parseError();
112 | }
113 | }
114 | /* check final position */
115 | if(mVars[VAR_POSN] != end) {
116 | parseError();
117 | }
118 | }
119 |
120 | /**
121 | * Internal: recursively parse one BER object
122 | * @param buf we are reading from
123 | * @param handler to call for every element
124 | */
125 | private void parseOne(byte[] buf, BERHandler handler) {
126 | /* read the tag */
127 | short t = readTag(buf);
128 | /* read the length */
129 | short l = readLength(buf);
130 | /* compute the end offset for this tag */
131 | short e = (short)(mVars[VAR_POSN] + l);
132 |
133 | /* check that we have enough data */
134 | checkLength(l);
135 |
136 | /* push state */
137 | mTagStk[mVars[VAR_DEPTH]] = t;
138 | mOffStk[mVars[VAR_DEPTH]] = (short)(mVars[VAR_POSN] + l);
139 |
140 | /* perform processing */
141 | if(BERTag.isPrimitive(t)) {
142 | /* call handler */
143 | if(!handler.handlePrimitive(this, (byte)mVars[VAR_DEPTH], t,
144 | buf, mVars[VAR_POSN], l)) {
145 | parseError();
146 | }
147 | } else {
148 | /* call begin handler */
149 | if(!handler.handleBeginConstructed(this, (byte)mVars[VAR_DEPTH], t)) {
150 | parseError();
151 | }
152 |
153 | /* now at next level of depth */
154 | mVars[VAR_DEPTH]++;
155 |
156 | /* check for maximum depth */
157 | if(mVars[VAR_DEPTH] == mMaxDepth) {
158 | parseError();
159 | }
160 |
161 | /* parse children */
162 | parseMultiple(buf, handler, e);
163 |
164 | /* done with this level of depth */
165 | mVars[VAR_DEPTH]--;
166 |
167 | /* call finish handler */
168 | if(!handler.handleFinishConstructed(this, (byte)mVars[VAR_DEPTH], t)) {
169 | parseError();
170 | }
171 | }
172 |
173 | /* pop state */
174 | mOffStk[mVars[VAR_DEPTH]] = 0;
175 | mTagStk[mVars[VAR_DEPTH]] = 0;
176 |
177 | /* advance position to after this tag */
178 | mVars[VAR_POSN] = e;
179 | }
180 |
181 | /**
182 | * Internal: throw a parse error
183 | *
184 | * We always throw SW=[data invalid].
185 | */
186 | private void parseError() {
187 | ISOException.throwIt(ISO7816.SW_DATA_INVALID);
188 | }
189 |
190 | /**
191 | * Internal: check number of available bytes
192 | * @param length required in bytes
193 | */
194 | private void checkLength(short length) {
195 | short newCur = (short)(mVars[VAR_POSN] + length);
196 | if(newCur < 0 || newCur > mVars[VAR_BUF_LEN]) {
197 | parseError();
198 | }
199 | }
200 |
201 | /**
202 | * Internal: read one byte at the current position
203 | * @param buf that we are reading from
204 | * @return the byte
205 | */
206 | private byte readByte(byte[] buf) {
207 | short newCur = (short)(mVars[VAR_POSN] + 1);
208 | if(newCur < 0 || newCur > mVars[VAR_BUF_LEN]) {
209 | parseError();
210 | }
211 | byte result = buf[(short)(mVars[VAR_BUF_OFF] + mVars[VAR_POSN])];
212 | mVars[VAR_POSN] = newCur;
213 | return result;
214 | }
215 |
216 | /**
217 | * Internal: read TLV tag at current position
218 | * @param buf that we are reading from
219 | * @return the tag
220 | */
221 | private short readTag(byte[] buf) {
222 | byte b0 = readByte(buf);
223 | byte b1 = 0;
224 | if(BERTag.byteIsLongForm(b0)) {
225 | b1 = readByte(buf);
226 | if(!BERTag.byteIsLast(b1)) {
227 | parseError();
228 | }
229 | }
230 | return (short)((b0 << 8) | b1);
231 | }
232 |
233 | /**
234 | * Internal: read TLV length at current position
235 | * @param buf that we are reading from
236 | * @return the length
237 | */
238 | private short readLength(byte[] buf) {
239 | short result = -1;
240 |
241 | // read the first byte
242 | byte b0 = readByte(buf);
243 |
244 | // check for short form
245 | if(BERLength.isShortForm(b0)) {
246 | // process short form
247 | result = BERLength.shortFormLength(b0);
248 | } else {
249 | // process long form
250 | byte bc = BERLength.longFormBytes(b0);
251 | if (bc == 1) {
252 | // read the length and cast it
253 | result = (short) readByte(buf);
254 | } else if (bc == 2) {
255 | // read the length
256 | byte b1 = readByte(buf);
257 | byte b2 = readByte(buf);
258 | // combine and cast
259 | result = (short) ((b1 << 8) | (b2));
260 | } else {
261 | parseError();
262 | }
263 | }
264 |
265 | // check for overflow
266 | if(result < 0) {
267 | parseError();
268 | }
269 |
270 | return result;
271 | }
272 |
273 | }
274 |
--------------------------------------------------------------------------------
/library-ber/src/main/java/org/openjavacard/lib/ber/BERSource.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.ber;
2 |
3 | /**
4 | * Interface for BER-TLV processing handlers
5 | */
6 | public interface BERSource {
7 | }
8 |
--------------------------------------------------------------------------------
/library-ber/src/main/java/org/openjavacard/lib/ber/BERTag.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.ber;
21 |
22 | import javacard.framework.Util;
23 |
24 | /**
25 | * Constants and functions related to BER tag values
26 | */
27 | public final class BERTag {
28 |
29 | public static final short TYPE_MASK = (short)0x1F7F;
30 | public static final short TYPE_MASK_FIRST = (short)0x1F00;
31 |
32 | public static final short TYPE_EOC = (short)0x0000;
33 | public static final short TYPE_BOOLEAN = (short)0x0100;
34 | public static final short TYPE_INTEGER = (short)0x0200;
35 | public static final short TYPE_BITSTRING = (short)0x0300;
36 | public static final short TYPE_OCTETSTRING = (short)0x0400;
37 | public static final short TYPE_NULL = (short)0x0500;
38 | public static final short TYPE_OID = (short)0x0600;
39 | public static final short TYPE_OBJECTDESCRIPTOR = (short)0x0700;
40 | public static final short TYPE_EXTERNAL = (short)0x0800;
41 | public static final short TYPE_REAL = (short)0x0900;
42 | public static final short TYPE_ENUMERATED = (short)0x0A00;
43 | public static final short TYPE_EMBEDDED_PDV = (short)0x0B00;
44 | public static final short TYPE_UTF8STRING = (short)0x0C00;
45 | public static final short TYPE_RELATIVE_OID = (short)0x0D00;
46 | public static final short TYPE_SEQUENCE = (short)0x1000;
47 | public static final short TYPE_SET = (short)0x1100;
48 | public static final short TYPE_NUMERICSTRING = (short)0x1200;
49 | public static final short TYPE_PRINTABLESTRING = (short)0x1300;
50 | public static final short TYPE_T61STRING = (short)0x1400;
51 | public static final short TYPE_VIDEOTEXSTRING = (short)0x1500;
52 | public static final short TYPE_IA5STRING = (short)0x1600;
53 | public static final short TYPE_UTCTIME = (short)0x1700;
54 | public static final short TYPE_GENERALIZEDTIME = (short)0x1800;
55 | public static final short TYPE_GRAPHICSTRING = (short)0x1900;
56 | public static final short TYPE_VISIBLESTRING = (short)0x1A00;
57 | public static final short TYPE_GENERALSTRING = (short)0x1B00;
58 | public static final short TYPE_UNIVERSALSTRING = (short)0x1C00;
59 | public static final short TYPE_CHARACTERSTRING = (short)0x1D00;
60 | public static final short TYPE_BMPSTRING = (short)0x1E00;
61 | public static final short TYPE_LONG = (short)0x1F00;
62 |
63 | public static final short CLASS_MASK = (short)0xC000;
64 | public static final short CLASS_UNIVERSAL = (short)0x0000;
65 | public static final short CLASS_APPLICATION = (short)0x4000;
66 | public static final short CLASS_CONTEXT = (short)0x8000;
67 | public static final short CLASS_PRIVATE = (short)0xC000;
68 |
69 | public static final short CONSTRUCTED_FLAG = (short)0x2000;
70 |
71 | private static final byte TAGBYTE_FIRST_TYPE_MASK = (byte)0x1F;
72 | private static final byte TAGBYTE_FIRST_TYPE_LONG = (byte)0x1F;
73 | private static final byte TAGBYTE_FLAG_CONTINUES = (byte)0x80;
74 |
75 | /** Internal: return true of the given first byte of a tag indicates long form */
76 | static boolean byteIsLongForm(byte firstByte) {
77 | return (firstByte & TAGBYTE_FIRST_TYPE_MASK)
78 | == TAGBYTE_FIRST_TYPE_LONG;
79 | }
80 |
81 | /** Internal: return true of the given tag byte is the last byte of the tag */
82 | static boolean byteIsLast(byte tagByte) {
83 | return (tagByte & TAGBYTE_FLAG_CONTINUES) == 0;
84 | }
85 |
86 | /** True of the tag is of the universal class */
87 | public static boolean isUniversal(short tag) {
88 | return tagClass(tag) == CLASS_UNIVERSAL;
89 | }
90 |
91 | /** True of the tag is of the application-specific class */
92 | public static boolean isApplication(short tag) {
93 | return tagClass(tag) == CLASS_APPLICATION;
94 | }
95 |
96 | /** True of the tag is of the context-specific class */
97 | public static boolean isContext(short tag) {
98 | return tagClass(tag) == CLASS_CONTEXT;
99 | }
100 |
101 | /** True of the tag is of the private class */
102 | public static boolean isPrivate(short tag) {
103 | return tagClass(tag) == CLASS_PRIVATE;
104 | }
105 |
106 | /** True of the tag is primitive */
107 | public static boolean isPrimitive(short tag) {
108 | return (tag & CONSTRUCTED_FLAG) == 0;
109 | }
110 |
111 | /** True of the tag is constructed */
112 | public static boolean isConstructed(short tag) {
113 | return (tag & CONSTRUCTED_FLAG) != 0;
114 | }
115 |
116 | /** Returns the class of the tag */
117 | public static short tagClass(short tag) {
118 | return (short)(tag & CLASS_MASK);
119 | }
120 |
121 | /** Returns the type of the tag */
122 | public static short tagType(short tag) {
123 | return (short)(tag & TYPE_MASK);
124 | }
125 |
126 | /** Returns true if the tag requires two bytes */
127 | public static boolean tagIsLong(short tag) {
128 | return (tag & TYPE_MASK_FIRST) == TYPE_LONG;
129 | }
130 |
131 | /** Coerce a tag to be constructed */
132 | public static short tagAsConstructed(short tag) {
133 | return (short)(tag & CONSTRUCTED_FLAG);
134 | }
135 |
136 | /** Coerce a tag to be of the given class */
137 | public static short tagAsClass(short tag, short cls) {
138 | return (short)((tag & ~CLASS_MASK) | (cls & CLASS_MASK));
139 | }
140 |
141 | /** Get the encoded size of a tag */
142 | public static short tagSize(short tag) {
143 | if(tagIsLong(tag)) {
144 | return 2;
145 | } else {
146 | return 1;
147 | }
148 | }
149 |
150 | /** Put a tag into the given buffer */
151 | public static short putTag(byte[] buf, short off, short tag) {
152 | if(tagIsLong(tag)) {
153 | off = Util.setShort(buf, off, tag);
154 | } else {
155 | buf[off++] = (byte) ((tag >> 8) & 0xFF);
156 | }
157 | return off;
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/library-ber/src/test/java/org/openjavacard/lib/ber/BERReaderTest.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.ber;
2 |
3 | import javacard.framework.JCSystem;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 |
7 | public class BERReaderTest {
8 |
9 | byte[] tmp;
10 |
11 | BERReader mReader;
12 |
13 | @Before
14 | public void prepare() {
15 | tmp = new byte[128];
16 | mReader = new BERReader((byte)32, JCSystem.CLEAR_ON_DESELECT);
17 | }
18 |
19 | @Test
20 | public void testEmpty() {
21 | mReader.parse(tmp, (short) 0, (short) 0, new BERHandler() {
22 | public boolean handlePrimitive(BERSource source, byte depth, short tag, byte[] dataBuf, short dataOff, short dataLen) {
23 | return false;
24 | }
25 | public boolean handleBeginConstructed(BERSource source, byte depth, short tag) {
26 | return false;
27 | }
28 | public boolean handleFinishConstructed(BERSource source, byte depth, short tag) {
29 | return false;
30 | }
31 | });
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/library-ber/src/test/java/org/openjavacard/lib/ber/BERWriterTest.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.ber;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 |
7 | import java.util.Arrays;
8 |
9 | public class BERWriterTest {
10 |
11 | byte[] zeroes;
12 | byte[] ones;
13 | byte[] count;
14 | byte[] tmp;
15 |
16 | BERWriter mWriter;
17 |
18 | @Before
19 | public void prepare() {
20 | zeroes = new byte[128];
21 | ones = new byte[128];
22 | count = new byte[128];
23 | Arrays.fill(ones, (byte)1);
24 | for(int i = 0; i < count.length; i++) {
25 | count[i] = (byte)i;
26 | }
27 |
28 | tmp = new byte[128];
29 | mWriter = new BERWriter((byte)32, (byte)32, (short)128);
30 | }
31 |
32 | @Test
33 | public void testEmpty() {
34 | mWriter.begin((short)128);
35 | short len = mWriter.finish(tmp, (short)0, (short)tmp.length);
36 | Assert.assertTrue(len == 0);
37 | }
38 |
39 | @Test
40 | public void testBufferedToplevel() {
41 | mWriter.begin((short)128);
42 | mWriter.primitiveByte(BERTag.TYPE_OCTETSTRING, (byte)12);
43 | mWriter.primitiveShort(BERTag.TYPE_OCTETSTRING, (short)1234);
44 | mWriter.primitiveBuffered(BERTag.TYPE_OCTETSTRING, ones, (short)0, (short)3);
45 | short len = mWriter.finish(tmp, (short)0, (short)tmp.length);
46 | Assert.assertTrue(len == 12);
47 | }
48 |
49 | @Test
50 | public void testBufferedNested() {
51 | mWriter.begin((short)128);
52 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
53 | mWriter.primitiveByte(BERTag.TYPE_OCTETSTRING, (byte)12);
54 | mWriter.primitiveShort(BERTag.TYPE_OCTETSTRING, (short)1234);
55 | mWriter.primitiveBuffered(BERTag.TYPE_OCTETSTRING, ones, (short)0, (short)3);
56 | mWriter.endConstructed();
57 | short len = mWriter.finish(tmp, (short)0, (short)tmp.length);
58 | Assert.assertTrue(len == 14);
59 | }
60 |
61 | @Test
62 | public void testBufferedComplex() {
63 | mWriter.begin((short)128);
64 |
65 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
66 |
67 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
68 | mWriter.primitiveByte(BERTag.TYPE_OCTETSTRING, (byte)12);
69 | mWriter.primitiveShort(BERTag.TYPE_OCTETSTRING, (short)1234);
70 | mWriter.primitiveBuffered(BERTag.TYPE_OCTETSTRING, ones, (short)0, (short)3);
71 | mWriter.endConstructed();
72 |
73 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
74 | mWriter.primitiveByte(BERTag.TYPE_OCTETSTRING, (byte)12);
75 | mWriter.primitiveShort(BERTag.TYPE_OCTETSTRING, (short)1234);
76 | mWriter.primitiveBuffered(BERTag.TYPE_OCTETSTRING, ones, (short)0, (short)3);
77 | mWriter.endConstructed();
78 |
79 | mWriter.endConstructed();
80 |
81 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
82 |
83 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
84 | mWriter.primitiveByte(BERTag.TYPE_OCTETSTRING, (byte)12);
85 | mWriter.primitiveShort(BERTag.TYPE_OCTETSTRING, (short)1234);
86 | mWriter.primitiveBuffered(BERTag.TYPE_OCTETSTRING, ones, (short)0, (short)3);
87 | mWriter.endConstructed();
88 |
89 | mWriter.beginConstructed(BERTag.TYPE_SEQUENCE);
90 | mWriter.primitiveByte(BERTag.TYPE_OCTETSTRING, (byte)12);
91 | mWriter.primitiveShort(BERTag.TYPE_OCTETSTRING, (short)1234);
92 | mWriter.primitiveBuffered(BERTag.TYPE_OCTETSTRING, ones, (short)0, (short)3);
93 | mWriter.endConstructed();
94 |
95 | mWriter.endConstructed();
96 |
97 | short len = mWriter.finish(tmp, (short)0, (short)tmp.length);
98 | Assert.assertTrue(len == 60);
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/library-codec/src/main/java/org/openjavacard/lib/codec/Base64Codec.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.codec;
2 |
3 | public class Base64Codec {
4 | }
5 |
--------------------------------------------------------------------------------
/library-codec/src/main/java/org/openjavacard/lib/codec/Decoder.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.codec;
2 |
3 | public interface Decoder {
4 |
5 | short decode(byte[] inBuf, short inOff, short inLen,
6 | byte[] outBuf, short outOff, short outMaxLen);
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/library-codec/src/main/java/org/openjavacard/lib/codec/Encoder.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.codec;
2 |
3 | public interface Encoder {
4 |
5 | short encode(byte[] inBuf, short inOff, short inLen,
6 | byte[] outBuf, short outOff, short outMaxLen);
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/library-codec/src/main/java/org/openjavacard/lib/codec/HexCodec.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.codec;
2 |
3 | import javacard.framework.ISO7816;
4 | import javacard.framework.ISOException;
5 |
6 | public class HexCodec {
7 |
8 | private static final byte NIBBLE = 0xF;
9 |
10 | private final byte[] mEncode;
11 |
12 | public HexCodec() {
13 | mEncode = new byte[] { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
14 | 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
15 | }
16 |
17 | public short encode(byte[] inBuf, short inOff, short inLen,
18 | byte[] outBuf, short outOff, short outMaxLen) {
19 | short outReq = (short)(inLen * 2);
20 | if(outReq < inLen || outReq < outMaxLen) {
21 | error();
22 | }
23 | short inEnd = (short)(inOff + inLen);
24 | for(; inOff < inEnd; inOff++) {
25 | byte b = inBuf[inOff];
26 | outBuf[outOff] = mEncode[(b >> 4) & NIBBLE];
27 | outBuf[outOff+1] = mEncode[b & NIBBLE];
28 | outOff += 2;
29 | }
30 | return outReq;
31 | }
32 |
33 | public short verify(byte[] inBuf, short inOff, short inLen) {
34 | short end = (short)(inOff + inLen);
35 | for(short i = inOff; i < end; i++) {
36 | }
37 | return 0;
38 | }
39 |
40 | public short decode(byte[] inBuf, short inOff, short inLen,
41 | byte[] outBuf, short outOff, short outMaxLen) {
42 | short outReq = (short)(inLen / 2);
43 | if((inLen % 2) != 0) {
44 | error();
45 | }
46 | if(outReq < inLen || outReq > outMaxLen) {
47 | error();
48 | }
49 | short outEnd = (short)(outOff + outReq);
50 | for(; outOff < outEnd; outOff++) {
51 | byte h = inBuf[inOff];
52 | byte l = inBuf[inOff+1];
53 | outBuf[outOff] = (byte)((xdigit(h) << 4) | xdigit(l));
54 | inOff += 2;
55 | }
56 | return outReq;
57 | }
58 |
59 | public static boolean isxdigit(byte c) {
60 | return ((c >= 0x30) && (c <= 0x39))
61 | || ((c >= 0x41) && (c <= 0x46))
62 | || ((c >= 0x61) && (c <= 0x66));
63 | }
64 |
65 | public static byte xdigit(byte c) {
66 | if((c <= 0x30) && (c <= 0x39)) {
67 | return (byte)(c - 0x30);
68 | } else if ((c >= 0x41) && (c <= 0x46)) {
69 | return (byte)(c + 10 - 0x41);
70 | } else if ((c >= 0x61) && (c <= 0x66)) {
71 | return (byte)(c + 10 - 0x61);
72 | } else {
73 | error();
74 | return -1;
75 | }
76 | }
77 |
78 | private static void error() {
79 | ISOException.throwIt(ISO7816.SW_UNKNOWN);
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/library-ctlv/src/main/java/org/openjavacard/lib/ctlv/ATR.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.ctlv;
2 |
3 | /**
4 | * Definitions for ATR historical bytes
5 | */
6 | public class ATR {
7 |
8 | /** Category indicator: historical bytes coded in non-TLV format */
9 | public static final byte CATEGORY_NON_TLV = (byte)0x00;
10 | /** Category indicator: historical bytes are a DIR data reference */
11 | public static final byte CATEGORY_DIR_DATA_REFERENCE = (byte)0x10;
12 | /** Category indicator: historical bytes coded in COMPACT-TLV */
13 | public static final byte CATEGORY_COMPACT_TLV = (byte)0x80;
14 |
15 | /** Tag for country data */
16 | public static final byte TAG_COUNTRY = (byte)0x10;
17 | /** Tag for issuer identification number (IIN) */
18 | public static final byte TAG_ISSUER = (byte)0x20;
19 | /** Coding for card service data (CSD) */
20 | public static final byte TAG_CARD_SERVICE_DATA = (byte)0x30;
21 | /** Tag for initial access data (IAD) retrieval information */
22 | public static final byte TAG_INITIAL_ACCESS_DATA = (byte)0x40;
23 | /** Tag for card issuer data (proprietary coding) */
24 | public static final byte TAG_CARD_ISSUER_DATA = (byte)0x50;
25 | /** Tag for pre-issuing data (proprietary coding) */
26 | public static final byte TAG_PRE_ISSUING_DATA = (byte)0x60;
27 | /** Tag for card capability bytes (SFT1, optional SFT2 and SFT3) */
28 | public static final byte TAG_CARD_CAPABILITIES = (byte)0x70;
29 | /** Tag for status indicator (LCS, SW or LCS+SW) */
30 | public static final byte TAG_STATUS_INDICATOR = (byte)0x80;
31 |
32 | /* Life cycle status */
33 |
34 | public static final byte LCS_UNKNOWN = (byte)0x00;
35 | public static final byte LCS_CREATION = (byte)0x01;
36 | public static final byte LCS_INITIALIZATION = (byte)0x03;
37 | public static final byte LCS_OPERATIONAL_DEACTIVATED = (byte)0x04;
38 | public static final byte LCS_OPERATIONAL_ACTIVATED = (byte)0x05;
39 | public static final byte LCS_TERMINATED = (byte)0x0C;
40 |
41 | /* Card service data */
42 |
43 | public static final byte CSD_SELECT_BY_DFNAME_FULL = (byte)0x80;
44 | public static final byte CSD_SELECT_BY_DFNAME_PARTIAL = (byte)0x40;
45 | public static final byte CSD_DO_IN_EF_DIR = (byte)0x20;
46 | public static final byte CSD_DO_IN_EF_ATR = (byte)0x10;
47 | public static final byte CSD_READ_MASK = (byte)0x08;
48 | public static final byte CSD_READ_RECORD = (byte)0x00;
49 | public static final byte CSD_READ_BINARY = (byte)0x08;
50 | public static final byte CSD_RESERVED_MASK = (byte)0x07;
51 | public static final byte CSD_RESERVED_OKAY = (byte)0x00;
52 |
53 | /* Card capabilities (Software function table 1) */
54 |
55 | public static final byte SFT1_DF_SELECT_BY_DFNAME_FULL = (byte)0x80;
56 | public static final byte SFT1_DF_SELECT_BY_DFNAME_PARTIAL = (byte)0x40;
57 | public static final byte SFT1_DF_SELECT_BY_PATH = (byte)0x20;
58 | public static final byte SFT1_DF_SELECT_BY_FILEID = (byte)0x10;
59 | public static final byte SFT1_DF_SELECT_IMPLICIT = (byte)0x08;
60 | public static final byte SFT1_EF_SFI_SUPPORTED = (byte)0x04;
61 | public static final byte SFT1_EF_RECORD_NUMBER_SUPPORTED = (byte)0x02;
62 | public static final byte SFT1_EF_RECORD_IDENTIFIER_SUPPORTED = (byte)0x01;
63 |
64 | /* Card capabilities (Software function table 2) */
65 |
66 | public static final byte SFT2_WRITE_MASK = (byte)0x60;
67 | public static final byte SFT2_WRITE_ONCE = (byte)0x00;
68 | public static final byte SFT2_WRITE_PROPRIETARY = (byte)0x20;
69 | public static final byte SFT2_WRITE_OR = (byte)0x40;
70 | public static final byte SFT2_WRITE_AND = (byte)0x60;
71 | public static final byte SFT2_DUSIZE_MASK = (byte)0x07;
72 | public static final byte SFT2_RESERVED_MASK = (byte)0x91;
73 | public static final byte SFT2_RESERVED_OKAY = (byte)0x00;
74 |
75 | /* Card capabilities (Software function table 3) */
76 |
77 | public static final byte SFT3_EXTENDED_APDU = (byte)0x40;
78 | public static final byte SFT3_CHANNELS_MASK = (byte)0x18;
79 | public static final byte SFT3_CHANNELS_UNSUPPORTED = (byte)0x00;
80 | public static final byte SFT3_CHANNELS_ASSIGNED_BY_CARD = (byte)0x08;
81 | public static final byte SFT3_CHANNELS_ASSIGNED_BY_HOST = (byte)0x10;
82 | public static final byte SFT3_CHANNELS_RESERVED = (byte)0x18;
83 | public static final byte SFT3_MAX_CHANNELS_MASK = (byte)0x03;
84 | public static final byte SFT3_RESERVED_MASK = (byte)0xA4;
85 | public static final byte SFT3_RESERVED_OKAY = (byte)0x00;
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/library-ctlv/src/main/java/org/openjavacard/lib/ctlv/CTLV.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.ctlv;
2 |
3 | import javacard.framework.ISO7816;
4 | import javacard.framework.ISOException;
5 | import javacard.framework.Util;
6 |
7 | /**
8 | * Compact-TLV processing functions
9 | *
10 | * Compact-TLV (or CTLV) is a special TLV format defined in ISO7816 for use in ATR historical bytes.
11 | *
12 | * This class provides functions and definitions for processing and producing Compact-TLV data.
13 | *
14 | */
15 | public class CTLV {
16 |
17 | /** Mask for a COMPACT-TLV tag */
18 | public static final byte MASK_TAG = (byte)0xF0;
19 | /** Mask for a COMPACT-TLV length */
20 | public static final byte MASK_LENGTH = (byte)0x0F;
21 | /** Maximum length of a COMPACT-TLV value */
22 | public static final byte MAX_LENGTH = (byte)0x0F;
23 |
24 | /**
25 | * Retrieve a C-TLV tag
26 | * @param inBuf
27 | * @param inOff
28 | * @return
29 | */
30 | public static byte getTag(byte[] inBuf, short inOff) {
31 | return (byte)(inBuf[inOff]& MASK_TAG);
32 | }
33 |
34 | /**
35 | * Retrieve a C-TLV length
36 | * @param inBuf
37 | * @param inOff
38 | * @return
39 | */
40 | public static byte getLength(byte[] inBuf, short inOff) {
41 | return (byte)(inBuf[inOff] & MASK_LENGTH);
42 | }
43 |
44 | /**
45 | * Find offset of a C-TLV tag, if present
46 | *
47 | * @param inBuf containing C-TLV data
48 | * @param inOff offset of data
49 | * @param inLen length of data
50 | * @param tag to search for
51 | * @return offset of tag, -1 if not found
52 | */
53 | public static short find(byte[] inBuf, short inOff, short inLen, byte tag) {
54 | // start at given offset
55 | short off = inOff;
56 | // determine end of data
57 | short end = (short)(inOff + inLen - 1);
58 | // search for the tag
59 | while(off < end) {
60 | // get fields of current tag
61 | byte t = getTag(inBuf, off);
62 | byte l = getLength(inBuf, off);
63 | // is this the requested tag?
64 | if(t == tag) {
65 | // return offset of TL byte
66 | return off;
67 | }
68 | // skip TL byte and data
69 | off += 1 + l;
70 | }
71 | // tag not found
72 | return -1;
73 | }
74 |
75 | /**
76 | * Put a C-TLV object containing one byte
77 | *
78 | * @param outBuf output buffer
79 | * @param outOff offset in buffer
80 | * @param outLen maximum length
81 | * @param tag to put
82 | * @param value for tag
83 | * @return length of output
84 | */
85 | public static short putByte(byte[] outBuf, short outOff, short outLen,
86 | byte tag, byte value) {
87 | short off = outOff;
88 | byte t = (byte)(tag & MASK_TAG);
89 | byte l = 1;
90 | // check parameters
91 | if(t != tag) {
92 | error();
93 | }
94 | // check space
95 | if(outLen < 2) {
96 | error();
97 | }
98 | // put TL byte
99 | outBuf[off++] = (byte)(t | l);
100 | // put data
101 | outBuf[off++] = value;
102 | // return new offset
103 | return (short)(off - outOff);
104 | }
105 |
106 | /**
107 | * Put a C-TLV object containing one short
108 | *
109 | * @param outBuf output buffer
110 | * @param outOff offset in buffer
111 | * @param outLen maximum length
112 | * @param tag to put
113 | * @param value for tag
114 | * @return length of output
115 | */
116 | public static short putShort(byte[] outBuf, short outOff, short outLen,
117 | byte tag, short value) {
118 | short off = outOff;
119 | byte t = (byte)(tag & MASK_TAG);
120 | byte l = 2;
121 | // check parameters
122 | if(t != tag) {
123 | error();
124 | }
125 | // check space
126 | if(outLen < 3) {
127 | error();
128 | }
129 | // put TL byte
130 | outBuf[off++] = (byte)(t | l);
131 | // put data
132 | off = Util.setShort(outBuf, off, value);
133 | // return new offset
134 | return (short)(off - outOff);
135 | }
136 |
137 | /**
138 | * Put a C-TLV object containing several bytes
139 | *
140 | * @param outBuf output buffer
141 | * @param outOff offset in buffer
142 | * @param outLen maximum length
143 | * @param tag to put
144 | * @param valueBuf buffer containing value
145 | * @param valueOff offset of value
146 | * @param valueLen length of value
147 | * @return length of output
148 | */
149 | public static short putBytes(byte[] outBuf, short outOff, short outLen,
150 | byte tag, byte[] valueBuf, short valueOff, short valueLen) {
151 | short off = outOff;
152 | byte t = (byte)(tag & MASK_TAG);
153 | byte l = (byte)(valueLen & MASK_LENGTH);
154 | // check parameters
155 | if((t != tag) || (l != valueLen) || (valueLen > MAX_LENGTH)) {
156 | error();
157 | }
158 | // check space
159 | if(outLen < (short)(l+1)) {
160 | error();
161 | }
162 | // put TL byte
163 | outBuf[off++] = (byte)(t | l);
164 | // put data
165 | off = Util.arrayCopyNonAtomic(valueBuf, valueOff, outBuf, off, valueLen);
166 | // return new offset
167 | return (short)(off - outOff);
168 | }
169 |
170 | /**
171 | * Internal: throw exception because of an error
172 | */
173 | private static void error() {
174 | ISOException.throwIt(ISO7816.SW_UNKNOWN);
175 | }
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/library-cvmpin/src/main/java/org/openjavacard/lib/cvmpin/CVMPIN.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.cvmpin;
2 |
3 | import javacard.framework.PIN;
4 | import javacard.framework.Shareable;
5 | import org.globalplatform.CVM;
6 | import org.globalplatform.GPSystem;
7 |
8 | /**
9 | * Wraps a CVM for use as an OwnerPIN
10 | */
11 | public class CVMPIN implements PIN, Shareable {
12 |
13 | /** The CVM that we wrap */
14 | private CVM mCVM;
15 |
16 | /**
17 | * Get a CVMPIN representing a system CVM
18 | *
19 | * @param cvmIdentifier to look for
20 | * @return resulting wrapper
21 | */
22 | public static CVMPIN get(byte cvmIdentifier) {
23 | CVM cvm = GPSystem.getCVM(cvmIdentifier);
24 | return new CVMPIN(cvm);
25 | }
26 |
27 | /**
28 | * Construct a CVM wrapper
29 | *
30 | * @param cvm to wrap
31 | */
32 | public CVMPIN(CVM cvm) {
33 | mCVM = cvm;
34 | }
35 |
36 | /**
37 | * @return number of tries remaining
38 | */
39 | public byte getTriesRemaining() {
40 | return mCVM.getTriesRemaining();
41 | }
42 |
43 | /**
44 | * @return true if validated
45 | */
46 | public boolean isValidated() {
47 | return mCVM.isVerified();
48 | }
49 |
50 | /**
51 | * Check the given PIN against the underlying CVM
52 | *
53 | * @param buf containing PIN
54 | * @param off of PIN
55 | * @param len of PIN
56 | * @return true if PIN is correct
57 | * @throws ArrayIndexOutOfBoundsException on usage error
58 | * @throws NullPointerException on usage error
59 | */
60 | public boolean check(byte[] buf, short off, byte len) throws ArrayIndexOutOfBoundsException, NullPointerException {
61 | short res = mCVM.verify(buf, off, len, CVM.FORMAT_ASCII);
62 | return res == CVM.CVM_SUCCESS;
63 | }
64 |
65 | /**
66 | * Reset and unblock the CVM
67 | */
68 | public void reset() {
69 | mCVM.resetAndUnblockState();
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/library-debug/src/main/java/org/openjavacard/lib/debug/Debug.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.debug;
21 |
22 | import javacard.framework.AID;
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 | public final class Debug implements DebugProtocol {
31 |
32 | public static Debug getInstance(Applet applet) {
33 | return new Debug(applet);
34 | }
35 |
36 | /** Reference to containing applet */
37 | private final Applet mApplet;
38 |
39 | /** Reference to service implementation (null if detached) */
40 | private DebugService mService;
41 |
42 | /** Binary representation of service AID */
43 | private final byte[] mServiceAID;
44 |
45 | /** Internal flags (clear-on-reset) */
46 | private final boolean[] mFlags;
47 | private final static byte FLAG_ACTIVE = 0;
48 | private final static byte NUM_FLAGS = 1;
49 |
50 | /** True if debugging is enabled (persistent) */
51 | private boolean mEnabled;
52 | /** Type of last exception (persistent) */
53 | private short mExceptionType;
54 | /** Code of last exception (persistent */
55 | private short mExceptionCode;
56 |
57 | private Debug(Applet applet) {
58 | // initialize fields
59 | mApplet = applet;
60 | mService = null;
61 | mServiceAID = newServiceAID();
62 | mFlags = JCSystem.makeTransientBooleanArray(NUM_FLAGS, JCSystem.CLEAR_ON_RESET);
63 | // we start disabled
64 | mEnabled = false;
65 | // no exception yet
66 | mExceptionType = 0;
67 | mExceptionCode = 0;
68 | }
69 |
70 | /** @return true if running in debugger */
71 | public boolean isActive() {
72 | return mFlags[FLAG_ACTIVE];
73 | }
74 |
75 | /** @return true if debugging is enabled */
76 | public boolean isEnabled() {
77 | return mEnabled;
78 | }
79 |
80 | /** @return true if the debug service is attached */
81 | public boolean isAttached() {
82 | return mService != null;
83 | }
84 |
85 | /** Enable debugging */
86 | public void enable() {
87 | mEnabled = true;
88 | }
89 |
90 | /** Disable debugging */
91 | public void disable() {
92 | mEnabled = false;
93 | }
94 |
95 | /**
96 | * Return the debug service AID
97 | *
98 | * @return AID as byte array
99 | */
100 | private byte[] newServiceAID() {
101 | // D276000177 - signal interrupt
102 | // 10 - OpenJavaCard
103 | // 011020 - OpenJavaCard Libraries (Debug service)
104 | return new byte[] {
105 | (byte)0xD2, (byte)0x76, (byte)0x00, (byte)0x01, (byte)0x77,
106 | (byte)0x10, (byte)0x01, (byte)0x10, (byte)0x20,
107 | };
108 | }
109 |
110 | /**
111 | * Attach to debug service
112 | */
113 | public void attach() {
114 | AID aid = JCSystem.lookupAID(mServiceAID, (short)0, (byte) mServiceAID.length);
115 | if(aid != null) {
116 | Object obj = JCSystem.getAppletShareableInterfaceObject(aid, SHARE_DEBUG);
117 | if(obj instanceof DebugService) {
118 | mService = (DebugService)obj;
119 | }
120 | }
121 | }
122 |
123 | /**
124 | * Detach from debug service
125 | */
126 | public void detach() {
127 | mService = null;
128 | }
129 |
130 | /**
131 | * Log memory usage in debug log
132 | */
133 | public void logMemory() {
134 | if(isAttached()) {
135 | short persistent = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
136 | short clearReset = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
137 | short clearDesel = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);
138 | mService.logMemory(persistent, clearReset, clearDesel);
139 | }
140 | }
141 |
142 | /**
143 | * Log message in debug log
144 | *
145 | * @param code of message
146 | * @param buf containing additional data
147 | * @param off of data
148 | * @param len of data
149 | */
150 | public void logMessage(short code, byte[] buf, short off, byte len) {
151 | if(isAttached()) {
152 | mService.logMessage(code, buf, off, len);
153 | }
154 | }
155 |
156 | /**
157 | * Log message in debug log
158 | *
159 | * @param code of message
160 | * @param buf containing additional data
161 | */
162 | public void logMessage(short code, byte[] buf) {
163 | logMessage(code, null, (short)0, (byte)buf.length);
164 | }
165 |
166 | /**
167 | * Log message in debug log
168 | *
169 | * @param code of message
170 | */
171 | public void logMessage(short code) {
172 | logMessage(code, null, (short)0, (byte)0);
173 | }
174 |
175 | public boolean process(APDU apdu) {
176 | byte[] buffer = apdu.getBuffer();
177 | byte cla = buffer[ISO7816.OFFSET_CLA];
178 | byte ins = buffer[ISO7816.OFFSET_INS];
179 |
180 | // prevent recursion
181 | if(mFlags[FLAG_ACTIVE]) {
182 | return false;
183 | }
184 |
185 | // handle debugger commands
186 | if(cla == CLA_LIB_DEBUG && ins == INS_LIB_DEBUG) {
187 | processDbgCommand(apdu);
188 | return true;
189 | }
190 |
191 | // bail out if not enabled
192 | if(!mEnabled) {
193 | return false;
194 | }
195 |
196 | // reset exception state
197 | mExceptionType = 0;
198 | mExceptionCode = 0;
199 |
200 | // determine if we are attached
201 | boolean attached = isAttached();
202 |
203 | // log the C-APDU
204 | if(attached) {
205 | mService.logAPDUCommand(APDU.getProtocol(), apdu);
206 | }
207 |
208 | // call user handler with exceptions caught
209 | Throwable caught = null;
210 | try {
211 | mFlags[FLAG_ACTIVE] = true;
212 | mApplet.process(apdu);
213 | } catch (RuntimeException ex) {
214 | caught = ex;
215 | } catch (Exception ex) {
216 | caught = ex;
217 | } catch (Throwable ex) {
218 | caught = ex;
219 | } finally {
220 | mFlags[FLAG_ACTIVE] = false;
221 | }
222 |
223 | // log the R-APDU
224 | if(attached) {
225 | mService.logAPDUResponse(apdu);
226 | }
227 |
228 | // handle exceptions
229 | if(caught != null) {
230 | // remember exception information
231 | mExceptionType = DebugException.exceptionType(caught);
232 | mExceptionCode = DebugException.exceptionCode(caught);
233 | // log the exception
234 | if(attached) {
235 | mService.logException(mExceptionType, mExceptionCode);
236 | }
237 | // rethrow or raise generic exception
238 | if(caught instanceof RuntimeException) {
239 | throw (RuntimeException)caught;
240 | } else {
241 | ISOException.throwIt(ISO7816.SW_UNKNOWN);
242 | }
243 | }
244 |
245 | // we have handled this APDU
246 | return true;
247 | }
248 |
249 | public boolean isDbgCommand(APDU apdu) {
250 | byte[] buffer = apdu.getBuffer();
251 | byte cla = buffer[ISO7816.OFFSET_CLA];
252 | byte ins = buffer[ISO7816.OFFSET_INS];
253 | return cla == CLA_LIB_DEBUG && ins == INS_LIB_DEBUG;
254 | }
255 |
256 | public void processDbgCommand(APDU apdu) {
257 | byte[] buffer = apdu.getBuffer();
258 | byte cmd = buffer[ISO7816.OFFSET_P1];
259 | switch(cmd) {
260 | case CMD_LIB_STATUS:
261 | processDbgStatus(apdu);
262 | break;
263 | case CMD_LIB_ATTACH:
264 | processDbgAttach(apdu);
265 | break;
266 | case CMD_LIB_DETACH:
267 | processDbgDetach(apdu);
268 | break;
269 | case CMD_LIB_ENABLE:
270 | processDbgEnable(apdu);
271 | break;
272 | case CMD_LIB_DISABLE:
273 | processDbgDisable(apdu);
274 | break;
275 | case CMD_LIB_MEM_USAGE:
276 | processMemStatus(apdu);
277 | break;
278 | case CMD_LIB_MEM_COLLECT:
279 | processMemCollect(apdu);
280 | break;
281 | default:
282 | ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
283 | }
284 | }
285 |
286 | private void processDbgStatus(APDU apdu) {
287 | byte[] buffer = apdu.getBuffer();
288 | short val, off = 0;
289 | buffer[off++] = (byte)(isAttached() ? 1 : 0);
290 | buffer[off++] = (byte)(isEnabled() ? 1 : 0);
291 | buffer[off++] = (byte)(isActive() ? 1 : 0);
292 | val = mExceptionType;
293 | off = Util.setShort(buffer, off, val);;
294 | val = mExceptionCode;
295 | off = Util.setShort(buffer, off, val);;
296 | apdu.setOutgoingAndSend((short)0, off);
297 | }
298 |
299 | private void processDbgAttach(APDU apdu) {
300 | attach();
301 | enable();
302 | processDbgStatus(apdu);
303 | }
304 |
305 | private void processDbgDetach(APDU apdu) {
306 | disable();
307 | detach();
308 | processDbgStatus(apdu);
309 | }
310 |
311 | private void processDbgEnable(APDU apdu) {
312 | enable();
313 | processDbgStatus(apdu);
314 | }
315 |
316 | private void processDbgDisable(APDU apdu) {
317 | disable();
318 | processDbgStatus(apdu);
319 | }
320 |
321 | private void processMemStatus(APDU apdu) {
322 | byte[] buffer = apdu.getBuffer();
323 | short v, off = 0;
324 | v = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
325 | Util.setShort(buffer, off, v); off += 2;
326 | v = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);
327 | Util.setShort(buffer, off, v); off += 2;
328 | v = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
329 | Util.setShort(buffer, off, v); off += 2;
330 | v = JCSystem.getUnusedCommitCapacity();
331 | Util.setShort(buffer, off, v); off += 2;
332 | apdu.setOutgoingAndSend((short)0, off);
333 | }
334 |
335 | private void processMemCollect(APDU apdu) {
336 | if(!JCSystem.isObjectDeletionSupported()) {
337 | ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
338 | }
339 | JCSystem.requestObjectDeletion();
340 | processMemStatus(apdu);
341 | }
342 |
343 | }
344 |
--------------------------------------------------------------------------------
/library-debug/src/main/java/org/openjavacard/lib/debug/DebugException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.debug;
21 |
22 | import javacard.framework.APDUException;
23 | import javacard.framework.CardException;
24 | import javacard.framework.CardRuntimeException;
25 | import javacard.framework.ISOException;
26 | import javacard.framework.PINException;
27 | import javacard.framework.SystemException;
28 | import javacard.framework.TransactionException;
29 | import javacard.framework.UserException;
30 | import javacard.security.CryptoException;
31 |
32 | public class DebugException implements DebugProtocol {
33 |
34 | /**
35 | * Decode an exception and determine its type
36 | * @param t to decode
37 | * @return type of the exception
38 | */
39 | public static short exceptionType(Throwable t) {
40 | if(t instanceof UserException) {
41 | return EXC_USER_EXCEPTION;
42 | }
43 | if(t instanceof TransactionException) {
44 | return EXC_TRANSACTION_EXCEPTION;
45 | }
46 | if(t instanceof SystemException) {
47 | return EXC_SYSTEM_EXCEPTION;
48 | }
49 | if(t instanceof PINException) {
50 | return EXC_PIN_EXCEPTION;
51 | }
52 | if(t instanceof ISOException) {
53 | return EXC_ISO_EXCEPTION;
54 | }
55 | if(t instanceof CryptoException) {
56 | return EXC_CRYPTO_EXCEPTION;
57 | }
58 | if(t instanceof APDUException) {
59 | return EXC_APDU_EXCEPTION;
60 | }
61 | if(t instanceof CardRuntimeException) {
62 | return EXC_CARD_RUNTIME_EXCEPTION;
63 | }
64 | if(t instanceof CardException) {
65 | return EXC_CARD_EXCEPTION;
66 | }
67 | if(t instanceof ArrayIndexOutOfBoundsException) {
68 | return EXC_ARRAY_INDEX_OOB_EXCEPTION;
69 | }
70 | if(t instanceof IndexOutOfBoundsException) {
71 | return EXC_INDEX_OOB_EXCEPTION;
72 | }
73 | if(t instanceof SecurityException) {
74 | return EXC_SECURITY_EXCEPTION;
75 | }
76 | if(t instanceof NullPointerException) {
77 | return EXC_NULL_POINTER_EXCEPTION;
78 | }
79 | if(t instanceof NegativeArraySizeException) {
80 | return EXC_NEGATIVE_ARRAY_SIZE_EXCEPTION;
81 | }
82 | if(t instanceof ClassCastException) {
83 | return EXC_CLASS_CAST_EXCEPTION;
84 | }
85 | if(t instanceof ArrayStoreException) {
86 | return EXC_ARRAY_STORE_EXCEPTION;
87 | }
88 | if(t instanceof ArithmeticException) {
89 | return EXC_ARITHMETIC_EXCEPTION;
90 | }
91 | if(t instanceof RuntimeException) {
92 | return EXC_RUNTIME_EXCEPTION;
93 | }
94 | if(t instanceof Exception) {
95 | return EXC_EXCEPTION;
96 | }
97 | return EXC_THROWABLE;
98 | }
99 |
100 | /**
101 | * Determine the reason code for an exception
102 | * @param t to check
103 | * @return the reason code, 0 if undetermined
104 | */
105 | public static short exceptionCode(Throwable t) {
106 | if(t instanceof CardException) {
107 | return ((CardException)t).getReason();
108 | }
109 | if(t instanceof CardRuntimeException) {
110 | return ((CardRuntimeException)t).getReason();
111 | }
112 | return 0;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/library-debug/src/main/java/org/openjavacard/lib/debug/DebugProtocol.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.debug;
21 |
22 | public interface DebugProtocol {
23 |
24 | byte SHARE_DEBUG = (byte)0xF0;
25 |
26 | byte INS_SVC_READ_APPLICATIONS = (byte)0x00;
27 | byte INS_SVC_READ_MESSAGES = (byte)0x02;
28 |
29 | /** CLA of the library stub */
30 | byte CLA_LIB_DEBUG = (byte)0x80;
31 | /** INS of the library stub */
32 | byte INS_LIB_DEBUG = (byte)0xF0;
33 | /** Library command: get library stub status */
34 | byte CMD_LIB_STATUS = (byte)0x00;
35 | /** Library command: attach to service */
36 | byte CMD_LIB_ATTACH = (byte)0x01;
37 | /** Library command: detach from service */
38 | byte CMD_LIB_DETACH = (byte)0x02;
39 | /** Library command: enable debugging */
40 | byte CMD_LIB_ENABLE = (byte)0x03;
41 | /** Library command: disable debugging */
42 | byte CMD_LIB_DISABLE = (byte)0x04;
43 | /** Library command: get memory usage */
44 | byte CMD_LIB_MEM_USAGE = (byte)0x10;
45 | /** Library command: request garbage collection */
46 | byte CMD_LIB_MEM_COLLECT = (byte)0x12;
47 |
48 | short MSG_APDU_COMMAND = (short)0x01;
49 | short MSG_APDU_RESPONSE = (short)0x02;
50 | short MSG_EXCEPTION = (short)0x03;
51 | short MSG_MEMORY = (short)0x04;
52 | short MSG_MESSAGE = (short)0x05;
53 |
54 | // Exceptions in java.lang
55 | short EXC_THROWABLE = (short)0x00;
56 | short EXC_EXCEPTION = (short)0x01;
57 | short EXC_RUNTIME_EXCEPTION = (short)0x02;
58 | short EXC_ARITHMETIC_EXCEPTION = (short)0x03;
59 | short EXC_ARRAY_STORE_EXCEPTION = (short)0x04;
60 | short EXC_CLASS_CAST_EXCEPTION = (short)0x05;
61 | short EXC_NEGATIVE_ARRAY_SIZE_EXCEPTION = (short)0x06;
62 | short EXC_NULL_POINTER_EXCEPTION = (short)0x07;
63 | short EXC_SECURITY_EXCEPTION = (short)0x08;
64 | short EXC_INDEX_OOB_EXCEPTION = (short)0x09;
65 | short EXC_ARRAY_INDEX_OOB_EXCEPTION = (short)0x0A;
66 | // Exceptions in java.io
67 | short EXC_IO_EXCEPTION = (short)0x10;
68 | // Exceptions in java.rmi
69 | short EXC_REMOTE_EXCEPTION = (short)0x20;
70 | // Exceptions in javacard.framework
71 | short EXC_CARD_EXCEPTION = (short)0x30;
72 | short EXC_CARD_RUNTIME_EXCEPTION = (short)0x31;
73 | short EXC_APDU_EXCEPTION = (short)0x32;
74 | short EXC_ISO_EXCEPTION = (short)0x33;
75 | short EXC_PIN_EXCEPTION = (short)0x34;
76 | short EXC_SYSTEM_EXCEPTION = (short)0x35;
77 | short EXC_TRANSACTION_EXCEPTION = (short)0x36;
78 | short EXC_USER_EXCEPTION = (short)0x37;
79 | // Exceptions in javacard.framework.service
80 | short EXC_SERVICE_EXCEPTION = (short)0x40;
81 | // Exceptions in javacard.security
82 | short EXC_CRYPTO_EXCEPTION = (short)0x50;
83 | // Exceptions in javacard.biometry
84 | short EXC_BIO_EXCEPTION = (short)0x60;
85 | // Exceptions in javacard.external
86 | short EXC_EXTERNAL_EXCEPTION = (short)0x70;
87 | // Exceptions in javacardx.framework.string
88 | short EXC_STRING_EXCEPTION = (short)0x80;
89 | // Exceptions in javacardx.framework.tlv
90 | short EXC_TLV_EXCEPTION = (short)0x90;
91 | // Exceptions in javacardx.framework.util
92 | short EXC_UTIL_EXCEPTION = (short)0xA0;
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/library-debug/src/main/java/org/openjavacard/lib/debug/DebugService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.debug;
21 |
22 | import javacard.framework.APDU;
23 | import javacard.framework.Shareable;
24 |
25 | public interface DebugService extends Shareable {
26 |
27 | void logAPDUCommand(byte protocol, APDU apdu);
28 | void logAPDUResponse(APDU apdu);
29 | void logException(short type, short code);
30 | void logMemory(short persistent, short clearReset, short clearDeselect);
31 | void logMessage(short code, byte[] buf, short off, short len);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/library-fortuna/src/main/java/org/openjavacard/lib/fortuna/FortunaRandom.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.fortuna;
21 |
22 | import javacard.framework.JCSystem;
23 | import javacard.framework.Util;
24 | import javacard.security.AESKey;
25 | import javacard.security.CryptoException;
26 | import javacard.security.KeyBuilder;
27 | import javacard.security.MessageDigest;
28 | import javacard.security.RandomData;
29 | import javacardx.crypto.Cipher;
30 |
31 | /**
32 | * Fortuna PRNG
33 | *
34 | * This is a PRNG based on Fortuna by Bruce Schneier.
35 | *
36 | * The output limit per request is significantly more strict
37 | * than Fortuna prescribes, being limited by the short type to 32768.
38 | */
39 | public class FortunaRandom extends RandomData {
40 |
41 | /** Cipher algorithm to be used */
42 | private static final byte CIPHER_ALGO = Cipher.ALG_AES_BLOCK_128_CBC_NOPAD;
43 | /** Hash algorithm to be used */
44 | private static final byte HASH_ALGO = MessageDigest.ALG_SHA_256;
45 | /** Key type to be used */
46 | private static final byte KEY_TYPE = KeyBuilder.TYPE_AES;
47 | /** Key length to be used */
48 | private static final short KEY_LENGTH = KeyBuilder.LENGTH_AES_256;
49 |
50 | /** Size of an internal block of random data */
51 | private static final short BLOCK_SIZE = 16;
52 | /** Size of the internal counter */
53 | private static final short COUNTER_SIZE = 16;
54 | /** Size of the internal temporary buffer */
55 | private static final short TMP_SIZE = 48;
56 |
57 | /** Bootstrap flag */
58 | private boolean mInitialized;
59 |
60 | /** Cipher instance */
61 | private final Cipher mCipher;
62 | /** Hash instance */
63 | private final MessageDigest mHash;
64 |
65 | /** Fortuna counter */
66 | private final LongNum mCounter;
67 | /** Fortuna key */
68 | private final AESKey mKey;
69 |
70 | /** Temp buffer */
71 | private final byte[] mTmp;
72 |
73 | /**
74 | * Construct a persistent Fortuna PRNG
75 | */
76 | public FortunaRandom() {
77 | mInitialized = false;
78 | // get crypto instances
79 | mCipher = Cipher.getInstance(CIPHER_ALGO, false);
80 | mHash = MessageDigest.getInstance(HASH_ALGO, false);
81 | // construct state
82 | mCounter = new LongNum(COUNTER_SIZE);
83 | mKey = (AESKey)KeyBuilder.buildKey(KEY_TYPE, KEY_LENGTH, false);
84 | // allocate temp buffer (caution: used for zeroes)
85 | mTmp = JCSystem.makeTransientByteArray(TMP_SIZE, JCSystem.CLEAR_ON_DESELECT);
86 | // initialize the keys (to zero as per Fortuna)
87 | mKey.setKey(mTmp, (short)0);
88 | }
89 |
90 | /**
91 | * Reset the PRNG
92 | *
93 | * After this the PRNG will be unusable until reseeded.
94 | */
95 | public void reset() {
96 | mInitialized = false;
97 | mCounter.clear();
98 | wipeTmp();
99 | mKey.setKey(mTmp, (short)0);
100 | }
101 |
102 | /**
103 | * Generate random data
104 | *
105 | * PRNG must have been seeded.
106 | *
107 | * @param buf to generate into
108 | * @param off to generate at
109 | * @param len to generate
110 | * @throws CryptoException on error
111 | */
112 | public void generateData(byte[] buf, short off, short len)
113 | throws CryptoException {
114 | // check that we are seeded
115 | if(!mInitialized) {
116 | CryptoException.throwIt(CryptoException.ILLEGAL_USE);
117 | }
118 | // check requested length
119 | if(len <= 0) {
120 | CryptoException.throwIt(CryptoException.ILLEGAL_USE);
121 | }
122 | // handle exceptions so we can force key advance
123 | try {
124 | // determine number of blocks
125 | short bLen = (short) (len / BLOCK_SIZE);
126 | // consider remainder separately
127 | short bRem = (short) (len % BLOCK_SIZE);
128 | // loop over all blocks but remainder
129 | short bOff = off;
130 | for (short bIdx = 0; bIdx < bLen; bIdx++) {
131 | generateBlock();
132 | Util.arrayCopyNonAtomic(mTmp, (short) 0, buf, bOff, BLOCK_SIZE);
133 | bOff += 16;
134 | }
135 | // handle the remainder
136 | if (bRem != 0) {
137 | generateBlock();
138 | Util.arrayCopyNonAtomic(mTmp, (short) 0, buf, bOff, bRem);
139 | }
140 | } finally {
141 | // advance key, even if some fault occurs
142 | generateKey();
143 | // be safe and wipe the temp buffer
144 | wipeTmp();
145 | }
146 | }
147 |
148 | /**
149 | * Seed the PRNG
150 | *
151 | * Seed must be at least 32 bytes.
152 | *
153 | * After using this once the PRNG is initialized.
154 | *
155 | * @param buf to read from
156 | * @param off to read at
157 | * @param len to read
158 | */
159 | public void setSeed(byte[] buf, short off, short len) {
160 | // reject any seed less than 256 bits
161 | if(len < 32) {
162 | CryptoException.throwIt(CryptoException.ILLEGAL_USE);
163 | }
164 | // handle exceptions so we can force wiping
165 | try {
166 | // retrieve key into tmp[0:31]
167 | mKey.getKey(mTmp, (short) 0);
168 | // hash the key
169 | mHash.reset();
170 | mHash.update(mTmp, (short) 0, (short) 32);
171 | // finish hash with new seed into tmp[0:31]
172 | mHash.doFinal(buf, off, len, mTmp, (short) 0);
173 | // increment counter
174 | incrementCounter();
175 | // set the new key
176 | mKey.setKey(mTmp, (short) 0);
177 | // once seeded we are initialized
178 | mInitialized = true;
179 | } finally {
180 | // be safe and wipe the temp buffer
181 | wipeTmp();
182 | }
183 | }
184 |
185 | /**
186 | * Internal: wipe the temporary buffer
187 | */
188 | private void wipeTmp() {
189 | Util.arrayFillNonAtomic(mTmp, (short)0, (short)mTmp.length, (byte)0);
190 | }
191 |
192 | /**
193 | * Internal: increment the Fortuna counter
194 | */
195 | private void incrementCounter() {
196 | mCounter.add((byte)1);
197 | }
198 |
199 | /**
200 | * Internal: generate one Fortuna block
201 | *
202 | * The result will be in mTmp[0:15].
203 | *
204 | * Temporary buffer should be cleared before returning to client.
205 | */
206 | private void generateBlock() {
207 | // get the counter before we increment it
208 | // mTmp[0:15] = counter
209 | mCounter.get(mTmp, (short)16, (short)16);
210 | // increment the counter early to better guarantee non-repetition
211 | incrementCounter();
212 | // first part of encrypt chain
213 | mCipher.init(mKey, Cipher.MODE_ENCRYPT);
214 | mCipher.doFinal(mTmp, (short)16, (short)16, mTmp, (short)0);
215 | // output is in mTmp[0:15]
216 | }
217 |
218 | /**
219 | * Internal: generate a new Fortuna key
220 | *
221 | * Temporary buffer should be cleared before returning to client.
222 | */
223 | private void generateKey() {
224 | generateBlock();
225 | Util.arrayCopyNonAtomic(mTmp, (short)0, mTmp, (short)32, (short)16);
226 | generateBlock();
227 | Util.arrayCopyNonAtomic(mTmp, (short)0, mTmp, (short)16, (short)16);
228 | Util.arrayCopyNonAtomic(mTmp, (short)32, mTmp, (short)0, (short)16);
229 | mKey.setKey(mTmp, (short)0);
230 | }
231 |
232 | }
233 |
--------------------------------------------------------------------------------
/library-fortuna/src/main/java/org/openjavacard/lib/fortuna/LongNum.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.fortuna;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 | import javacard.framework.JCSystem;
25 | import javacard.framework.Util;
26 |
27 | public class LongNum {
28 |
29 | private final byte[] mBuf;
30 | private final short mOff;
31 | private final short mLen;
32 |
33 | public LongNum(short len) {
34 | mBuf = new byte[len];
35 | mOff = 0;
36 | mLen = len;
37 | }
38 |
39 | public LongNum(short len, byte clearOn) {
40 | mBuf = JCSystem.makeTransientByteArray(len, clearOn);
41 | mOff = 0;
42 | mLen = len;
43 | }
44 |
45 | public LongNum(byte[] buf, short off, short len) {
46 | mBuf = buf;
47 | mOff = off;
48 | mLen = len;
49 | }
50 |
51 | public byte[] getBuffer() {
52 | return mBuf;
53 | }
54 |
55 | public short getOffset() {
56 | return mOff;
57 | }
58 |
59 | public short getLength() {
60 | return mLen;
61 | }
62 |
63 | private void error() {
64 | ISOException.throwIt(ISO7816.SW_DATA_INVALID);
65 | }
66 |
67 | public void clear() {
68 | Util.arrayFillNonAtomic(mBuf, (short)0, mLen, (byte)0);
69 | }
70 |
71 | public void get(byte[] buf, short off, short len) {
72 | if(len != mLen) {
73 | error();
74 | }
75 | Util.arrayCopyNonAtomic(mBuf, (short)0, buf, off, len);
76 | }
77 |
78 | public short getSignificantLength() {
79 | short result = 0;
80 | for(short i = 0; i < mLen; i++) {
81 | byte n = mBuf[i];
82 | if(n != 0) {
83 | result = (short)(mLen - i);
84 | }
85 | }
86 | return result;
87 | }
88 |
89 | public void getSignificant(byte[] buf, short off, short len) {
90 | short sigLen = getSignificantLength();
91 | short cutOff = (short)(mLen - len);
92 | if(len < sigLen) {
93 | error();
94 | }
95 | Util.arrayCopyNonAtomic(mBuf, cutOff, buf, off, len);
96 | }
97 |
98 | public void set(byte v) {
99 | clear();
100 | mBuf[(short)(mLen - 1)] = v;
101 | }
102 |
103 | public void set(byte[] buf, short off, short len) {
104 | if(len > mLen) {
105 | error();
106 | }
107 | clear();
108 | short shift = (short)(mLen - len);
109 | Util.arrayCopyNonAtomic(buf, off, mBuf, shift, len);
110 | }
111 |
112 | public void add(byte b) {
113 | short carry = (short)(b & 0xFF);
114 | for(short i = (short)(mLen - 1); i >= 0; i--) {
115 | short io = (short)(mOff + i);
116 | short o = (short)(mBuf[io] & 0xFF);
117 | short n = (short)(o + carry);
118 | mBuf[io] = (byte)(n & 0xFF);
119 | if(n > 255) {
120 | carry = 1;
121 | } else {
122 | carry = 0;
123 | }
124 | }
125 | }
126 |
127 | public void sub(byte b) {
128 | short carry = (short)(b & 0xFF);
129 | for(short i = (short)(mLen - 1); i >= 0; i--) {
130 | short io = (short)(mOff + i);
131 | short o = (short)(mBuf[io] & 0xFF);
132 | short n = (short)(o - carry);
133 | mBuf[io] = (byte)n;
134 | if(n < 0) {
135 | carry = 1;
136 | } else {
137 | carry = 0;
138 | }
139 | }
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/DF.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2019 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.isofs;
21 |
22 | import javacard.framework.ISOException;
23 |
24 | public class DF extends ISOFile {
25 |
26 | public static final byte FIND_TYPE_ANY = 0;
27 | public static final byte FIND_TYPE_DF = 1;
28 | public static final byte FIND_TYPE_EF = 2;
29 |
30 | private final ISOFile[] mChildren;
31 |
32 | DF(DF parent, byte fdb, short fid) {
33 | super(parent, fdb, fid, (byte)0);
34 | mChildren = new ISOFile[DF_SIZE];
35 | }
36 |
37 | short getChildCount() {
38 | short result = 0;
39 | for(short i = 0; i < mChildren.length; i++) {
40 | if(mChildren[i] != null) {
41 | result++;
42 | }
43 | }
44 | return result;
45 | }
46 |
47 | void addChild(ISOFile file) {
48 | // callers must hold this rule
49 | if(file.getParent() != this) {
50 | ISOException.throwIt(SW_UNKNOWN);
51 | }
52 | // check all child slots
53 | short slot = -1;
54 | boolean conflict = false;
55 | for(short i = 0; i < mChildren.length; i++) {
56 | ISOFile child = mChildren[i];
57 | if(child == null) {
58 | if(slot < 0) {
59 | // found an empty slot
60 | slot = i;
61 | }
62 | } else {
63 | if (child.mFID == file.mFID) {
64 | // found a name conflict
65 | conflict = true;
66 | }
67 | }
68 | }
69 | // throw due exceptions
70 | if(conflict) {
71 | ISOException.throwIt(SW_FILE_INVALID);
72 | }
73 | if(slot < 0) {
74 | ISOException.throwIt(SW_FILE_FULL);
75 | }
76 | // actually add the file
77 | mChildren[slot] = file;
78 | }
79 |
80 | void removeChild(ISOFile file) {
81 | for(short i = 0; i < mChildren.length; i++) {
82 | ISOFile child = mChildren[i];
83 | if(child == file) {
84 | mChildren[i] = null;
85 | }
86 | }
87 | }
88 |
89 | public ISOFile findUpwardsByFID(short fid, byte type) {
90 | ISOFile res = null;
91 | DF current = this;
92 | while(res == null && current != null) {
93 | res = current.findChildByFID(fid, type);
94 | current = current.getParent();
95 | }
96 | return res;
97 | }
98 |
99 | public ISOFile findChildByFID(short fid, byte type) {
100 | ISOFile res = null;
101 | for(short i = 0; i < mChildren.length; i++) {
102 | ISOFile child = mChildren[i];
103 | if(child.mFID == fid) {
104 | res = child;
105 | }
106 | }
107 | return res;
108 | }
109 |
110 | public ISOFile findChildBySFI(byte sfi, byte type) {
111 | ISOFile res = null;
112 | for(short i = 0; i < mChildren.length; i++) {
113 | ISOFile child = mChildren[i];
114 | if(child.mSFI == sfi) {
115 | res = child;
116 | }
117 | }
118 | return res;
119 | }
120 |
121 | public ISOFile findChildByPath(byte[] pathBuf, short pathOff, short pathLen) {
122 | return null;
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/EF.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2019 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.isofs;
21 |
22 | public abstract class EF extends ISOFile {
23 |
24 | protected byte mDCB;
25 |
26 | EF(DF parent, byte fdb, short fid, byte sfi) {
27 | super(parent, fdb, fid, sfi);
28 | }
29 |
30 | public byte getDCB() {
31 | return mDCB;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/EFCyclicFixed.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.isofs;
2 |
3 | public class EFCyclicFixed extends EFRecords {
4 |
5 | EFCyclicFixed(DF parent, byte fdb, short fid, byte sfi, short maxRecords, short maxSize) {
6 | super(parent, fdb, fid, sfi, maxRecords, maxSize);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/EFLinearFixed.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.isofs;
2 |
3 | public class EFLinearFixed extends EFRecords {
4 |
5 | EFLinearFixed(DF parent, byte fdb, short fid, byte sfi, short maxRecords, short maxSize) {
6 | super(parent, fdb, fid, sfi, maxRecords, maxSize);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/EFLinearVariable.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.isofs;
2 |
3 | public class EFLinearVariable extends EFRecords {
4 |
5 | EFLinearVariable(DF parent, byte fdb, short fid, byte sfi, short maxRecords, short maxSize) {
6 | super(parent, fdb, fid, sfi, maxRecords, maxSize);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/EFRecords.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.isofs;
2 |
3 | import javacard.framework.ISOException;
4 | import javacard.framework.Util;
5 |
6 | public abstract class EFRecords extends EF {
7 |
8 | protected final short mMaxRecords;
9 | protected final short mMaxSize;
10 |
11 | private final Object[] mRecords;
12 |
13 | EFRecords(DF parent, byte fdb, short fid, byte sfi, short maxRecords, short maxSize) {
14 | super(parent, fdb, fid, sfi);
15 | mMaxRecords = maxRecords;
16 | mMaxSize = maxSize;
17 | mRecords = new Object[maxRecords];
18 | }
19 |
20 | public byte[] getRecordByIndex(short index) {
21 | return (byte[])mRecords[index];
22 | }
23 |
24 | public void readRecord(short fileOff, byte[] dstBuf, short dstOff, short dstLen) {
25 | // XXX Util.arrayCopy(mData, fileOff, dstBuf, dstOff, dstLen);
26 | }
27 |
28 | public void updateRecord(short fileOff, byte[] srcBuf, short srcOff, short srcLen) {
29 | // XXX Util.arrayCopy(srcBuf, srcOff, mData, fileOff, srcLen);
30 | }
31 |
32 | public void writeRecord(short fileOff, byte[] srcBuf, short srcOff, short srcLen) {
33 | byte write = (byte)(mDCB & DCB_WRITE_MASK);
34 | short i;
35 | switch(write) {
36 | case DCB_WRITE_ONCE:
37 | // XXX
38 | break;
39 | case DCB_WRITE_PROPRIETARY:
40 | ISOException.throwIt(SW_COMMAND_NOT_ALLOWED);
41 | break;
42 | case DCB_WRITE_OR:
43 | for(i = 0; i < srcLen; i++) {
44 | // XXX mData[(short)(fileOff+i)] |= srcBuf[(short)(srcOff+i)];
45 | }
46 | break;
47 | case DCB_WRITE_AND:
48 | for(i = 0; i < srcLen; i++) {
49 | // XXX mData[(short)(fileOff+i)] &= srcBuf[(short)(srcOff+i)];
50 | }
51 | break;
52 | }
53 | }
54 |
55 | public void eraseRecord(short startOff, short endOff) {
56 | for(short off = startOff; off < endOff; off++) {
57 | // XXX mData[off] = 0;
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/EFTransparent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2019 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.isofs;
21 |
22 | import javacard.framework.ISOException;
23 | import javacard.framework.Util;
24 | import org.openjavacard.lib.ber.BERWriter;
25 |
26 | public class EFTransparent extends EF {
27 |
28 | protected final short mMaxLength;
29 |
30 | private final byte[] mData;
31 |
32 | EFTransparent(DF parent, byte fdb, short fid, byte sfi, short maxLength) {
33 | super(parent, fdb, fid, sfi);
34 | mMaxLength = maxLength;
35 | mData = new byte[maxLength];
36 | }
37 |
38 | public short getLength() {
39 | return (short)mData.length;
40 | }
41 |
42 | public byte[] getData() {
43 | return mData;
44 | }
45 |
46 | protected void tagsFCP(BERWriter ber) {
47 | ber.primitiveShort(TAG_FCI_SIZE_CONTENT, mMaxLength);
48 | super.tagsFCP(ber);
49 | }
50 |
51 | public void readData(short fileOff, byte[] dstBuf, short dstOff, short dstLen) {
52 | Util.arrayCopy(mData, fileOff, dstBuf, dstOff, dstLen);
53 | }
54 |
55 | public void updateData(short fileOff, byte[] srcBuf, short srcOff, short srcLen) {
56 | Util.arrayCopy(srcBuf, srcOff, mData, fileOff, srcLen);
57 | }
58 |
59 | public void writeData(short fileOff, byte[] srcBuf, short srcOff, short srcLen) {
60 | byte write = (byte)(mDCB & DCB_WRITE_MASK);
61 | short i;
62 | switch(write) {
63 | case DCB_WRITE_ONCE:
64 | // XXX
65 | break;
66 | case DCB_WRITE_PROPRIETARY:
67 | ISOException.throwIt(SW_COMMAND_NOT_ALLOWED);
68 | break;
69 | case DCB_WRITE_OR:
70 | for(i = 0; i < srcLen; i++) {
71 | mData[(short)(fileOff+i)] |= srcBuf[(short)(srcOff+i)];
72 | }
73 | break;
74 | case DCB_WRITE_AND:
75 | for(i = 0; i < srcLen; i++) {
76 | mData[(short)(fileOff+i)] &= srcBuf[(short)(srcOff+i)];
77 | }
78 | break;
79 | }
80 | }
81 |
82 | public void eraseData(short startOff, short endOff) {
83 | for(short off = startOff; off < endOff; off++) {
84 | mData[off] = 0;
85 | }
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/ISOConfig.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.isofs;
2 |
3 | public interface ISOConfig {
4 |
5 | /**
6 | * Maximum number of children in a DF
7 | */
8 | short DF_SIZE = 16;
9 |
10 | /**
11 | * Maximum length of FCI/FCP/FMD records
12 | */
13 | short BER_MAX_LENGTH = (short)128;
14 |
15 | /**
16 | * Maximum number of tags in TLV output
17 | */
18 | byte BER_MAX_TAGS = (byte)16;
19 |
20 | /**
21 | * Maximum depth of tags in TLV output
22 | */
23 | byte BER_MAX_DEPTH = (byte)4;
24 |
25 | /**
26 | * Maximum number of temp bytes for TLV output
27 | */
28 | short BER_MAX_TEMP = 128;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/ISOExtensions.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.isofs;
2 |
3 | import javacard.framework.ISO7816;
4 |
5 | public interface ISOExtensions extends ISO7816 {
6 |
7 | /* INS - Instruction bytes */
8 |
9 | byte INS_SELECT = ISO7816.INS_SELECT;
10 | byte SELECT_P1_SELECT_MASK = (byte)0xFF;
11 | byte SELECT_P1_SELECT_MF_DF_EF = (byte)0x00;
12 | byte SELECT_P1_SELECT_CHILD_DF = (byte)0x01;
13 | byte SELECT_P1_SELECT_CHILD_EF = (byte)0x02;
14 | byte SELECT_P1_SELECT_PARENT = (byte)0x03;
15 | byte SELECT_P1_SELECT_DFNAME = (byte)0x04;
16 | byte SELECT_P1_SELECT_PATH_MF = (byte)0x08;
17 | byte SELECT_P1_SELECT_PATH_DF = (byte)0x09;
18 | byte SELECT_P2_RESERVED_MASK = (byte)0xF0;
19 | byte SELECT_P2_RESERVED_OKAY = (byte)0x00;
20 | byte SELECT_P2_RETURN_MASK = (byte)0x0C;
21 | byte SELECT_P2_RETURN_FCI = (byte)0x00;
22 | byte SELECT_P2_RETURN_FCP = (byte)0x04;
23 | byte SELECT_P2_RETURN_FMD = (byte)0x08;
24 | byte SELECT_P2_RETURN_PROPRIETARY = (byte)0x0C;
25 | byte SELECT_P2_ITERATE_MASK = (byte)0x03;
26 | byte SELECT_P2_ITERATE_FIRST = (byte)0x00;
27 | byte SELECT_P2_ITERATE_LAST = (byte)0x01;
28 | byte SELECT_P2_ITERATE_NEXT = (byte)0x02;
29 | byte SELECT_P2_ITERATE_PREVIOUS = (byte)0x03;
30 |
31 | byte INS_CREATE_FILE = (byte)0xE0;
32 | byte INS_DELETE = (byte)0xE4;
33 | byte INS_READ_BINARY1 = (byte)0xB0;
34 | byte INS_READ_BINARY2 = (byte)0xB1;
35 | byte INS_UPDATE_BINARY1 = (byte)0xD6;
36 | byte INS_UPDATE_BINARY2 = (byte)0xD7;
37 | byte INS_WRITE_BINARY1 = (byte)0xD0;
38 | byte INS_WRITE_BINARY2 = (byte)0xD1;
39 | byte INS_SEARCH_BINARY1 = (byte)0xA0;
40 | byte INS_SEARCH_BINARY2 = (byte)0xA1;
41 | byte INS_ERASE_BINARY1 = (byte)0x0E;
42 | byte INS_ERASE_BINARY2 = (byte)0x0F;
43 |
44 | byte INS_READ_RECORD1 = (byte)0xB2;
45 | byte INS_READ_RECORD2 = (byte)0xB3;
46 | byte READ_RECORD_P2_SELECT_MASK = 0x07;
47 | byte READ_RECORD_P2_SELECT_RID_FIRST = 0x00;
48 | byte READ_RECORD_P2_SELECT_RID_LAST = 0x01;
49 | byte READ_RECORD_P2_SELECT_RID_NEXT = 0x02;
50 | byte READ_RECORD_P2_SELECT_RID_PREV = 0x03;
51 | byte READ_RECORD_P2_SELECT_NUMBER = 0x04;
52 | byte READ_RECORD_P2_SELECT_NUMBER_DOWN = 0x05;
53 | byte READ_RECORD_P2_SELECT_NUMBER_UP = 0x06;
54 |
55 | byte INS_UPDATE_RECORD1 = (byte)0xDC;
56 | byte INS_UPDATE_RECORD2 = (byte)0xDD;
57 | byte UPDATE_RECORD_P2_WRITE_MASK = 0x07;
58 | byte UPDATE_RECORD_P2_WRITE_REPLACE = 0x04;
59 | byte UPDATE_RECORD_P2_WRITE_LOGICAL_AND = 0x05;
60 | byte UPDATE_RECORD_P2_WRITE_LOGICAL_OR = 0x06;
61 | byte UPDATE_RECORD_P2_WRITE_LOGICAL_XOR = 0x07;
62 |
63 | byte INS_WRITE_RECORD = (byte)0xD2;
64 | byte WRITE_RECORD_P2_SELECT_MASK = 0x07;
65 | byte WRITE_RECORD_P2_SELECT_FIRST = 0x00;
66 | byte WRITE_RECORD_P2_SELECT_LAST = 0x01;
67 | byte WRITE_RECORD_P2_SELECT_NEXT = 0x02;
68 | byte WRITE_RECORD_P2_SELECT_PREV = 0x03;
69 | byte WRITE_RECORD_P2_SELECT_NUMBER = 0x04;
70 |
71 | byte INS_APPEND_RECORD = (byte)0xE2;
72 |
73 | byte INS_SEARCH_RECORD = (byte)0xA2;
74 |
75 | byte INS_ERASE_RECORD = (byte)0x0C;
76 | byte ERASE_RECORD_P2_SELECT_MASK = 0x07;
77 | byte ERASE_RECORD_P2_SELECT_NUMBER = 0x04;
78 | byte ERASE_RECORD_P2_SELECT_NUMBER_UP = 0x05;
79 |
80 | byte INS_CREATE = (byte)0xE1;
81 | byte INS_GET_DATA = (byte)0xCA;
82 | byte INS_PUT_DATA = (byte)0xDA;
83 | byte INS_MANAGE_DATA = (byte)0xCF;
84 | byte INS_ACTIVATE = (byte)0x44;
85 | byte INS_DEACTIVATE = (byte)0x04;
86 |
87 | byte INS_ACTIVATE_RECORD = (byte)0x08;
88 | byte INS_DEACTIVATE_RECORD = (byte)0x06;
89 | byte ACTIVATE_RECORD_SELECT_MASK = 0x07;
90 | byte ACTIVATE_RECORD_P2_SELECT_NUMBER = 0x04;
91 | byte ACTIVATE_RECORD_P2_SELECT_NUMBER_UP = 0x05;
92 |
93 | byte INS_TERMINATE = (byte)0xE6;
94 | byte INS_TERMINATE_EF = (byte)0xE8;
95 |
96 | byte INS_TERMINATE_CARD_USAGE = (byte)0xFE;
97 | byte INS_IMPORT_CARD_SECRET = (byte)0x48;
98 | byte INS_COMPARE = (byte)0x33;
99 |
100 | byte LIFECYCLE_P1_TYPE_MASK = (byte)0xF0;
101 | byte LIFECYCLE_P1_TYPE_FILE = (byte)0x00;
102 | byte LIFECYCLE_P1_TYPE_PASSWORD = (byte)0x10;
103 | byte LIFECYCLE_P1_TYPE_KEY = (byte)0x20;
104 | byte LIFECYCLE_P1_TYPE_OTHER = (byte)0x30;
105 | byte LIFECYCLE_P1_SELECT_MASK = (byte)0x0F;
106 | byte LIFECYCLE_P1_SELECT_FILE_SELECTED = (byte)0x00;
107 | byte LIFECYCLE_P1_SELECT_FILE_CHILD_DF = (byte)0x01;
108 | byte LIFECYCLE_P1_SELECT_FILE_CHILD_EF = (byte)0x02;
109 | byte LIFECYCLE_P1_SELECT_FILE_DFNAME = (byte)0x04;
110 | byte LIFECYCLE_P1_SELECT_FILE_PATH_MF = (byte)0x08;
111 | byte LIFECYCLE_P1_SELECT_FILE_PATH_DF = (byte)0x09;
112 |
113 | /* FID - File identifiers */
114 |
115 | /** FID of the Master File */
116 | short FID_MF = (short)0x3F00;
117 | /** FID of EF.DIR */
118 | short FID_EF_DIR = (short)0x2F00;
119 | /** FID of EF.ATR */
120 | short FID_EF_ATR = (short)0x2F01;
121 |
122 | /* TAG - Tag values for TLV structures */
123 |
124 | /** Tag for File Control Parameter template */
125 | short TAG_FCP = (short)0x6200;
126 | /** Tag for File Management Data template */
127 | short TAG_FMD = (short)0x6400;
128 | /** Tag for File Control Information template */
129 | short TAG_FCI = (short)0x6F00;
130 |
131 | short TAG_FCI_SIZE_CONTENT = (short)0x8000;
132 | short TAG_FCI_SIZE_TOTAL = (short)0x8100;
133 | short TAG_FCI_FDB = (short)0x8200;
134 | short TAG_FCI_FILEID = (short)0x8300;
135 | short TAG_FCI_DFNAME = (short)0x8400;
136 | short TAG_FCI_PROPRIETARY = (short)0x8500;
137 | short TAG_FCI_SECURITY_PROPRIETARY = (short)0x8600;
138 | short TAG_FCI_EXTENSION = (short)0x8700;
139 | short TAG_FCI_SFI = (short)0x8800;
140 | short TAG_FCI_LCS = (short)0x8A00;
141 | short TAG_FCI_SECURITY_EXPANDED = (short)0x8B00;
142 | short TAG_FCI_SECURITY_COMPACT = (short)0x8C00;
143 | short TAG_FCI_SECENV_TEMPLATE = (short)0x8D00;
144 | short TAG_FCI_CSA = (short)0x8E00;
145 |
146 | /* FDB - File descriptor byte */
147 |
148 | byte FDB_SHAREABLE = (byte)0x40;
149 |
150 | byte FDB_CATEGORY_MASK = (byte)0x38;
151 | byte FDB_CATEGORY_SPECIAL = (byte)0x38;
152 | byte FDB_CATEGORY_EF_WORKING = (byte)0x00;
153 | byte FDB_CATEGORY_EF_INTERNAL = (byte)0x08;
154 |
155 | byte FDB_SPECIAL_MASK = (byte)0x03;
156 | byte FDB_SPECIAL_DF = (byte)0x00;
157 | byte FDB_SPECIAL_TLV_BER = (byte)0x01;
158 | byte FDB_SPECIAL_TLV_SIMPLE = (byte)0x02;
159 |
160 | byte FDB_STRUCTURE_MASK = (byte)0x07;
161 | byte FDB_STRUCTURE_UNKNOWN = (byte)0x00;
162 | byte FDB_STRUCTURE_TRANSPARENT = (byte)0x01;
163 | byte FDB_STRUCTURE_LINEAR_FIXED = (byte)0x02;
164 | byte FDB_STRUCTURE_LINEAR_FIXED_TLV = (byte)0x03;
165 | byte FDB_STRUCTURE_LINEAR_VARIABLE = (byte)0x04;
166 | byte FDB_STRUCTURE_LINEAR_VARIABLE_TLV = (byte)0x05;
167 | byte FDB_STRUCTURE_CYCLIC_FIXED = (byte)0x06;
168 | byte FDB_STRUCTURE_CYCLIC_FIXED_TLV = (byte)0x07;
169 |
170 | /* DCB Data coding byte */
171 |
172 | byte DCB_BERSUPPORT_FLAG = (byte)0x80;
173 |
174 | byte DCB_WRITE_MASK = (byte)0x60;
175 | byte DCB_WRITE_ONCE = (byte)0x00;
176 | byte DCB_WRITE_PROPRIETARY = (byte)0x20;
177 | byte DCB_WRITE_OR = (byte)0x40;
178 | byte DCB_WRITE_AND = (byte)0x60;
179 |
180 | byte DCB_TLVFF_MASK = (byte)0x10;
181 | byte DCB_TLVFF_INVALID = (byte)0x00;
182 | byte DCB_TLVFF_VALID = (byte)0x10;
183 |
184 | byte DCB_DUSIZE_MASK = (byte)0x0F;
185 |
186 | /* LCS - Life cycle state */
187 |
188 | byte LCS_UNKNOWN = (byte)0x00;
189 | byte LCS_CREATION = (byte)0x01;
190 | byte LCS_INITIALIZATION = (byte)0x03;
191 | byte LCS_OPERATIONAL_DEACTIVATED = (byte)0x04;
192 | byte LCS_OPERATIONAL_ACTIVATED = (byte)0x05;
193 | byte LCS_TERMINATED = (byte)0x0C;
194 |
195 | /* CSA - Channel security attribute */
196 |
197 | byte CSA_RESERVED_MASK = (byte)0xF8;
198 | byte CSA_RESERVED_OKAY = (byte)0x00;
199 | byte CSA_NONSHARED = (byte)0x04;
200 | byte CSA_SECURED = (byte)0x02;
201 | byte CSA_AUTHENTICATED = (byte)0x01;
202 |
203 | /* SCB - Security condition byte */
204 |
205 | byte SCB_ALWAYS = (byte)0x00;
206 | byte SCB_NEVER = (byte)0xFF;
207 |
208 | byte SCB_MODE_MASK = (byte)0x80;
209 | byte SCB_MODE_OR = (byte)0x00;
210 | byte SCB_MODE_AND = (byte)0x80;
211 |
212 | byte SCB_CHECK_MASK = (byte)0x70;
213 | byte SCB_CHECK_SM = (byte)0x40;
214 | byte SCB_CHECK_EA = (byte)0x20;
215 | byte SCB_CHECK_UA = (byte)0x10;
216 |
217 | byte SCB_ENVIRONMENT_MASK = (byte)0x0F;
218 | byte SCB_ENVIRONMENT_NONE = (byte)0x00;
219 |
220 |
221 |
222 |
223 |
224 |
225 | byte ACCESS_DF_DELETE_SELF = 6;
226 | byte ACCESS_DF_TERMINATE = 5;
227 | byte ACCESS_DF_ACTIVATE_FILE = 4;
228 | byte ACCESS_DF_DEACTIVATE_FILE = 3;
229 | byte ACCESS_DF_CREATE_DF = 2;
230 | byte ACCESS_DF_CREATE_EF = 1;
231 | byte ACCESS_DF_DELETE_CHILD = 0;
232 |
233 | byte ACCESS_EF_DELETE = 6;
234 | byte ACCESS_EF_TERMINATE = 5;
235 | byte ACCESS_EF_ACTIVATE = 4;
236 | byte ACCESS_EF_DEACTIVATE = 3;
237 | byte ACCESS_EF_WRITE = 2;
238 | byte ACCESS_EF_UPDATE = 1;
239 | byte ACCESS_EF_READ = 0;
240 |
241 | byte ACCESS_DO_MANAGE = 2;
242 | byte ACCESS_DO_PUT_DATA = 1;
243 | byte ACCESS_DO_GET_DATA = 0;
244 | }
245 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/ISOFile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2019 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.isofs;
21 |
22 | import org.openjavacard.lib.ber.BERWriter;
23 |
24 | public abstract class ISOFile implements ISOConfig, ISOExtensions {
25 |
26 | final DF mParent;
27 | final short mFID;
28 | final byte mSFI;
29 | final byte mFDB;
30 | private byte mLCS;
31 | private byte mCSA;
32 |
33 | /**
34 | * Base constructor
35 | * @param fid for the file
36 | * @param fdb for the file
37 | */
38 | ISOFile(DF parent, byte fdb, short fid, byte sfi) {
39 | mParent = parent;
40 | mFID = fid;
41 | mSFI = sfi;
42 | mFDB = fdb;
43 | mLCS = LCS_CREATION;
44 | }
45 |
46 | /** @return parent DF of this file */
47 | public DF getParent() {
48 | return mParent;
49 | }
50 |
51 | /** @return file ID of this file */
52 | public short getFID() {
53 | return mFID;
54 | }
55 |
56 | /** @return short EF identifier */
57 | public byte getSFI() {
58 | return mSFI;
59 | }
60 |
61 | /** @return channel security attribute */
62 | public byte getCSA() {
63 | return mCSA;
64 | }
65 |
66 | /** @return assigned life cycle state */
67 | public byte getAssignedLCS() {
68 | return mLCS;
69 | }
70 |
71 | /** @return effective life cycle state */
72 | public byte getEffectiveLCS() {
73 | // start with the assigned LCS
74 | byte effective = mLCS;
75 | // termination is always effective
76 | if(effective != LCS_TERMINATED) {
77 | // skip processing if no parent (MF)
78 | if(mParent != null) {
79 | // get parent LCS
80 | byte parent = mParent.getEffectiveLCS();
81 | // if parent is deactivated then so are we
82 | if (parent == LCS_OPERATIONAL_DEACTIVATED) {
83 | effective = LCS_OPERATIONAL_DEACTIVATED;
84 | }
85 | // if parent is terminated then so are we
86 | if (parent == LCS_TERMINATED) {
87 | effective = LCS_TERMINATED;
88 | }
89 | }
90 | }
91 | // return result
92 | return effective;
93 | }
94 |
95 | /**
96 | * Activate the file
97 | */
98 | public void activate() {
99 | byte effectiveLCS = getEffectiveLCS();
100 | if(effectiveLCS != LCS_TERMINATED) {
101 | mLCS = LCS_OPERATIONAL_ACTIVATED;
102 | }
103 | }
104 |
105 | /**
106 | * Deactivate the file
107 | */
108 | public void deactivate() {
109 | byte effectiveLCS = getEffectiveLCS();
110 | if(effectiveLCS != LCS_TERMINATED) {
111 | mLCS = LCS_OPERATIONAL_DEACTIVATED;
112 | }
113 | }
114 |
115 | /**
116 | * Terminate the file
117 | */
118 | public void terminate() {
119 | byte effectiveLCS = getEffectiveLCS();
120 | if(effectiveLCS != LCS_TERMINATED) {
121 | mLCS = LCS_TERMINATED;
122 | }
123 | }
124 |
125 | /**
126 | * Write FCI into the given writer
127 | * @param ber
128 | */
129 | public void writeFCI(BERWriter ber) {
130 | ber.beginConstructed(TAG_FCI);
131 | tagsFCP(ber);
132 | tagsFMD(ber);
133 | ber.endConstructed();
134 | }
135 |
136 | /**
137 | * Write FCP into the given writer
138 | * @param ber
139 | */
140 | public void writeFCP(BERWriter ber) {
141 | ber.beginConstructed(TAG_FCP);
142 | tagsFCP(ber);
143 | ber.endConstructed();
144 | }
145 |
146 | /**
147 | * Write FMD into the given writer
148 | * @param ber
149 | */
150 | public void writeFMD(BERWriter ber) {
151 | ber.beginConstructed(TAG_FMD);
152 | tagsFMD(ber);
153 | ber.endConstructed();
154 | }
155 |
156 | /**
157 | * Produce FCP tags
158 | * @param ber
159 | */
160 | protected void tagsFCP(BERWriter ber) {
161 | // 82 - File descriptor
162 | ber.primitiveByte(TAG_FCI_FDB, mFDB);
163 | // 83 - File identifier
164 | ber.primitiveShort(TAG_FCI_FILEID, mFID);
165 | // 8A - Life cycle status
166 | ber.primitiveByte(TAG_FCI_LCS, mLCS);
167 | // 8E - Channel security attribute
168 | if(mCSA != 0) {
169 | ber.primitiveByte(TAG_FCI_CSA, mCSA);
170 | }
171 | }
172 |
173 | /**
174 | * Produce FMD tags
175 | * @param ber
176 | */
177 | protected void tagsFMD(BERWriter ber) {
178 | }
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/ISOFileCreator.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.isofs;
2 |
3 | import javacard.framework.JCSystem;
4 | import javacard.framework.Util;
5 | import org.openjavacard.lib.ber.BERHandler;
6 | import org.openjavacard.lib.ber.BERReader;
7 | import org.openjavacard.lib.ber.BERSource;
8 |
9 | /**
10 | * ISO7816 file creator
11 | */
12 | public class ISOFileCreator implements BERHandler, ISOExtensions {
13 |
14 | private final Object[] mRefs;
15 | private static final short REF_PARENT = 0;
16 | private static final short NUM_REFS = 1;
17 |
18 | private final short[] mVars;
19 | private static final short VAR_FID = 0;
20 | private static final short VAR_FDB = 1;
21 | private static final short VAR_DCB = 2;
22 | private static final short VAR_LCS = 3;
23 | private static final short VAR_CSA = 4;
24 | private static final short VAR_SFI = 5;
25 | private static final short VAR_MAX_CONTENT = 6;
26 | private static final short VAR_MAX_RECORD_COUNT = 7;
27 | private static final short VAR_MAX_RECORD_SIZE = 8;
28 | private static final short NUM_VARS = 9;
29 |
30 | ISOFileCreator() {
31 | mRefs = JCSystem.makeTransientObjectArray(NUM_REFS, JCSystem.CLEAR_ON_RESET);
32 | mVars = JCSystem.makeTransientShortArray(NUM_VARS, JCSystem.CLEAR_ON_RESET);
33 | }
34 |
35 | public boolean isCreatingDF() {
36 | byte fdb = (byte)mVars[VAR_FDB];
37 | return ((fdb & FDB_CATEGORY_MASK) == FDB_CATEGORY_SPECIAL)
38 | && ((fdb & FDB_SPECIAL_MASK) == FDB_SPECIAL_DF);
39 | }
40 |
41 | public void prepare(DF parent) {
42 | mRefs[REF_PARENT] = parent;
43 | }
44 |
45 | public ISOFile create() {
46 | DF parent = (DF) mRefs[REF_PARENT];
47 | byte fdb = (byte)mVars[VAR_FDB];
48 |
49 | ISOFile file = null;
50 |
51 | switch(fdb & FDB_CATEGORY_MASK) {
52 | case FDB_CATEGORY_EF_WORKING:
53 | case FDB_CATEGORY_EF_INTERNAL:
54 | file = createEF(fdb);
55 | break;
56 | case FDB_CATEGORY_SPECIAL:
57 | switch (fdb & FDB_SPECIAL_MASK) {
58 | case FDB_SPECIAL_DF:
59 | file = createDF(fdb);
60 | break;
61 | case FDB_SPECIAL_TLV_BER:
62 | case FDB_SPECIAL_TLV_SIMPLE:
63 | file = createDO(fdb);
64 | break;
65 | default:
66 | // XXX error
67 | break;
68 | }
69 | break;
70 | default:
71 | // XXX error
72 | break;
73 | }
74 |
75 | parent.addChild(file);
76 |
77 | return file;
78 | }
79 |
80 | private EF createEF(byte fdb) {
81 | DF parent = (DF) mRefs[REF_PARENT];
82 | short fid = mVars[VAR_FID];
83 | byte sfi = (byte)mVars[VAR_SFI];
84 | EF ef = null;
85 |
86 | switch(fdb & FDB_STRUCTURE_MASK) {
87 | case FDB_STRUCTURE_TRANSPARENT:
88 | ef = new EFTransparent(parent, fdb, fid, sfi, mVars[VAR_MAX_CONTENT]);
89 | break;
90 | case FDB_STRUCTURE_LINEAR_FIXED:
91 | case FDB_STRUCTURE_LINEAR_FIXED_TLV:
92 | ef = new EFLinearFixed(parent, fdb, fid, sfi, (short)0, (short)0);
93 | break;
94 | case FDB_STRUCTURE_LINEAR_VARIABLE:
95 | case FDB_STRUCTURE_LINEAR_VARIABLE_TLV:
96 | ef = new EFLinearVariable(parent, fdb, fid, sfi, (short)0, (short)0);
97 | break;
98 | case FDB_STRUCTURE_CYCLIC_FIXED:
99 | case FDB_STRUCTURE_CYCLIC_FIXED_TLV:
100 | ef = new EFCyclicFixed(parent, fdb, fid, sfi, (short)0, (short)0);
101 | break;
102 | default:
103 | // XXX error
104 | break;
105 | }
106 |
107 | return ef;
108 | }
109 |
110 | private DF createDF(byte fdb) {
111 | DF parent = (DF) mRefs[REF_PARENT];
112 | short fid = mVars[VAR_FID];
113 | DF df = new DF(parent, fdb, fid);
114 | return df;
115 | }
116 |
117 | private EF createDO(byte fdb) {
118 | return null;
119 | }
120 |
121 | public boolean handlePrimitive(BERSource source, byte depth, short tag,
122 | byte[] dataBuf, short dataOff, short dataLen) {
123 | if(depth == 1) {
124 | if(tag == TAG_FCI_SIZE_CONTENT) {
125 | if(dataLen == 1) {
126 | mVars[VAR_MAX_CONTENT] = (short)(dataBuf[dataOff] & 0xFF);
127 | return true;
128 | }
129 | if(dataLen == 2) {
130 | mVars[VAR_MAX_CONTENT] = Util.getShort(dataBuf, dataOff);
131 | return true;
132 | }
133 | }
134 | if(tag == TAG_FCI_FDB) {
135 | if(dataLen >= 1 && dataLen <= 6) {
136 | // first byte is FCB
137 | mVars[VAR_FDB] = dataBuf[dataOff++];
138 | if(dataLen > 1) {
139 | // second byte is DCB
140 | mVars[VAR_DCB] = dataBuf[dataOff++];
141 | // now decode the max record size
142 | if(dataLen == 3) {
143 | mVars[VAR_MAX_RECORD_SIZE] = (short)(dataBuf[dataOff++] & 0xFF);
144 | }
145 | if(dataLen >= 4) {
146 | mVars[VAR_MAX_RECORD_SIZE] = Util.getShort(dataBuf, dataOff);
147 | dataOff += 2;
148 | // there might also be a max record count
149 | if(dataLen == 5) {
150 | mVars[VAR_MAX_RECORD_COUNT] = (short)(dataBuf[dataOff++] & 0xFF);
151 | }
152 | if(dataLen == 6) {
153 | mVars[VAR_MAX_RECORD_COUNT] = Util.getShort(dataBuf, dataOff);
154 | dataOff += 2;
155 | }
156 | }
157 | }
158 | return true;
159 | }
160 | }
161 | if(tag == TAG_FCI_FILEID && dataLen == 2) {
162 | mVars[VAR_FID] = Util.getShort(dataBuf, dataOff);
163 | return true;
164 | }
165 | if(tag == TAG_FCI_LCS && dataLen == 1) {
166 | mVars[VAR_LCS] = dataBuf[dataOff];
167 | return true;
168 | }
169 | if(tag == TAG_FCI_CSA && dataLen == 1) {
170 | mVars[VAR_CSA] = dataBuf[dataOff];
171 | return true;
172 | }
173 | if(tag == TAG_FCI_SFI && dataLen == 1) {
174 | mVars[VAR_SFI] = dataBuf[dataOff];
175 | return true;
176 | }
177 | }
178 | return false;
179 | }
180 |
181 | public boolean handleBeginConstructed(BERSource source, byte depth, short tag) {
182 | if(depth == 0) {
183 | if (tag == TAG_FCI) {
184 | return true;
185 | }
186 | if (tag == TAG_FCP) {
187 | return true;
188 | }
189 | }
190 | return false;
191 | }
192 |
193 | public boolean handleFinishConstructed(BERSource source, byte depth, short tag) {
194 | if(depth == 0) {
195 | if (tag == TAG_FCI) {
196 | return true;
197 | }
198 | if (tag == TAG_FCP) {
199 | return true;
200 | }
201 | }
202 | return false;
203 | }
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/ISOFileSystem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2019 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.isofs;
21 |
22 | import javacard.framework.APDU;
23 | import javacard.framework.ISOException;
24 | import javacard.framework.JCSystem;
25 | import javacard.framework.Util;
26 | import org.openjavacard.lib.ber.BERReader;
27 | import org.openjavacard.lib.ber.BERWriter;
28 |
29 | /**
30 | * ISO7816 file system implementation
31 | */
32 | public class ISOFileSystem implements ISOConfig, ISOExtensions {
33 |
34 | /** The root directory */
35 | private final MF mMF;
36 |
37 | /** BER reader for parsing */
38 | private final BERReader mReader;
39 |
40 | /** BER writer for generating */
41 | private final BERWriter mWriter;
42 |
43 | /** File creator */
44 | private final ISOFileCreator mFileCreator;
45 |
46 | /**
47 | * Main constructor
48 | */
49 | public ISOFileSystem() {
50 | byte clearOn = JCSystem.CLEAR_ON_RESET;
51 | mMF = new MF();
52 | mReader = new BERReader(BER_MAX_DEPTH, clearOn);
53 | mWriter = new BERWriter(BER_MAX_TAGS, BER_MAX_DEPTH, BER_MAX_TEMP, clearOn);
54 | mFileCreator = new ISOFileCreator();
55 | }
56 |
57 | /** @return the MF */
58 | public MF getMF() {
59 | return mMF;
60 | }
61 |
62 | public DF findByDFName(byte[] pathBuf, short pathOff, short pathLen) {
63 | return null;
64 | }
65 |
66 |
67 |
68 | BERReader getBERReader() {
69 | return mReader;
70 | }
71 |
72 | BERWriter getBERWriter() {
73 | return mWriter;
74 | }
75 |
76 | ISOFileCreator getISOFileCreator() {
77 | return mFileCreator;
78 | }
79 |
80 |
81 |
82 | private void accessFile(ISOFile file, byte access) {
83 | }
84 |
85 | public void accessDirectory(DF directory, byte access) {
86 | accessFile(directory, access);
87 | }
88 |
89 | public EFTransparent accessFileBinary(EF file, byte access) {
90 | EFTransparent eft = (EFTransparent)file;
91 | accessFile(file, access);
92 | return eft;
93 | }
94 |
95 | public EFRecords accessFileRecord(EF file, byte access) {
96 | EFRecords efr = (EFRecords)file;
97 | accessFile(file, access);
98 | return efr;
99 | }
100 |
101 |
102 | private short checkLength(APDU apdu) {
103 | short lc = apdu.getIncomingLength();
104 | short len = apdu.setIncomingAndReceive();
105 | if(len != lc) {
106 | ISOException.throwIt(SW_WRONG_LENGTH);
107 | }
108 | return len;
109 | }
110 |
111 |
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/library-isofs/src/main/java/org/openjavacard/lib/isofs/MF.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2019 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.isofs;
21 |
22 | public class MF extends DF {
23 |
24 | private static final byte FDB = FDB_CATEGORY_SPECIAL|FDB_SPECIAL_DF;
25 |
26 | MF() {
27 | super(null, FDB, FID_MF);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/library-oath/src/main/java/org/openjavacard/lib/oath/HOTPGenerator.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.oath;
2 |
3 | public class HOTPGenerator {
4 |
5 | private OATHConfig mConfig;
6 |
7 | public HOTPGenerator(OATHConfig config) {
8 | }
9 |
10 | public short getCounter(byte[] buf, short off, short len) {
11 | return (short)0;
12 | }
13 |
14 | public short setCounter(byte[] buf, short off, short len) {
15 | return (short)0;
16 | }
17 |
18 | public short generate(byte[] buf, short off, short len) {
19 | return (short)0;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/library-oath/src/main/java/org/openjavacard/lib/oath/HOTPVerifier.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.oath;
2 |
3 | import javacard.framework.ISOException;
4 | import javacard.framework.JCSystem;
5 | import javacard.framework.PIN;
6 |
7 | public class HOTPVerifier implements PIN {
8 |
9 | private static final short SW_PIN_TRIES_REMAINING = (short)0x63C0;
10 |
11 | private final byte mMaxTries;
12 | private final byte mMaxOffset;
13 |
14 | private byte mTries;
15 |
16 | private final OATHConfig mConfig;
17 | private final byte[] mCounter;
18 |
19 | private final boolean[] mFlags;
20 | private static final short NUM_FLAGS = 1;
21 | private static final short FLAG_VALIDATED = 0;
22 |
23 | public HOTPVerifier(OATHConfig config, byte maxTries, byte maxOffset, byte clearOn) {
24 | mMaxTries = maxTries;
25 | mMaxOffset = maxOffset;
26 | mConfig = config;
27 | mCounter = new byte[8];
28 | mFlags = JCSystem.makeTransientBooleanArray(NUM_FLAGS, clearOn);
29 | }
30 |
31 | public byte getTriesRemaining() {
32 | return (byte)(mMaxTries - mTries);
33 | }
34 |
35 | public boolean isValidated() {
36 | return mFlags[FLAG_VALIDATED];
37 | }
38 |
39 | public short getCounter(byte[] buf, short off, short len) {
40 | return (short)0;
41 | }
42 |
43 | public short setCounter(byte[] buf, short off, short len) {
44 | return (short)0;
45 | }
46 |
47 | public void reset() {
48 | if(mFlags[FLAG_VALIDATED]) {
49 | resetAndUnblock();
50 | }
51 | }
52 |
53 | public void resetAndUnblock() {
54 | mFlags[FLAG_VALIDATED] = false;
55 | mTries = 0;
56 | }
57 |
58 | public boolean check(byte[] bytes, short off, byte len) throws ArrayIndexOutOfBoundsException, NullPointerException {
59 | // assume password is incorrect
60 | boolean correct = false;
61 |
62 | // clear validated flag
63 | mFlags[FLAG_VALIDATED] = false;
64 |
65 | // compute new counter value
66 | byte newTries = (byte)(mTries + 1);
67 | // check try counter
68 | if(newTries >= mMaxTries || newTries <= 0) {
69 | errorTriesRemaining();
70 | }
71 | // save try counter
72 | mTries = newTries;
73 |
74 | // pre-wipe temp buffer for paranoia
75 | wipeTemp();
76 | try {
77 | // iterate acceptable offsets
78 | for(byte counterOffset = 0; counterOffset < mMaxOffset; counterOffset++) {
79 | }
80 | // handle correct password
81 | if(correct) {
82 | // set validated flag
83 | mFlags[FLAG_VALIDATED] = true;
84 | // reset try counter
85 | mTries = 0;
86 | }
87 | } finally {
88 | wipeTemp();
89 | }
90 |
91 | // return result
92 | return correct;
93 | }
94 |
95 | private void errorTriesRemaining() {
96 | short code = SW_PIN_TRIES_REMAINING;
97 | byte remaining = getTriesRemaining();
98 | if(remaining > 15) {
99 | remaining = 15;
100 | }
101 | code |= remaining;
102 | ISOException.throwIt(code);
103 | }
104 |
105 | private void wipeTemp() {
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/library-oath/src/main/java/org/openjavacard/lib/oath/LongNum.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.oath;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 | import javacard.framework.JCSystem;
25 | import javacard.framework.Util;
26 |
27 | public class LongNum {
28 |
29 | private final byte[] mBuf;
30 | private final short mOff;
31 | private final short mLen;
32 |
33 | public LongNum(short len) {
34 | mBuf = new byte[len];
35 | mOff = 0;
36 | mLen = len;
37 | }
38 |
39 | public LongNum(short len, byte clearOn) {
40 | mBuf = JCSystem.makeTransientByteArray(len, clearOn);
41 | mOff = 0;
42 | mLen = len;
43 | }
44 |
45 | public LongNum(byte[] buf, short off, short len) {
46 | mBuf = buf;
47 | mOff = off;
48 | mLen = len;
49 | }
50 |
51 | public byte[] getBuffer() {
52 | return mBuf;
53 | }
54 |
55 | public short getOffset() {
56 | return mOff;
57 | }
58 |
59 | public short getLength() {
60 | return mLen;
61 | }
62 |
63 | private void error() {
64 | ISOException.throwIt(ISO7816.SW_DATA_INVALID);
65 | }
66 |
67 | public void clear() {
68 | Util.arrayFillNonAtomic(mBuf, (short)0, mLen, (byte)0);
69 | }
70 |
71 | public void get(byte[] buf, short off, short len) {
72 | if(len != mLen) {
73 | error();
74 | }
75 | Util.arrayCopyNonAtomic(mBuf, (short)0, buf, off, len);
76 | }
77 |
78 | public short getSignificantLength() {
79 | short result = 0;
80 | for(short i = 0; i < mLen; i++) {
81 | byte n = mBuf[i];
82 | if(n != 0) {
83 | result = (short)(mLen - i);
84 | }
85 | }
86 | return result;
87 | }
88 |
89 | public void getSignificant(byte[] buf, short off, short len) {
90 | short sigLen = getSignificantLength();
91 | short cutOff = (short)(mLen - len);
92 | if(len < sigLen) {
93 | error();
94 | }
95 | Util.arrayCopyNonAtomic(mBuf, cutOff, buf, off, len);
96 | }
97 |
98 | public void set(byte v) {
99 | clear();
100 | mBuf[(short)(mLen - 1)] = v;
101 | }
102 |
103 | public void set(byte[] buf, short off, short len) {
104 | if(len > mLen) {
105 | error();
106 | }
107 | clear();
108 | short shift = (short)(mLen - len);
109 | Util.arrayCopyNonAtomic(buf, off, mBuf, shift, len);
110 | }
111 |
112 | public void add(byte b) {
113 | short carry = (short)(b & 0xFF);
114 | for(short i = (short)(mLen - 1); i >= 0; i--) {
115 | short io = (short)(mOff + i);
116 | short o = (short)(mBuf[io] & 0xFF);
117 | short n = (short)(o + carry);
118 | mBuf[io] = (byte)(n & 0xFF);
119 | if(n > 255) {
120 | carry = 1;
121 | } else {
122 | carry = 0;
123 | }
124 | }
125 | }
126 |
127 | public void sub(byte b) {
128 | short carry = (short)(b & 0xFF);
129 | for(short i = (short)(mLen - 1); i >= 0; i--) {
130 | short io = (short)(mOff + i);
131 | short o = (short)(mBuf[io] & 0xFF);
132 | short n = (short)(o - carry);
133 | mBuf[io] = (byte)n;
134 | if(n < 0) {
135 | carry = 1;
136 | } else {
137 | carry = 0;
138 | }
139 | }
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/library-oath/src/main/java/org/openjavacard/lib/oath/OATHCipher.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.oath;
2 |
3 | import javacard.security.HMACKey;
4 | import javacard.security.KeyBuilder;
5 | import javacard.security.Signature;
6 |
7 | public class OATHCipher {
8 |
9 | public static final byte ALG_SHA1 = Signature.ALG_HMAC_SHA1;
10 | public static final byte ALG_SHA256 = Signature.ALG_HMAC_SHA_256;
11 | public static final byte ALG_SHA512 = Signature.ALG_HMAC_SHA_512;
12 |
13 | private Signature mSigner;
14 |
15 | private HMACKey mKey;
16 |
17 | public OATHCipher(byte mode) {
18 | mSigner = Signature.getInstance(mode, false);
19 | mKey = (HMACKey)KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, mSigner.getLength(), false);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/library-oath/src/main/java/org/openjavacard/lib/oath/OATHConfig.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.oath;
2 |
3 | import javacard.security.HMACKey;
4 | import javacard.security.SecretKey;
5 |
6 | public class OATHConfig implements SecretKey {
7 |
8 | private HMACKey mKey;
9 |
10 | private byte mDigits;
11 |
12 | private byte[] mCounter;
13 |
14 | public boolean isInitialized() {
15 | return false;
16 | }
17 |
18 | public short getSize() {
19 | return 0;
20 | }
21 |
22 | public byte getType() {
23 | return 0;
24 | }
25 |
26 | public void clearKey() {
27 | mKey.clearKey();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/library-oath/src/main/java/org/openjavacard/lib/oath/TOTPClock.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.oath;
2 |
3 | public interface TOTPClock {
4 |
5 | short getLength();
6 |
7 | short getTime(byte[] buf, short off, short len);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/library-oath/src/main/java/org/openjavacard/lib/oath/TOTPGenerator.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.oath;
2 |
3 | public class TOTPGenerator {
4 |
5 | private TOTPClock mClock;
6 |
7 | public TOTPClock getClock() {
8 | return mClock;
9 | }
10 |
11 | public void setClock(TOTPClock clock) {
12 | mClock = clock;
13 | }
14 |
15 | public short generate(byte[] buf, short off, short len) {
16 | return (short)0;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/library-password/src/main/java/org/openjavacard/lib/password/PasswordHash.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.password;
21 |
22 | import javacard.framework.ISO7816;
23 | import javacard.framework.ISOException;
24 | import javacard.framework.JCSystem;
25 | import javacard.framework.PIN;
26 |
27 | import javacard.framework.Util;
28 | import javacard.security.MessageDigest;
29 | import javacard.security.RandomData;
30 |
31 | /**
32 | * Password hash authenticator
33 | *
34 | * This class implements a salted hash password mechanism and can
35 | * be used as an alternative to OwnerPIN with improved properties.
36 | *
37 | */
38 | public class PasswordHash implements PIN {
39 |
40 | /** ISO7816: SW value for warning about remaining tries */
41 | private static final short SW_PIN_TRIES_REMAINING = (short)0x63C0;
42 |
43 | /** Configuration: allow use of SHA512 */
44 | private static final boolean USE_SHA512 = true;
45 | /** Configuration: allow use of SHA256 */
46 | private static final boolean USE_SHA256 = true;
47 | /** Configuration: allow use of SHA1 */
48 | private static final boolean USE_SHA160 = true;
49 | /** Configuration: allow use of MD5 */
50 | private static final boolean USE_MD5 = false;
51 |
52 | /** RNG for salt generation */
53 | private final RandomData mRandom;
54 | /** Digest for hash operations */
55 | private final MessageDigest mDigest;
56 |
57 | /** Minimum password length */
58 | private final byte mMinLength;
59 | /** Maximum password length */
60 | private final byte mMaxLength;
61 | /** Maximum number of tries before blocking */
62 | private final byte mMaxTries;
63 |
64 | /** Number of tries since last unblock */
65 | private byte mTries;
66 |
67 | /** Optional password policy */
68 | private PasswordPolicy mPolicy;
69 |
70 | /** Current password salt */
71 | private final byte[] mSalt;
72 | /** Current password hash */
73 | private final byte[] mHash;
74 |
75 | /** Transient flags */
76 | private final boolean[] mFlags;
77 | private static final byte FLAG_VALIDATED = 0;
78 | private static final byte NUM_FLAGS = 1;
79 |
80 | /** Temporary buffer */
81 | private final byte[] mTemp;
82 |
83 | /**
84 | * Full constructor
85 | *
86 | * This should be used if you want to share digest/random instances between
87 | * password instances, and it can also be used to override the default choice
88 | * of digest and random.
89 | *
90 | *
91 | * @param minLength minimum password length
92 | * @param maxLength maximum password length
93 | * @param maxTries maximum number of tries before blocking
94 | * @param clearOn memory type for validation state
95 | * @param random RNG to use for generating salts, can be shared
96 | * @param digest digest to be used for hash operations, can be shared
97 | */
98 | public PasswordHash(byte minLength, byte maxLength, byte maxTries, byte clearOn,
99 | RandomData random, MessageDigest digest) {
100 | byte hashLen = digest.getLength();
101 | // crypto instances
102 | mRandom = random;
103 | mDigest = digest;
104 | // configuration constants
105 | mMinLength = minLength;
106 | mMaxLength = maxLength;
107 | mMaxTries = maxTries;
108 | // state
109 | mTries = 0;
110 | mPolicy = null;
111 | // password data
112 | mSalt = new byte[hashLen];
113 | mHash = new byte[hashLen];
114 | // variables
115 | mFlags = JCSystem.makeTransientBooleanArray(NUM_FLAGS, clearOn);
116 | // temporary buffer
117 | mTemp = JCSystem.makeTransientByteArray((short)(2 * hashLen), clearOn);
118 | }
119 |
120 | /**
121 | * Convenience constructor
122 | *
123 | * This should be used if only one password instance is needed and the algorithms
124 | * used do not matter. The best available algorithm will be used for the digest.
125 | *
126 | *
127 | * @param minLength minimum password length
128 | * @param maxLength maximum password length
129 | * @param maxTries maximum number of tries before blocking
130 | * @param clearOn memory type for validation state
131 | */
132 | public PasswordHash(byte minLength, byte maxLength, byte maxTries, byte clearOn) {
133 | this(minLength, maxLength, maxTries, clearOn,
134 | getDefaultRandomInstance(),
135 | getDefaultDigestInstance());
136 | }
137 |
138 | /**
139 | * Get digest algorithm used for password hashing
140 | * @return a MessageDigest algorithm identifier
141 | */
142 | public byte getDigestAlgorithm() {
143 | return mDigest.getAlgorithm();
144 | }
145 |
146 | /**
147 | * Get digest length used for salt and hash
148 | * @return length of digest
149 | */
150 | public byte getDigestLength() {
151 | return mDigest.getLength();
152 | }
153 |
154 | /**
155 | * Get the current password policy
156 | * @return the policy or null
157 | */
158 | public PasswordPolicy getPasswordPolicy() {
159 | return mPolicy;
160 | }
161 |
162 | /**
163 | * Set the password policy
164 | * @param policy new policy or null
165 | */
166 | public void setPasswordPolicy(PasswordPolicy policy) {
167 | mPolicy = policy;
168 | }
169 |
170 | /**
171 | * Get the current password salt value
172 | * @param buf for output
173 | * @param off for output
174 | * @param len available in buf
175 | * @return offset after output
176 | */
177 | public short getSalt(byte[] buf, short off, short len) {
178 | short hashLen = mDigest.getLength();
179 | if(len < hashLen) {
180 | ISOException.throwIt(ISO7816.SW_UNKNOWN);
181 | }
182 | if(len > hashLen) {
183 | len = hashLen;
184 | }
185 | return Util.arrayCopyNonAtomic(buf, off, mSalt, (short)0, len);
186 | }
187 |
188 | /**
189 | * Get the current password hash value
190 | * @param buf for output
191 | * @param off for output
192 | * @param len available in buf
193 | * @return offset after output
194 | */
195 | public short getHash(byte[] buf, short off, short len) {
196 | short hashLen = mDigest.getLength();
197 | if(len < hashLen) {
198 | ISOException.throwIt(ISO7816.SW_UNKNOWN);
199 | }
200 | if(len > hashLen) {
201 | len = hashLen;
202 | }
203 | return Util.arrayCopyNonAtomic(buf, off, mHash, (short)0, len);
204 | }
205 |
206 | /**
207 | * Get number of tried remaining before blocking
208 | * @return number of tries
209 | */
210 | public byte getTriesRemaining() {
211 | return (byte)(mMaxTries - mTries);
212 | }
213 |
214 | /**
215 | * Return true if the password has been entered since last deselect/reset
216 | * @return true if validated
217 | */
218 | public boolean isValidated() {
219 | return mFlags[FLAG_VALIDATED];
220 | }
221 |
222 | /**
223 | * Reset the try counter
224 | *
225 | * Only works when validated. Should be used at a safe point after login.
226 | */
227 | public void reset() {
228 | if(mFlags[FLAG_VALIDATED]) {
229 | resetAndUnblock();
230 | }
231 | }
232 |
233 | /**
234 | * Reset the try counter and unblock
235 | *
236 | * Always works. Should be used for PUK-based recovery.
237 | */
238 | public void resetAndUnblock() {
239 | mFlags[FLAG_VALIDATED] = false;
240 | mTries = 0;
241 | }
242 |
243 | /**
244 | * Check the given password
245 | * @param buf containing password
246 | * @param off of password
247 | * @param len of password
248 | * @return true if validated
249 | */
250 | public boolean check(byte[] buf, short off, byte len) {
251 | // assume password is incorrect
252 | boolean correct;
253 | // get length of hash
254 | byte hashLen = mDigest.getLength();
255 | // compute new counter value
256 | byte newTries = (byte)(mTries + 1);
257 | // clear validated flag
258 | mFlags[FLAG_VALIDATED] = false;
259 | // check try counter
260 | if(newTries >= mMaxTries || newTries <= 0) {
261 | errorTriesRemaining();
262 | }
263 | // save try counter
264 | mTries = newTries;
265 | // pre-wipe temp buffer for paranoia
266 | wipeTemp();
267 | try {
268 | // perform the hash operation
269 | mDigest.reset();
270 | mDigest.update(mSalt, (short) 0, hashLen);
271 | mDigest.update(buf, off, len);
272 | mDigest.doFinal(null, (short) 0, (short) 0, mTemp, (short) 0);
273 | // compare hash
274 | correct = Util.arrayCompare(mHash, (short) 0, mTemp, (short) 0, hashLen) == 0;
275 | // handle correct password
276 | if(correct) {
277 | // set validated flag
278 | mFlags[FLAG_VALIDATED] = true;
279 | // reset try counter
280 | mTries = 0;
281 | }
282 | } finally {
283 | wipeTemp();
284 | }
285 | // return result
286 | return correct;
287 | }
288 |
289 | /**
290 | * Change the password
291 | * @param buf containing new password
292 | * @param off of password
293 | * @param len of password
294 | */
295 | public void update(byte[] buf, short off, byte len) {
296 | // get length of hash
297 | short hashLen = mDigest.getLength();
298 | short offHash = (short)0;
299 | short offSalt = hashLen;
300 | // check length restrictions
301 | if(len < mMinLength || len > mMaxLength) {
302 | ISOException.throwIt(ISO7816.SW_WRONG_DATA);
303 | }
304 | // check password policy
305 | if(mPolicy != null && !mPolicy.validate(buf, off, len)) {
306 | ISOException.throwIt(ISO7816.SW_WRONG_DATA);
307 | }
308 | // pre-wipe temp buffer
309 | wipeTemp();
310 | // set up the new password
311 | try {
312 | // generate new salt
313 | mRandom.generateData(mTemp, offSalt, hashLen);
314 | // compute new hash
315 | mDigest.reset();
316 | mDigest.update(mTemp, offSalt, hashLen);
317 | mDigest.update(buf, off, len);
318 | mDigest.doFinal(null, (short)0, (short)0, mTemp, offHash);
319 | // atomically copy hash and salt, also reset try counter
320 | JCSystem.beginTransaction();
321 | Util.arrayCopy(mHash, (short) 0, mTemp, offHash, hashLen);
322 | Util.arrayCopy(mSalt, (short) 0, mTemp, offSalt, hashLen);
323 | mTries = 0;
324 | JCSystem.commitTransaction();
325 | } finally {
326 | // wipe temp buffer
327 | wipeTemp();
328 | }
329 | }
330 |
331 | /**
332 | * Internal: wipe temporary buffer
333 | */
334 | private void wipeTemp() {
335 | Util.arrayFillNonAtomic(mTemp, (short)0, (short)mTemp.length, (byte)0);
336 | }
337 |
338 | /**
339 | * Internal: throw a warning exception with tries remaining
340 | */
341 | private void errorTriesRemaining() {
342 | short code = SW_PIN_TRIES_REMAINING;
343 | byte remaining = getTriesRemaining();
344 | if(remaining > 15) {
345 | remaining = 15;
346 | }
347 | code |= remaining;
348 | ISOException.throwIt(code);
349 | }
350 |
351 | /**
352 | * Return an instance with the best supported digest algorithm
353 | * @return a MessageDigest instance
354 | */
355 | public static MessageDigest getDefaultDigestInstance() {
356 | MessageDigest res = null;
357 | if(USE_SHA512 && res == null) {
358 | res = MessageDigest.getInstance(MessageDigest.ALG_SHA_512, false);
359 | }
360 | if(USE_SHA256 && res == null) {
361 | res = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
362 | }
363 | if(USE_SHA160 && res == null) {
364 | res = MessageDigest.getInstance(MessageDigest.ALG_SHA, false);
365 | }
366 | if(USE_MD5 && res == null) {
367 | res = MessageDigest.getInstance(MessageDigest.ALG_MD5, false);
368 | }
369 | return res;
370 | }
371 |
372 | /**
373 | * Return an instance with the best supported random source
374 | * @return a RandomData instance
375 | */
376 | public static RandomData getDefaultRandomInstance() {
377 | return RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
378 | }
379 |
380 | }
381 |
--------------------------------------------------------------------------------
/library-password/src/main/java/org/openjavacard/lib/password/PasswordPolicy.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.password;
2 |
3 | /**
4 | * Interface for password policy objects
5 | */
6 | public interface PasswordPolicy {
7 |
8 | /**
9 | * Validate the given password for compliance
10 | *
11 | *
12 | * @param buf containing password
13 | * @param off of password
14 | * @param len of password
15 | * @return true if compliant
16 | */
17 | boolean validate(byte[] buf, short off, short len);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/library-rsa/src/main/java/org/openjavacard/lib/rsa/MGF1.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.rsa;
21 |
22 | import javacard.framework.JCSystem;
23 | import javacard.framework.Util;
24 | import javacard.security.CryptoException;
25 | import javacard.security.MessageDigest;
26 |
27 | /**
28 | * Implementation of PKCS #1 v2.1 MGF-1
29 | *
30 | * This is a mask generation function used by OAEP and PSS.
31 | *
32 | * It can be used with any message digest, usually SHA-1 or SHA-256.
33 | */
34 | public class MGF1 {
35 |
36 | private static final short short0 = (short)0;
37 |
38 | /** Internal hash */
39 | private final MessageDigest mHash;
40 | /** Temporary buffer */
41 | private final byte[] mTemp;
42 |
43 | /**
44 | * Creates a new MGF1 mask generator
45 | *
46 | * The generator will use the provided hash.
47 | *
48 | *
49 | * @param hash to use for mask generation
50 | */
51 | public MGF1(MessageDigest hash) {
52 | mHash = hash;
53 | mTemp = JCSystem.makeTransientByteArray(mHash.getLength(), JCSystem.CLEAR_ON_DESELECT);
54 | }
55 |
56 | /**
57 | * Combined mask generation function and XOR (MGF1-XOR)
58 | *
59 | * This is equivalent to generating a mask using MGF1
60 | * and applying it to the output buffer using XOR.
61 | *
62 | * Doing this in one step saves an additional buffer.
63 | *
64 | *
65 | * @param seed buffer for mask generation
66 | * @param seedOff offset of seed in buffer
67 | * @param seedLen length of seed in buffer
68 | * @param out buffer for generated mask
69 | * @param outOff offset of output in buffer
70 | * @param outLen length of output in buffer
71 | * @throws CryptoException on internal errors
72 | */
73 | public void applyMask(byte[] seed, short seedOff, short seedLen, byte[] out, short outOff, short outLen)
74 | throws CryptoException {
75 | // length of hash (octets)
76 | byte hLen = mHash.getLength();
77 | // determine number of rounds required to fill OUT
78 | short rounds = shortCeil(outLen, hLen);
79 | // iteration: remaining bytes for current round
80 | short outRemaining = outLen;
81 | // iteration: output position for current round
82 | short outPosition = outOff;
83 | // reset the hash
84 | mHash.reset();
85 | // run rounds
86 | for(short counter = 0; counter < rounds; counter++) {
87 | // compute number of bytes for current round
88 | short outBytes = shortMin(hLen, outRemaining);
89 | // update the counter
90 | mTemp[0] = 0;
91 | mTemp[1] = 0;
92 | mTemp[2] = (byte)((counter >> 8) & 0xFF);
93 | mTemp[3] = (byte)((counter >> 0) & 0xFF);
94 | // compute the round hash from seed and counter
95 | mHash.update(seed, seedOff, seedLen);
96 | mHash.doFinal(mTemp, short0, (short) 4, mTemp, short0);
97 | // xor round hash to output array
98 | xorInPlace(out, outPosition, mTemp, short0, outBytes);
99 | // advance iteration
100 | outPosition += outBytes;
101 | outRemaining = shortMax((short)0, (short)(outRemaining - hLen));
102 | }
103 | // burn the evidence
104 | Util.arrayFillNonAtomic(mTemp, short0, (short) mTemp.length, (byte) 0);
105 | }
106 |
107 | private static short shortMin(short a, short b) {
108 | if(a < b) {
109 | return a;
110 | } else {
111 | return b;
112 | }
113 | }
114 |
115 | private static short shortMax(short a, short b) {
116 | if(a > b) {
117 | return a;
118 | } else {
119 | return b;
120 | }
121 | }
122 |
123 | /**
124 | * Implementation of ceiling division for short integers
125 | *
126 | * @param dividend
127 | * @param divisor
128 | * @return ceiled quotient
129 | */
130 | private static short shortCeil(short dividend, short divisor) {
131 | short i1 = (short)(dividend+(divisor-1));
132 | return (short)(i1 / divisor);
133 | }
134 |
135 | /**
136 | * XOR a buffer onto another
137 | *
138 | * @param out
139 | * @param outOffset
140 | * @param in
141 | * @param inOffset
142 | * @param length
143 | */
144 | private static void xorInPlace(byte[] out, short outOffset, byte[] in, short inOffset, short length) {
145 | for(short i = 0; i < length; i++) {
146 | short inCur = (short)(inOffset + i);
147 | short outCur = (short)(outOffset + i);
148 | out[outCur] ^= in[inCur];
149 | }
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/library-string/src/main/java/org/openjavacard/lib/string/ASCII.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.string;
21 |
22 | public class ASCII {
23 |
24 | public static boolean isnull(byte c) {
25 | return c == 0;
26 | }
27 |
28 | public static boolean isascii(byte c) {
29 | return (c >= 0);
30 | }
31 |
32 | public static boolean isalnum(byte c) {
33 | return ((c >= 0x30) && (c <= 0x39))
34 | || ((c >= 0x41) && (c <= 0x5A))
35 | || ((c >= 0x61) && (c <= 0x7A));
36 | }
37 |
38 | public static boolean isalpha(byte c) {
39 | return ((c >= 0x41) && (c <= 0x5A))
40 | || ((c >= 0x61) && (c <= 0x7A));
41 | }
42 |
43 | public static boolean isblank(byte c) {
44 | return (c == 0x09) || (c == 0x20);
45 | }
46 |
47 | public static boolean iscntrl(byte c) {
48 | return (c < 0x20) || (c == 0x7F);
49 | }
50 |
51 | public static boolean isdigit(byte c) {
52 | return (c >= 0x30) && (c <= 0x39);
53 | }
54 |
55 | public static boolean isgraph(byte c) {
56 | return (c >= 0x21) && (c <= 0x7E);
57 | }
58 |
59 | public static boolean islower(byte c) {
60 | return (c >= 0x61) && (c <= 0x7A);
61 | }
62 |
63 | public static boolean isprint(byte c) {
64 | return (c >= 0x20) && (c <= 0x7F);
65 | }
66 |
67 | public static boolean ispunct(byte c) {
68 | return isgraph(c) && !isalnum(c);
69 | }
70 |
71 | public static boolean isspace(byte c) {
72 | return (c == 0x20) || ((c >= 0x09) && (c <= 0x0D));
73 | }
74 |
75 | public static boolean isupper(byte c) {
76 | return (c >= 0x41) && (c <= 0x5A);
77 | }
78 |
79 | public static boolean isxdigit(byte c) {
80 | return ((c >= 0x30) && (c <= 0x39))
81 | || ((c >= 0x41) && (c <= 0x46))
82 | || ((c >= 0x61) && (c <= 0x66));
83 | }
84 |
85 | public static byte tolower(byte c) {
86 | if(isupper(c)) {
87 | return (byte)(c | 32);
88 | }
89 | return c;
90 | }
91 |
92 | public static byte toupper(byte c) {
93 | if(islower(c)) {
94 | return (byte)(c & 0x5F);
95 | }
96 | return c;
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/library-string/src/main/java/org/openjavacard/lib/string/StringStatistics.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.string;
21 |
22 | import javacard.framework.JCSystem;
23 |
24 | public class StringStatistics {
25 |
26 | public static final byte NUM_STATS = 14;
27 |
28 | public static final byte STAT_NULL = 0;
29 | public static final byte STAT_ASCII = 1;
30 | public static final byte STAT_ALNUM = 2;
31 | public static final byte STAT_ALPHA = 3;
32 | public static final byte STAT_BLANK = 4;
33 | public static final byte STAT_CNTRL = 5;
34 | public static final byte STAT_DIGIT = 6;
35 | public static final byte STAT_GRAPH = 7;
36 | public static final byte STAT_LOWER = 8;
37 | public static final byte STAT_PRINT = 9;
38 | public static final byte STAT_PUNCT = 10;
39 | public static final byte STAT_SPACE = 11;
40 | public static final byte STAT_UPPER = 12;
41 | public static final byte STAT_XDIGIT = 13;
42 |
43 | private final short[] mStatistics;
44 |
45 | public StringStatistics() {
46 | mStatistics = new short[NUM_STATS];
47 | }
48 |
49 | public StringStatistics(byte clearOn) {
50 | mStatistics = JCSystem.makeTransientShortArray(NUM_STATS, clearOn);
51 | }
52 |
53 | public short get(byte statistic) {
54 | return mStatistics[statistic];
55 | }
56 |
57 | public void reset() {
58 | fillShortArray(mStatistics, (short)0, (short)mStatistics.length, (short)0);
59 | }
60 |
61 | public void update(byte[] buf, short off, short len) {
62 | reset();
63 |
64 | short lim = (short)(off + len);
65 | for(short cur = off; cur < lim; cur++) {
66 | byte chr = buf[cur];
67 | if(ASCII.isnull(chr)) {
68 | mStatistics[STAT_NULL]++;
69 | }
70 | if(ASCII.isascii(chr)) {
71 | mStatistics[STAT_ASCII]++;
72 | }
73 | if(ASCII.isalnum(chr)) {
74 | mStatistics[STAT_ALNUM]++;
75 | }
76 | if(ASCII.isalpha(chr)) {
77 | mStatistics[STAT_ALPHA]++;
78 | }
79 | if(ASCII.isblank(chr)) {
80 | mStatistics[STAT_BLANK]++;
81 | }
82 | if(ASCII.iscntrl(chr)) {
83 | mStatistics[STAT_CNTRL]++;
84 | }
85 | if(ASCII.isdigit(chr)) {
86 | mStatistics[STAT_DIGIT]++;
87 | }
88 | if(ASCII.isgraph(chr)) {
89 | mStatistics[STAT_GRAPH]++;
90 | }
91 | if(ASCII.islower(chr)) {
92 | mStatistics[STAT_LOWER]++;
93 | }
94 | if(ASCII.isprint(chr)) {
95 | mStatistics[STAT_PRINT]++;
96 | }
97 | if(ASCII.ispunct(chr)) {
98 | mStatistics[STAT_PUNCT]++;
99 | }
100 | if(ASCII.isspace(chr)) {
101 | mStatistics[STAT_SPACE]++;
102 | }
103 | if(ASCII.isupper(chr)) {
104 | mStatistics[STAT_UPPER]++;
105 | }
106 | if(ASCII.isxdigit(chr)) {
107 | mStatistics[STAT_XDIGIT]++;
108 | }
109 | }
110 | }
111 |
112 | private static void fillShortArray(short[] array, short off, short len, short value) {
113 | short lim = (short)(off + len);
114 | for(short cur = off; cur < lim; cur++) {
115 | array[cur] = value;
116 | }
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/library-string/src/main/java/org/openjavacard/lib/string/StringWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * openjavacard-libraries: Class libraries for JavaCard
3 | * Copyright (C) 2018 Ingo Albrecht
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library 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 GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with this library; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | package org.openjavacard.lib.string;
21 |
22 | public class StringWriter {
23 |
24 | private final short mMaxChunks;
25 |
26 | private final short[] mVars;
27 | /** Number of transient variables */
28 | private static final byte NUM_VAR = 3;
29 | /** Variable: maximum allowed length */
30 | private static final byte VAR_MAX_LENGTH = 0;
31 | /** Variable: current running length */
32 | private static final byte VAR_LENGTH = 1;
33 | /** Variable: current index */
34 | private static final byte VAR_INDEX = 2;
35 |
36 | private final Object[] mBufStk;
37 | private final short[] mOffStk;
38 | private final short[] mLenStk;
39 |
40 | public StringWriter(short maxChunks) {
41 | mMaxChunks = maxChunks;
42 | mVars = new short[NUM_VAR];
43 | mBufStk = new Object[maxChunks];
44 | mOffStk = new short[maxChunks];
45 | mLenStk = new short[maxChunks];
46 | }
47 |
48 | void begin(short maxLength) {
49 | mVars[VAR_MAX_LENGTH] = maxLength;
50 | mVars[VAR_LENGTH] = 0;
51 | mVars[VAR_INDEX] = 0;
52 | }
53 |
54 | short finish(byte[] buf, short off, short len) {
55 | return 0;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/library-tlv/src/main/java/org/openjavacard/lib/tlv/TLVBuilder.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.tlv;
2 |
3 | import org.openjavacard.lib.ber.BERHandler;
4 | import org.openjavacard.lib.ber.BERSource;
5 |
6 | public class TLVBuilder implements BERHandler {
7 |
8 | Object[] mObjs;
9 | private static final short OBJ_ROOT = 0;
10 | private static final short OBJ_CURRENT = 1;
11 | private static final short NUM_OBJS = 2;
12 |
13 | public TLVBuilder() {
14 | }
15 |
16 | private boolean handle(BERSource source, byte depth, TLVNode node) {
17 | if(depth == 0) {
18 | mObjs[OBJ_ROOT] = node;
19 | }
20 | return false;
21 | }
22 |
23 | public boolean handlePrimitive(BERSource source, byte depth, short tag,
24 | byte[] dataBuf, short dataOff, short dataLen) {
25 | TLVPrimitive node = new TLVPrimitive(tag, dataLen);
26 | node.updateValue(dataBuf, dataOff, dataLen);
27 | return handle(source, depth, node);
28 | }
29 |
30 | public boolean handleBeginConstructed(BERSource source, byte depth, short tag) {
31 | TLVConstructed node = new TLVConstructed(tag);
32 | return handle(source, depth, node);
33 | }
34 |
35 | public boolean handleFinishConstructed(BERSource source, byte depth, short tag) {
36 | return true;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/library-tlv/src/main/java/org/openjavacard/lib/tlv/TLVConstructed.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.tlv;
2 |
3 | public class TLVConstructed extends TLVNode {
4 |
5 | private TLVNode[] mChildren;
6 |
7 | public TLVConstructed(short tag) {
8 | super(tag);
9 | }
10 |
11 | public final short getLength() {
12 | return 0;
13 | }
14 |
15 | public final short getChildCount() {
16 | return (short)mChildren.length;
17 | }
18 |
19 | public TLVNode getChild(short index) {
20 | return mChildren[index];
21 | }
22 |
23 | public boolean hasChild(TLVNode child) {
24 | return false;
25 | }
26 |
27 | public boolean removeChild(TLVNode child) {
28 | return false;
29 | }
30 |
31 | public short insertChild(TLVNode child, short position) {
32 | return 0;
33 | }
34 |
35 | public short prependChild(TLVNode child) {
36 | return 0;
37 | }
38 |
39 | public short appendChild(TLVNode child) {
40 | return 0;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/library-tlv/src/main/java/org/openjavacard/lib/tlv/TLVNode.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.tlv;
2 |
3 | public abstract class TLVNode {
4 |
5 | private short mTag;
6 |
7 | protected TLVNode(short tag) {
8 | mTag = tag;
9 | }
10 |
11 | public final short getTag() {
12 | return mTag;
13 | }
14 |
15 | public final void setTag(short tag) {
16 | mTag = tag;
17 | }
18 |
19 | public final boolean isConstructed() {
20 | return this instanceof TLVConstructed;
21 | }
22 |
23 | public final boolean isPrimitive() {
24 | return this instanceof TLVPrimitive;
25 | }
26 |
27 | public abstract short getLength();
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/library-tlv/src/main/java/org/openjavacard/lib/tlv/TLVPrimitive.java:
--------------------------------------------------------------------------------
1 | package org.openjavacard.lib.tlv;
2 |
3 | import javacard.framework.Util;
4 |
5 | public class TLVPrimitive extends TLVNode {
6 |
7 | private short mLength;
8 | private byte[] mValue;
9 |
10 | public TLVPrimitive(short tag, short len) {
11 | super(tag);
12 | mLength = len;
13 | if(len > 0) {
14 | mValue = new byte[len];
15 | }
16 | }
17 |
18 | public TLVPrimitive(short tag) {
19 | super(tag);
20 | }
21 |
22 | public final short getLength() {
23 | return mLength;
24 | }
25 |
26 | public short readValue(byte[] buf, short off, short maxLen) {
27 | return Util.arrayCopyNonAtomic(mValue, (short)0, buf, off, maxLen);
28 | }
29 |
30 | public short updateValue(byte[] buf, short off, short len) {
31 | return Util.arrayCopyNonAtomic(buf, off, mValue, (short)0, len);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/openjavacard-libraries.iml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/uninstall.script:
--------------------------------------------------------------------------------
1 |
2 |
3 | gp-delete --related \
4 | d27600017710011001 \
5 | d27600017710011021 \
6 | d27600017710011020 \
7 | d276000177100210010001 \
8 | d276000177100210210001 \
9 | d276000177100210200001 \
10 | d276000177100310050001 \
11 | d276000177100310070001 \
12 | d276000177100310030001 \
13 | d276000177100310020001 \
14 | d276000177100310010001
15 |
16 |
--------------------------------------------------------------------------------