├── .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 | [![Build Status](https://travis-ci.org/OpenJavaCard/openjavacard-libraries.svg?branch=master)](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 | --------------------------------------------------------------------------------