├── .gitignore ├── LICENSE ├── README.md ├── build.xml ├── demo └── templates │ ├── input_applet_files │ └── OCUnitTests.java │ ├── template_profiler_applet │ ├── PM.java │ └── PMC.java │ └── template_profiler_client │ ├── build.xml │ ├── manifest.mf │ ├── nbproject │ ├── build-impl.xml │ ├── genfiles.properties │ ├── project.properties │ └── project.xml │ └── src │ └── jcprofiler │ ├── CardManager.java │ ├── JCProfiler_client.java │ ├── PMC.java │ └── PerfTests.java ├── dist └── README.TXT ├── lib └── commons-cli-1.3.1.jar ├── nbproject ├── build-impl.xml ├── genfiles.properties ├── project.properties └── project.xml └── src └── opencryptoutils ├── JCProfiler.java ├── PerfCodeConfig.java └── PerfCodeGenerator.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | /dist/*.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | # Javadoc 25 | /dist/javadoc/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JCProfiler 2 | Performance profiler for JavaCard code 3 | 4 | The performance profiling of JavaCard applet code is a notoriously difficult task. As the card environment is build to protect the stored and processed secrets against an attacker with direct physical access, it is difficult to obtain a precise timing trace of the executed code on the granularity of separate methods or even lines of code. To the best of our knowledge, there is no open-source performance profiler available for the JavaCard platform. So we decided to build one. 5 | 6 | The profiler is based on the following idea: The source code of an applet is extended with numerous additional lines of code called "performance traps" capable to prematurely interrupt the applet's execution if the condition match the controlling _trapID_ variable. The trap can be inserted after every single line of an applet's original code to achieved the finest profiling granularity if required. The client-side testing application is then repeatedly executed with the different value of controlling _trapID_ variable. As a result increasingly larger chunk of applet's code is executed before interrupted on the corresponding trap. The client-side time measurements are collected and processed to compute the time difference between the two consecutive traps - resulting in the time required to execute a block of an original code between these two traps. 7 | 8 | The usage is simple: 9 | 1. Developer signalizes interseting parts of code to profile by insertion of fixed strings 10 | 2. JCProfiler tool automatically generates all necessary testing code 11 | 3. Developer sets proper applet AID, applet CLA and APDU command which will trigger inspected operation 12 | 4. Performance measurement client is executed to collect all timing measurements 13 | 5. Applet source code is annotted with the extracted timings 14 | 15 | Take a look at short tutorial (thx Matej Evin): 16 | 17 | [![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/4eYKty6G4fg/0.jpg)](https://www.youtube.com/watch?v=4eYKty6G4fg) 18 | 19 | Please read [wiki](https://github.com/petrs/JCProfiler/wiki) for all details. 20 | 21 | ## Simple example 22 | The code below was automatically transformed and profiled after insertion of perfromance traps 'PM.check(PM.TRAP...'. Time in milliseconds provides time necessary to reach particular trap from the previous one. A name of card and unique profiling session ID in braces (gd60,1500968219581). 23 | 24 | ```` java 25 | private short multiplication_x_KA(Bignat scalar, byte[] outBuffer, short outBufferOffset) { 26 | PM.check(PM.TRAP_ECPOINT_MULT_X_1); // 40 ms (gd60,1500968219581) 27 | priv.setS(scalar.as_byte_array(), (short) 0, scalar.length()); 28 | PM.check(PM.TRAP_ECPOINT_MULT_X_2); // 12 ms (gd60,1500968219581) 29 | 30 | keyAgreement.init(priv); 31 | PM.check(PM.TRAP_ECPOINT_MULT_X_3); // 120 ms (gd60,1500968219581) 32 | 33 | short len = this.getW(point_arr1, (short) 0); 34 | PM.check(PM.TRAP_ECPOINT_MULT_X_4); // 9 ms (gd60,1500968219581) 35 | len = keyAgreement.generateSecret(point_arr1, (short) 0, len, outBuffer, outBufferOffset); 36 | PM.check(PM.TRAP_ECPOINT_MULT_X_5); // 186 ms (gd60,1500968219581) 37 | 38 | return COORD_SIZE; 39 | } 40 | ```` 41 | 42 | 43 | ### Satisfied users so far 44 | * [JCMathLib](https://github.com/OpenCryptoProject/JCMathLib) library for Bignat and ECPoint operations 45 | * [AEonJC](https://github.com/palkrajesh/AEonJC) implementation of ACORN, AEGIS, ASCON, CLOC, and MORUS authenticated encryption functions 46 | * You? Give it a try - love to hear the feedback :) 47 | 48 | ### Future work 49 | * Proper ant compilation, travis... 50 | * Averaging from multiple results instead of single run 51 | * Better analysis of applet and detection of developer-provided info 52 | * Automatic insertion of all performance traps (no requirement for manual templates) 53 | * Code improvements (a lot of hardcoded strings etc. ) 54 | 55 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Builds, tests, and runs the project JCProfiler. 12 | 13 | 73 | 74 | -------------------------------------------------------------------------------- /demo/templates/input_applet_files/OCUnitTests.java: -------------------------------------------------------------------------------- 1 | package opencrypto.jcmathlib; 2 | 3 | 4 | import javacard.framework.APDU; 5 | import javacard.framework.Applet; 6 | import javacard.framework.CardRuntimeException; 7 | import javacard.framework.ISO7816; 8 | import javacard.framework.ISOException; 9 | import javacard.framework.JCSystem; 10 | import javacard.framework.PINException; 11 | import javacard.framework.SystemException; 12 | import javacard.framework.TransactionException; 13 | import javacard.framework.Util; 14 | import javacard.security.CryptoException; 15 | 16 | /** 17 | * 18 | * @author Vasilios Mavroudis and Petr Svenda 19 | */ 20 | public class OCUnitTests extends Applet { 21 | // Main instruction CLAss 22 | public final static byte CLA_OC_UT = (byte) 0xB0; // OpenCrypto Unit Tests 23 | 24 | // INStructions 25 | // Card Management 26 | public final static byte INS_SETUP = (byte) 0x01; 27 | public final static byte INS_STATUS = (byte) 0x02; 28 | public final static byte INS_CLEANUP = (byte) 0x03; 29 | //public final static byte INS_TESTRSAMULT = (byte) 0x04; 30 | public final static byte INS_PERF_SETSTOP = (byte) 0x05; 31 | public final static byte INS_FREEMEMORY = (byte) 0x06; 32 | public final static byte INS_GET_ALLOCATOR_STATS = (byte) 0x07; 33 | 34 | //BigNatural and BigInteger Operations 35 | public final static byte INS_INT_STR = (byte) 0x09; 36 | public final static byte INS_INT_ADD = (byte) 0x10; 37 | public final static byte INS_INT_SUB = (byte) 0x11; 38 | public final static byte INS_INT_MUL = (byte) 0x12; 39 | public final static byte INS_INT_DIV = (byte) 0x13; 40 | //public final static byte INS_INT_EXP = (byte) 0x14; 41 | public final static byte INS_INT_MOD = (byte) 0x15; 42 | 43 | public final static byte INS_BN_STR = (byte) 0x20; 44 | public final static byte INS_BN_ADD = (byte) 0x21; 45 | public final static byte INS_BN_SUB = (byte) 0x22; 46 | public final static byte INS_BN_MUL = (byte) 0x23; 47 | public final static byte INS_BN_EXP = (byte) 0x24; 48 | public final static byte INS_BN_MOD = (byte) 0x25; 49 | public final static byte INS_BN_SQRT = (byte) 0x26; 50 | public final static byte INS_BN_MUL_SCHOOL = (byte) 0x27; 51 | 52 | public final static byte INS_BN_ADD_MOD = (byte) 0x30; 53 | public final static byte INS_BN_SUB_MOD = (byte) 0x31; 54 | public final static byte INS_BN_MUL_MOD = (byte) 0x32; 55 | public final static byte INS_BN_EXP_MOD = (byte) 0x33; 56 | public final static byte INS_BN_INV_MOD = (byte) 0x34; 57 | public final static byte INS_BN_POW2_MOD = (byte) 0x35; 58 | 59 | //EC Operations 60 | public final static byte INS_EC_GEN = (byte) 0x40; 61 | public final static byte INS_EC_DBL = (byte) 0x41; 62 | public final static byte INS_EC_ADD = (byte) 0x42; 63 | public final static byte INS_EC_MUL = (byte) 0x43; 64 | public final static byte INS_EC_NEG = (byte) 0x44; 65 | public final static byte INS_EC_SETCURVE_G = (byte) 0x45; 66 | public final static byte INS_EC_COMPARE = (byte) 0x46; 67 | 68 | 69 | static boolean bIsSimulator = false; 70 | static boolean bTEST_256b_CURVE = true; 71 | static boolean bTEST_512b_CURVE = false; 72 | 73 | short[] m_memoryInfo = null; 74 | short m_memoryInfoOffset = 0; 75 | 76 | ECConfig m_ecc = null; 77 | 78 | ECCurve m_testCurve = null; 79 | 80 | ECPoint m_testPoint1 = null; 81 | ECPoint m_testPoint2 = null; 82 | 83 | byte[] m_customG = null; 84 | ECCurve m_testCurveCustom = null; 85 | ECPoint m_testPointCustom = null; 86 | 87 | Bignat m_testBN1; 88 | Bignat m_testBN2; 89 | Bignat m_testBN3; 90 | 91 | Integer m_testINT1; 92 | Integer m_testINT2; 93 | 94 | public OCUnitTests() { 95 | m_memoryInfo = new short[(short) (7 * 3)]; // Contains RAM and EEPROM memory required for basic library objects 96 | m_memoryInfoOffset = snapshotAvailableMemory((short) 1, m_memoryInfo, m_memoryInfoOffset); 97 | if (bTEST_256b_CURVE) { 98 | m_ecc = new ECConfig((short) 256); 99 | } 100 | if (bTEST_512b_CURVE) { 101 | m_ecc = new ECConfig((short) 512); 102 | } 103 | m_memoryInfoOffset = snapshotAvailableMemory((short) 2, m_memoryInfo, m_memoryInfoOffset); 104 | 105 | 106 | // Pre-allocate test objects (no new allocation for every tested operation) 107 | if (bTEST_256b_CURVE) { 108 | m_testCurve = new ECCurve(false, SecP256r1.p, SecP256r1.a, SecP256r1.b, SecP256r1.G, SecP256r1.r, m_ecc); 109 | m_memoryInfoOffset = snapshotAvailableMemory((short) 3, m_memoryInfo, m_memoryInfoOffset); 110 | // m_testCurveCustom and m_testPointCustom will have G occasionally changed so we need separate ECCurve 111 | m_customG = new byte[(short) SecP256r1.G.length]; 112 | Util.arrayCopyNonAtomic(SecP256r1.G, (short) 0, m_customG, (short) 0, (short) SecP256r1.G.length); 113 | m_testCurveCustom = new ECCurve(false, SecP256r1.p, SecP256r1.a, SecP256r1.b, m_customG, SecP256r1.r, m_ecc); 114 | } 115 | if (bTEST_512b_CURVE) { 116 | m_testCurve = new ECCurve(false, P512r1.p, P512r1.a, P512r1.b, P512r1.G, P512r1.r, m_ecc); 117 | // m_testCurveCustom and m_testPointCustom will have G occasionally changed so we need separate ECCurve 118 | m_customG = new byte[(short) P512r1.G.length]; 119 | Util.arrayCopyNonAtomic(P512r1.G, (short) 0, m_customG, (short) 0, (short) P512r1.G.length); 120 | m_testCurveCustom = new ECCurve(false, P512r1.p, P512r1.a, P512r1.b, m_customG, P512r1.r, m_ecc); 121 | } 122 | 123 | m_memoryInfoOffset = snapshotAvailableMemory((short) 5, m_memoryInfo, m_memoryInfoOffset); 124 | m_testPoint1 = new ECPoint(m_testCurve, m_ecc); 125 | m_memoryInfoOffset = snapshotAvailableMemory((short) 6, m_memoryInfo, m_memoryInfoOffset); 126 | m_testPoint2 = new ECPoint(m_testCurve, m_ecc); 127 | m_testPointCustom = new ECPoint(m_testCurveCustom, m_ecc); 128 | 129 | // Testing Bignat objects used in tests 130 | m_memoryInfoOffset = snapshotAvailableMemory((short) 7, m_memoryInfo, m_memoryInfoOffset); 131 | byte memoryType = JCSystem.MEMORY_TYPE_TRANSIENT_RESET; 132 | m_testBN1 = new Bignat(m_ecc.MAX_BIGNAT_SIZE, memoryType, m_ecc); 133 | m_memoryInfoOffset = snapshotAvailableMemory((short) 8, m_memoryInfo, m_memoryInfoOffset); 134 | m_testBN2 = new Bignat(m_ecc.MAX_BIGNAT_SIZE, memoryType, m_ecc); 135 | m_testBN3 = new Bignat(m_ecc.MAX_BIGNAT_SIZE, memoryType, m_ecc); 136 | 137 | short intLen = 4; 138 | m_testINT1 = new Integer(intLen, m_ecc); 139 | m_testINT2 = new Integer(intLen, m_ecc); 140 | } 141 | 142 | public static void install(byte[] bArray, short bOffset, byte bLength) { 143 | // GP-compliant JavaCard applet registration 144 | //new UnitTests().register(bArray, (short) (bOffset + 1), bArray[bOffset]); 145 | if (bLength == 0) { 146 | bIsSimulator = true; 147 | } 148 | new OCUnitTests().register(); 149 | } 150 | 151 | public boolean select() { 152 | updateAfterReset(); 153 | return true; 154 | } 155 | public void process(APDU apdu) { 156 | byte[] apdubuf = apdu.getBuffer(); 157 | 158 | // Good practice: Return 9000 on SELECT 159 | if (selectingApplet()) { 160 | return; 161 | } 162 | 163 | // Check CLA byte 164 | if (apdubuf[ISO7816.OFFSET_CLA] != CLA_OC_UT) { 165 | ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); 166 | } 167 | 168 | // Process Input 169 | short dataLen = apdu.setIncomingAndReceive(); // returns length of data field 170 | 171 | try { 172 | switch (apdubuf[ISO7816.OFFSET_INS]) { 173 | case INS_CLEANUP: 174 | m_ecc.unlockAll(); 175 | break; 176 | case INS_FREEMEMORY: 177 | if (!bIsSimulator) { 178 | JCSystem.requestObjectDeletion(); 179 | } 180 | break; 181 | case INS_PERF_SETSTOP: 182 | PM.m_perfStop = Util.makeShort(apdubuf[ISO7816.OFFSET_CDATA], apdubuf[(short) (ISO7816.OFFSET_CDATA + 1)]); 183 | break; 184 | case INS_GET_ALLOCATOR_STATS: 185 | short offset = 0; 186 | Util.setShort(apdubuf, offset, m_ecc.memAlloc.getAllocatedInRAM()); 187 | offset += 2; 188 | Util.setShort(apdubuf, offset, m_ecc.memAlloc.getAllocatedInEEPROM()); 189 | offset += 2; 190 | for (short i = 0; i < (short) m_memoryInfo.length; i++) { 191 | Util.setShort(apdubuf, offset, m_memoryInfo[i]); 192 | offset += 2; 193 | } 194 | apdu.setOutgoingAndSend((short) 0, offset); 195 | break; 196 | 197 | //============================================================== 198 | case INS_EC_GEN: 199 | test_EC_GEN(apdu); 200 | break; 201 | case INS_EC_SETCURVE_G: 202 | test_EC_SETCURVE_G(apdu, dataLen); 203 | break; 204 | case INS_EC_DBL: 205 | test_EC_DBL(apdu); 206 | break; 207 | 208 | case INS_EC_ADD: 209 | test_EC_ADD(apdu); 210 | break; 211 | 212 | case INS_EC_MUL: 213 | test_EC_MUL(apdu); 214 | break; 215 | 216 | case INS_EC_NEG: 217 | test_EC_NEG(apdu); 218 | break; 219 | 220 | case INS_EC_COMPARE: 221 | test_EC_COMPARE(apdu); 222 | break; 223 | 224 | //============================================================== 225 | case INS_BN_STR: 226 | test_BN_STR(apdu, dataLen); 227 | break; 228 | 229 | case INS_BN_ADD: 230 | test_BN_ADD(apdu, dataLen); 231 | break; 232 | 233 | case INS_BN_SUB: 234 | test_BN_SUB(apdu, dataLen); 235 | break; 236 | 237 | case INS_BN_MUL: 238 | test_BN_MUL(apdu, dataLen, true); 239 | break; 240 | case INS_BN_MUL_SCHOOL: 241 | test_BN_MUL(apdu, dataLen, false); 242 | break; 243 | 244 | case INS_BN_EXP: 245 | test_BN_EXP(apdu, dataLen); 246 | break; 247 | case INS_BN_SQRT: 248 | test_BN_SQRT(apdu, dataLen); 249 | break; 250 | 251 | case INS_BN_MOD: 252 | test_BN_MOD(apdu, dataLen); 253 | break; 254 | 255 | case INS_BN_ADD_MOD: 256 | test_BN_ADD_MOD(apdu, dataLen); 257 | break; 258 | 259 | case INS_BN_SUB_MOD: 260 | test_BN_SUB_MOD(apdu, dataLen); 261 | break; 262 | 263 | case INS_BN_MUL_MOD: 264 | test_BN_MUL_MOD(apdu, dataLen); 265 | break; 266 | 267 | case INS_BN_EXP_MOD: 268 | test_BN_EXP_MOD(apdu, dataLen); 269 | break; 270 | 271 | case INS_BN_POW2_MOD: 272 | test_BN_POW2_MOD(apdu, dataLen); 273 | break; 274 | 275 | case INS_BN_INV_MOD: 276 | test_BN_INV_MOD(apdu, dataLen); 277 | break; 278 | 279 | // --------------------------------------- 280 | case INS_INT_STR: 281 | test_INT_STR(apdu, dataLen); 282 | break; 283 | 284 | case INS_INT_ADD: 285 | test_INT_ADD(apdu, dataLen); 286 | break; 287 | 288 | case INS_INT_SUB: 289 | test_INT_SUB(apdu, dataLen); 290 | break; 291 | 292 | case INS_INT_MUL: 293 | test_INT_MUL(apdu, dataLen); 294 | break; 295 | 296 | case INS_INT_DIV: 297 | test_INT_DIV(apdu, dataLen); 298 | break; 299 | 300 | //case (byte) Configuration.INS_INT_EXP: 301 | // test_INT_EXP(apdu, dataLen); 302 | // break; 303 | case INS_INT_MOD: 304 | test_INT_MOD(apdu, dataLen); 305 | break; 306 | 307 | default: 308 | // good practice: If you don't know the INStruction, say so: 309 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); 310 | } 311 | // Capture all reasonable exceptions and change into readable ones (instead of 0x6f00) 312 | } catch (ISOException e) { 313 | throw e; // Our exception from code, just re-emit 314 | } catch (ArrayIndexOutOfBoundsException e) { 315 | ISOException.throwIt(ReturnCodes.SW_ArrayIndexOutOfBoundsException); 316 | } catch (ArithmeticException e) { 317 | ISOException.throwIt(ReturnCodes.SW_ArithmeticException); 318 | } catch (ArrayStoreException e) { 319 | ISOException.throwIt(ReturnCodes.SW_ArrayStoreException); 320 | } catch (NullPointerException e) { 321 | ISOException.throwIt(ReturnCodes.SW_NullPointerException); 322 | } catch (NegativeArraySizeException e) { 323 | ISOException.throwIt(ReturnCodes.SW_NegativeArraySizeException); 324 | } catch (CryptoException e) { 325 | ISOException.throwIt((short) (ReturnCodes.SW_CryptoException_prefix | e.getReason())); 326 | } catch (SystemException e) { 327 | ISOException.throwIt((short) (ReturnCodes.SW_SystemException_prefix | e.getReason())); 328 | } catch (PINException e) { 329 | ISOException.throwIt((short) (ReturnCodes.SW_PINException_prefix | e.getReason())); 330 | } catch (TransactionException e) { 331 | ISOException.throwIt((short) (ReturnCodes.SW_TransactionException_prefix | e.getReason())); 332 | } catch (CardRuntimeException e) { 333 | ISOException.throwIt((short) (ReturnCodes.SW_CardRuntimeException_prefix | e.getReason())); 334 | } catch (Exception e) { 335 | ISOException.throwIt(ReturnCodes.SW_Exception); 336 | } 337 | 338 | } 339 | 340 | 341 | final short snapshotAvailableMemory(short tag, short[] buffer, short bufferOffset) { 342 | buffer[bufferOffset] = tag; 343 | buffer[(short) (bufferOffset + 1)] = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET); 344 | buffer[(short) (bufferOffset + 2)] = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT); 345 | return (short) (bufferOffset + 3); 346 | } 347 | 348 | 349 | void test_EC_GEN(APDU apdu) { 350 | byte[] apdubuf = apdu.getBuffer(); 351 | 352 | PM.check(PMC.TRAP_EC_GEN_0); 353 | m_testPoint1.randomize(); 354 | PM.check(PMC.TRAP_EC_GEN_0); 355 | 356 | short len = m_testPoint1.getW(apdubuf, (short) 0); 357 | PM.check(PMC.TRAP_EC_GEN_0); 358 | apdu.setOutgoingAndSend((short) 0, len); 359 | } 360 | 361 | void updateAfterReset() { 362 | if (m_testCurve != null) { m_testCurve.updateAfterReset(); } 363 | if (m_testCurveCustom != null) {m_testCurveCustom.updateAfterReset(); } 364 | if (m_ecc != null) { 365 | m_ecc.refreshAfterReset(); 366 | m_ecc.unlockAll(); 367 | } 368 | if (m_ecc.bnh != null) {m_ecc.bnh.bIsSimulator = bIsSimulator; } 369 | } 370 | void test_EC_SETCURVE_G(APDU apdu, short dataLen) { 371 | byte[] apdubuf = apdu.getBuffer(); 372 | 373 | Util.arrayCopyNonAtomic(apdubuf, ISO7816.OFFSET_CDATA, m_customG, (short) 0, dataLen); 374 | PM.check(PM.TRAP_EC_SETCURVE_1); 375 | 376 | if (apdubuf[ISO7816.OFFSET_P2] == 1) { // If required, complete new custom curve and point is allocated 377 | m_testCurveCustom = new ECCurve(false, SecP256r1.p, SecP256r1.a, SecP256r1.b, m_customG, SecP256r1.r, m_ecc); 378 | m_testPointCustom = new ECPoint(m_testCurveCustom, m_ecc); 379 | PM.check(PM.TRAP_EC_SETCURVE_2); 380 | // Release unused previous objects 381 | if (!bIsSimulator) { 382 | JCSystem.requestObjectDeletion(); 383 | } 384 | } 385 | else { 386 | // Otherwise, only G is set and relevant objects are updated 387 | m_testCurveCustom.setG(apdubuf, (short) ISO7816.OFFSET_CDATA, m_testCurveCustom.POINT_SIZE); 388 | m_testPointCustom.updatePointObjects(); // After changing curve parameters, internal objects needs to be actualized 389 | } 390 | } 391 | 392 | void test_EC_DBL(APDU apdu) { 393 | byte[] apdubuf = apdu.getBuffer(); 394 | 395 | PM.check(PM.TRAP_EC_DBL_1); 396 | m_testPointCustom.setW(apdubuf, (short) ISO7816.OFFSET_CDATA, m_testCurveCustom.POINT_SIZE); 397 | // NOTE: for doubling, curve G must be also set. Here we expect that test_EC_SETCURVE_G() was called before 398 | PM.check(PM.TRAP_EC_DBL_2); 399 | m_testPointCustom.makeDouble(); //G + G 400 | PM.check(PM.TRAP_EC_DBL_3); 401 | 402 | short len = m_testPointCustom.getW(apdubuf, (short) 0); 403 | PM.check(PM.TRAP_EC_DBL_4); 404 | apdu.setOutgoingAndSend((short) 0, len); 405 | } 406 | 407 | void test_EC_ADD(APDU apdu) { 408 | byte[] apdubuf = apdu.getBuffer(); 409 | 410 | PM.check(PM.TRAP_EC_ADD_1); 411 | m_testPoint1.setW(apdubuf, (short) ISO7816.OFFSET_CDATA, m_testCurve.POINT_SIZE); 412 | PM.check(PM.TRAP_EC_ADD_2); 413 | m_testPoint2.setW(apdubuf, (short) (ISO7816.OFFSET_CDATA + m_testCurve.POINT_SIZE), m_testCurve.POINT_SIZE); 414 | PM.check(PM.TRAP_EC_ADD_3); 415 | m_testPoint1.add(m_testPoint2); 416 | PM.check(PM.TRAP_EC_ADD_4); 417 | 418 | short len = m_testPoint1.getW(apdubuf, (short) 0); 419 | PM.check(PM.TRAP_EC_ADD_5); 420 | apdu.setOutgoingAndSend((short) 0, len); 421 | } 422 | 423 | void test_EC_MUL(APDU apdu) { 424 | byte[] apdubuf = apdu.getBuffer(); 425 | short p1_len = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 426 | 427 | PM.check(PM.TRAP_EC_MUL_1); 428 | Bignat scalar = m_testBN1; 429 | scalar.set_size(p1_len); 430 | scalar.from_byte_array(p1_len, (short) 0, apdubuf, ISO7816.OFFSET_CDATA); 431 | PM.check(PM.TRAP_EC_MUL_2); 432 | m_testPoint1.setW(apdubuf, (short) (ISO7816.OFFSET_CDATA + p1_len), m_testCurve.POINT_SIZE); 433 | PM.check(PM.TRAP_EC_MUL_3); 434 | m_testPoint1.multiplication(scalar); 435 | PM.check(PM.TRAP_EC_MUL_4); 436 | 437 | short len = m_testPoint1.getW(apdubuf, (short) 0); 438 | PM.check(PM.TRAP_EC_MUL_5); 439 | apdu.setOutgoingAndSend((short) 0, len); 440 | } 441 | 442 | void test_EC_NEG(APDU apdu) { 443 | byte[] apdubuf = apdu.getBuffer(); 444 | short p1_len = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 445 | 446 | m_testPoint1.setW(apdubuf, ISO7816.OFFSET_CDATA, p1_len); 447 | m_testPoint1.negate(); 448 | short len = m_testPoint1.getW(apdubuf, (short) 0); 449 | apdu.setOutgoingAndSend((short) 0, len); 450 | } 451 | 452 | 453 | void test_EC_COMPARE(APDU apdu) { 454 | byte[] apdubuf = apdu.getBuffer(); 455 | short p1_len = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 456 | short p2_len = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 457 | 458 | m_testPoint1.setW(apdubuf, (short) ISO7816.OFFSET_CDATA, p1_len); 459 | m_testPoint2.setW(apdubuf, (short) (ISO7816.OFFSET_CDATA + p1_len), p2_len); 460 | apdubuf[0] = 0; apdubuf[1] = 0; apdubuf[2] = 0; apdubuf[3] = 0; // Tests expects big integer 461 | apdubuf[4] = m_testPoint1.isEqual(m_testPoint2) ? (byte) 1 : (byte) 0; 462 | apdu.setOutgoingAndSend((short) 0, (short) 5); 463 | } 464 | 465 | 466 | void test_BN_STR(APDU apdu, short dataLen) { 467 | byte[] apdubuf = apdu.getBuffer(); 468 | 469 | PM.check(PM.TRAP_BN_STR_1); 470 | Bignat num = m_testBN1; 471 | num.set_size(dataLen); 472 | PM.check(PM.TRAP_BN_STR_2); 473 | num.from_byte_array(dataLen, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 474 | PM.check(PM.TRAP_BN_STR_3); 475 | short len = num.copy_to_buffer(apdubuf, (short) 0); 476 | apdu.setOutgoingAndSend((short) 0, len); 477 | } 478 | 479 | void test_BN_ADD(APDU apdu, short dataLen) { 480 | byte[] apdubuf = apdu.getBuffer(); 481 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 482 | 483 | PM.check(PM.TRAP_BN_ADD_1); 484 | Bignat num1 = m_testBN1; 485 | num1.set_size(p1); 486 | PM.check(PM.TRAP_BN_ADD_2); 487 | Bignat num2 = m_testBN2; 488 | num2.set_size((short) (dataLen - p1)); 489 | PM.check(PM.TRAP_BN_ADD_3); 490 | Bignat sum = m_testBN3; 491 | sum.set_size((short) (p1 + 1)); 492 | 493 | PM.check(PM.TRAP_BN_ADD_4); 494 | num1.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 495 | num2.from_byte_array((short) (dataLen - p1), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 496 | PM.check(PM.TRAP_BN_ADD_5); 497 | sum.copy(num1); 498 | PM.check(PM.TRAP_BN_ADD_6); 499 | sum.add(num2); 500 | PM.check(PM.TRAP_BN_ADD_7); 501 | short len = sum.copy_to_buffer(apdubuf, (short) 0); 502 | apdu.setOutgoingAndSend((short) 0, len); 503 | } 504 | 505 | void test_BN_SUB(APDU apdu, short dataLen) { 506 | byte[] apdubuf = apdu.getBuffer(); 507 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 508 | 509 | PM.check(PM.TRAP_BN_SUB_1); 510 | Bignat sub1 = m_testBN1; 511 | sub1.set_size(p1); 512 | PM.check(PM.TRAP_BN_SUB_2); 513 | Bignat sub2 = m_testBN2; 514 | sub2.set_size((short) (dataLen - p1)); 515 | PM.check(PM.TRAP_BN_SUB_3); 516 | Bignat result = m_testBN3; 517 | result.set_size((short) (p1 + 1)); 518 | PM.check(PM.TRAP_BN_SUB_4); 519 | sub1.from_byte_array(dataLen, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 520 | sub2.from_byte_array(dataLen, (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 521 | PM.check(PM.TRAP_BN_SUB_5); 522 | result.copy(sub1); 523 | PM.check(PM.TRAP_BN_SUB_6); 524 | result.subtract(sub2); 525 | PM.check(PM.TRAP_BN_SUB_7); 526 | short len = result.copy_to_buffer(apdubuf, (short) 0); 527 | apdu.setOutgoingAndSend((short) 0, len); 528 | } 529 | 530 | void test_BN_MUL(APDU apdu, short dataLen, boolean bFastEngine) { 531 | byte[] apdubuf = apdu.getBuffer(); 532 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 533 | 534 | PM.check(PM.TRAP_BN_MUL_1); 535 | Bignat mul1 = m_testBN1; 536 | mul1.set_size(p1); 537 | PM.check(PM.TRAP_BN_MUL_2); 538 | Bignat mul2 = m_testBN2; 539 | mul2.set_size((short) (dataLen - p1)); 540 | PM.check(PM.TRAP_BN_MUL_3); 541 | Bignat product = m_testBN3; 542 | product.set_size(dataLen); 543 | PM.check(PM.TRAP_BN_MUL_4); 544 | mul1.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 545 | mul2.from_byte_array((short)(dataLen-p1), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 546 | PM.check(PM.TRAP_BN_MUL_5); 547 | if (bFastEngine) { 548 | product.mult_rsa_trick(mul1, mul2, null, null); 549 | } 550 | else { 551 | product.mult_schoolbook(mul1, mul2); 552 | } 553 | PM.check(PM.TRAP_BN_MUL_6); 554 | short len = product.copy_to_buffer(apdubuf, (short) 0); 555 | apdu.setOutgoingAndSend((short) 0, len); 556 | } 557 | 558 | void test_BN_EXP(APDU apdu, short dataLen) { 559 | byte[] apdubuf = apdu.getBuffer(); 560 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 561 | short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF); 562 | 563 | PM.check(PM.TRAP_BN_EXP_1); 564 | Bignat base = m_testBN1; 565 | base.set_size(p1); 566 | PM.check(PM.TRAP_BN_EXP_2); 567 | Bignat exp = m_testBN2; 568 | exp.set_size((short) (dataLen - p1)); 569 | PM.check(PM.TRAP_BN_EXP_3); 570 | Bignat res = m_testBN3; 571 | res.set_size((short) (m_ecc.MAX_BIGNAT_SIZE / 2)); 572 | PM.check(PM.TRAP_BN_EXP_4); 573 | base.from_byte_array(p1, (short) 0, apdubuf, ISO7816.OFFSET_CDATA); 574 | exp.from_byte_array((short) (dataLen - p1), (short) 0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 575 | PM.check(PM.TRAP_BN_EXP_5); 576 | res.exponentiation(base, exp); 577 | PM.check(PM.TRAP_BN_EXP_6); 578 | short len = res.copy_to_buffer(apdubuf, (short) 0); 579 | apdu.setOutgoingAndSend((short) 0, len); 580 | } 581 | 582 | void test_BN_SQRT(APDU apdu, short dataLen) { 583 | byte[] apdubuf = apdu.getBuffer(); 584 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 585 | 586 | Bignat num = m_testBN1; 587 | num.set_size(p1); 588 | num.from_byte_array(p1, p1, apdubuf, ISO7816.OFFSET_CDATA); 589 | Bignat num2 = m_testBN2; 590 | num2.clone(m_testCurve.pBN); 591 | num.sqrt_FP(num2); 592 | short len = num.copy_to_buffer(apdubuf, (short) 0); 593 | apdu.setOutgoingAndSend((short) 0, len); 594 | } 595 | 596 | 597 | void test_BN_MOD(APDU apdu, short dataLen) { 598 | byte[] apdubuf = apdu.getBuffer(); 599 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 600 | 601 | PM.check(PM.TRAP_BN_MOD_1); 602 | Bignat num = m_testBN1; 603 | num.set_size(p1); 604 | PM.check(PM.TRAP_BN_MOD_2); 605 | Bignat mod = m_testBN2; 606 | mod.set_size((short) (dataLen - p1)); 607 | PM.check(PM.TRAP_BN_MOD_3); 608 | num.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 609 | mod.from_byte_array((short)(dataLen-p1), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 610 | PM.check(PM.TRAP_BN_MOD_4); 611 | num.mod(mod); 612 | PM.check(PM.TRAP_BN_MOD_5); 613 | short len = num.copy_to_buffer(apdubuf, (short) 0); 614 | apdu.setOutgoingAndSend((short) 0, len); 615 | } 616 | 617 | void test_BN_ADD_MOD(APDU apdu, short dataLen) { 618 | byte[] apdubuf = apdu.getBuffer(); 619 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 620 | short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF); 621 | 622 | PM.check(PM.TRAP_BN_ADD_MOD_1); 623 | Bignat num1 = m_testBN1; 624 | num1.set_size(p1); 625 | PM.check(PM.TRAP_BN_ADD_MOD_2); 626 | Bignat num2 = m_testBN2; 627 | num2.set_size(p2); 628 | PM.check(PM.TRAP_BN_ADD_MOD_3); 629 | Bignat mod = m_testBN3; 630 | mod.set_size((short) (dataLen - p1 - p2)); 631 | PM.check(PM.TRAP_BN_ADD_MOD_4); 632 | num1.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 633 | num2.from_byte_array(p2, (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 634 | PM.check(PM.TRAP_BN_ADD_MOD_5); 635 | mod.from_byte_array((short)(dataLen-p1-p2), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1+p2)); 636 | PM.check(PM.TRAP_BN_ADD_MOD_6); 637 | num1.mod_add(num2, mod); 638 | PM.check(PM.TRAP_BN_ADD_MOD_7); 639 | short len = num1.copy_to_buffer(apdubuf, (short) 0); 640 | apdu.setOutgoingAndSend((short) 0, len); 641 | } 642 | 643 | void test_BN_SUB_MOD(APDU apdu, short dataLen) { 644 | byte[] apdubuf = apdu.getBuffer(); 645 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 646 | short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF); 647 | 648 | PM.check(PM.TRAP_BN_SUB_MOD_1); 649 | Bignat num1 = m_testBN1; 650 | num1.set_size(p1); 651 | PM.check(PM.TRAP_BN_SUB_MOD_2); 652 | Bignat num2 = m_testBN2; 653 | num2.set_size(p2); 654 | PM.check(PM.TRAP_BN_SUB_MOD_3); 655 | Bignat mod = m_testBN3; 656 | mod.set_size((short) (dataLen - p1 - p2)); 657 | PM.check(PM.TRAP_BN_SUB_MOD_4); 658 | num1.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 659 | num2.from_byte_array(p2, (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 660 | mod.from_byte_array((short)(dataLen-p1-p2), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1+p2)); 661 | PM.check(PM.TRAP_BN_SUB_MOD_5); 662 | num1.mod_sub(num2, mod); 663 | PM.check(PM.TRAP_BN_SUB_MOD_6); 664 | short len = num1.copy_to_buffer(apdubuf, (short) 0); 665 | apdu.setOutgoingAndSend((short) 0, len); 666 | } 667 | 668 | void test_BN_MUL_MOD(APDU apdu, short dataLen) { 669 | byte[] apdubuf = apdu.getBuffer(); 670 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 671 | short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF); 672 | 673 | PM.check(PM.TRAP_BN_MUL_MOD_1); 674 | Bignat num1 = m_testBN1; 675 | num1.set_size(p1); 676 | PM.check(PM.TRAP_BN_MUL_MOD_2); 677 | Bignat num2 = m_testBN2; 678 | num2.set_size(p2); 679 | PM.check(PM.TRAP_BN_MUL_MOD_3); 680 | Bignat mod = m_testBN3; 681 | mod.set_size((short) (dataLen - p1 - p2)); 682 | PM.check(PM.TRAP_BN_MUL_MOD_4); 683 | num1.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 684 | num2.from_byte_array(p2, (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 685 | mod.from_byte_array((short)(dataLen-p1-p2), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1+p2)); 686 | PM.check(PM.TRAP_BN_MUL_MOD_5); 687 | num1.mod_mult(num1, num2, mod); 688 | PM.check(PM.TRAP_BN_MUL_MOD_6); 689 | short len = num1.copy_to_buffer(apdubuf, (short) 0); 690 | apdu.setOutgoingAndSend((short) 0, len); 691 | } 692 | 693 | void test_BN_EXP_MOD(APDU apdu, short dataLen) { 694 | byte[] apdubuf = apdu.getBuffer(); 695 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 696 | short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF); 697 | 698 | PM.check(PM.TRAP_BN_EXP_MOD_1); 699 | Bignat num1 = m_testBN1; 700 | num1.set_size(p1); 701 | PM.check(PM.TRAP_BN_EXP_MOD_2); 702 | Bignat num2 = m_testBN2; 703 | num2.set_size(p2); 704 | PM.check(PM.TRAP_BN_EXP_MOD_3); 705 | Bignat mod = m_testBN3; 706 | mod.set_size((short) (dataLen - p1 - p2)); 707 | PM.check(PM.TRAP_BN_EXP_MOD_4); 708 | num1.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 709 | num2.from_byte_array(p2, (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 710 | mod.from_byte_array((short)(dataLen-p1-p2), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1+p2)); 711 | PM.check(PM.TRAP_BN_EXP_MOD_5); 712 | num1.mod_exp(num2, mod); 713 | PM.check(PM.TRAP_BN_EXP_MOD_6); 714 | short len = num1.copy_to_buffer(apdubuf, (short) 0); 715 | apdu.setOutgoingAndSend((short) 0, len); 716 | } 717 | 718 | void test_BN_POW2_MOD(APDU apdu, short dataLen) { 719 | byte[] apdubuf = apdu.getBuffer(); 720 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 721 | short p2 = (short) (apdubuf[ISO7816.OFFSET_P2] & 0x00FF); 722 | 723 | PM.check(PM.TRAP_BN_POW2_MOD_1); 724 | Bignat num1 = m_testBN1; 725 | num1.set_size(p1); 726 | Bignat mod = m_testBN3; 727 | mod.set_size((short) (dataLen - p1)); 728 | num1.from_byte_array(p1, (short) 0, apdubuf, ISO7816.OFFSET_CDATA); 729 | mod.from_byte_array((short) (dataLen - p1), (short) 0, apdubuf, (short) (ISO7816.OFFSET_CDATA + p1)); 730 | PM.check(PM.TRAP_BN_POW2_MOD_2); 731 | //num1.pow2Mod_RSATrick(mod); 732 | num1.mod_exp2(mod); 733 | PM.check(PM.TRAP_BN_POW2_MOD_3); 734 | short len = num1.copy_to_buffer(apdubuf, (short) 0); 735 | apdu.setOutgoingAndSend((short) 0, len); 736 | } 737 | 738 | void test_BN_INV_MOD(APDU apdu, short dataLen) { 739 | byte[] apdubuf = apdu.getBuffer(); 740 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 741 | 742 | PM.check(PM.TRAP_BN_INV_MOD_1); 743 | Bignat num1 = m_testBN1; 744 | num1.set_size(p1); 745 | PM.check(PM.TRAP_BN_INV_MOD_2); 746 | Bignat mod = m_testBN2; 747 | mod.set_size((short) (dataLen - p1)); 748 | PM.check(PM.TRAP_BN_INV_MOD_3); 749 | num1.from_byte_array(p1, (short)0, apdubuf, ISO7816.OFFSET_CDATA); 750 | mod.from_byte_array((short)(dataLen-p1), (short)0, apdubuf, (short)(ISO7816.OFFSET_CDATA+p1)); 751 | PM.check(PM.TRAP_BN_INV_MOD_4); 752 | num1.mod_inv(mod); 753 | PM.check(PM.TRAP_BN_INV_MOD_5); 754 | short len = num1.copy_to_buffer(apdubuf, (short) 0); 755 | apdu.setOutgoingAndSend((short) 0, len); 756 | } 757 | 758 | void test_INT_STR(APDU apdu, short dataLen) { 759 | byte[] apdubuf = apdu.getBuffer(); 760 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 761 | 762 | PM.check(PM.TRAP_INT_STR_1); 763 | //Integer num_int = new Integer(dataLen, (short) 0, apdubuf, ISO7816.OFFSET_CDATA); 764 | Integer num_int = m_testINT1; 765 | num_int.fromByteArray(apdubuf, ISO7816.OFFSET_CDATA, dataLen); 766 | PM.check(PM.TRAP_INT_STR_2); 767 | short len = num_int.toByteArray(apdubuf, (short) 0); 768 | apdu.setOutgoingAndSend((short) 0, len); 769 | } 770 | 771 | void test_INT_ADD(APDU apdu, short dataLen) { 772 | byte[] apdubuf = apdu.getBuffer(); 773 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 774 | 775 | PM.check(PM.TRAP_INT_ADD_1); 776 | //Integer num_add_1 = new Integer(dataLen, (short) 0, apdubuf, ISO7816.OFFSET_CDATA); 777 | Integer num_add_1 = m_testINT1; 778 | num_add_1.fromByteArray(apdubuf, ISO7816.OFFSET_CDATA, p1); 779 | PM.check(PM.TRAP_INT_ADD_2); 780 | //Integer num_add_2 = new Integer((short) (dataLen - p1), (short) 0, apdubuf, (short) (ISO7816.OFFSET_CDATA + p1)); 781 | Integer num_add_2 = m_testINT2; 782 | num_add_2.fromByteArray(apdubuf, (short) (ISO7816.OFFSET_CDATA + p1), p1); 783 | PM.check(PM.TRAP_INT_ADD_3); 784 | num_add_1.add(num_add_2); 785 | PM.check(PM.TRAP_INT_ADD_4); 786 | short len = num_add_1.toByteArray(apdubuf, (short) 0); 787 | apdu.setOutgoingAndSend((short) 0, len); 788 | } 789 | 790 | void test_INT_SUB(APDU apdu, short dataLen) { 791 | byte[] apdubuf = apdu.getBuffer(); 792 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 793 | 794 | PM.check(PM.TRAP_INT_SUB_1); 795 | Integer num_sub_1 = m_testINT1; 796 | num_sub_1.fromByteArray(apdubuf, ISO7816.OFFSET_CDATA, p1); 797 | Integer num_sub_2 = m_testINT2; 798 | num_sub_2.fromByteArray(apdubuf, (short) (ISO7816.OFFSET_CDATA + p1), p1); 799 | PM.check(PM.TRAP_INT_SUB_2); 800 | 801 | num_sub_1.subtract(num_sub_2); 802 | PM.check(PM.TRAP_INT_SUB_3); 803 | short len = num_sub_1.toByteArray(apdubuf, (short) 0); 804 | apdu.setOutgoingAndSend((short) 0, len); 805 | } 806 | 807 | void test_INT_MUL(APDU apdu, short dataLen) { 808 | byte[] apdubuf = apdu.getBuffer(); 809 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 810 | 811 | PM.check(PM.TRAP_INT_MUL_1); 812 | Integer num_mul_1 = m_testINT1; 813 | num_mul_1.fromByteArray(apdubuf, ISO7816.OFFSET_CDATA, p1); 814 | Integer num_mul_2 = m_testINT2; 815 | num_mul_2.fromByteArray(apdubuf, (short) (ISO7816.OFFSET_CDATA + p1), p1); 816 | PM.check(PM.TRAP_INT_MUL_2); 817 | 818 | num_mul_1.multiply(num_mul_2); 819 | PM.check(PM.TRAP_INT_MUL_3); 820 | short len = num_mul_1.toByteArray(apdubuf, (short) 0); 821 | apdu.setOutgoingAndSend((short) 0, len); 822 | } 823 | 824 | void test_INT_DIV(APDU apdu, short dataLen) { 825 | byte[] apdubuf = apdu.getBuffer(); 826 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 827 | 828 | PM.check(PM.TRAP_INT_DIV_1); 829 | Integer num_div_1 = m_testINT1; 830 | num_div_1.fromByteArray(apdubuf, ISO7816.OFFSET_CDATA, p1); 831 | Integer num_div_2 = m_testINT2; 832 | num_div_2.fromByteArray(apdubuf, (short) (ISO7816.OFFSET_CDATA + p1), p1); 833 | PM.check(PM.TRAP_INT_DIV_2); 834 | 835 | num_div_1.divide(num_div_2); 836 | PM.check(PM.TRAP_INT_DIV_3); 837 | 838 | short len = num_div_1.toByteArray(apdubuf, (short) 0); 839 | apdu.setOutgoingAndSend((short) 0, len); 840 | } 841 | 842 | void test_INT_MOD(APDU apdu, short dataLen) { 843 | byte[] apdubuf = apdu.getBuffer(); 844 | short p1 = (short) (apdubuf[ISO7816.OFFSET_P1] & 0x00FF); 845 | 846 | PM.check(PM.TRAP_INT_MOD_1); 847 | Integer num_mod_1 = m_testINT1; 848 | num_mod_1.fromByteArray(apdubuf, ISO7816.OFFSET_CDATA, p1); 849 | Integer num_mod_2 = m_testINT2; 850 | num_mod_2.fromByteArray(apdubuf, (short) (ISO7816.OFFSET_CDATA + p1), p1); 851 | PM.check(PM.TRAP_INT_MOD_2); 852 | 853 | num_mod_1.modulo(num_mod_2); 854 | PM.check(PM.TRAP_INT_MOD_3); 855 | short len = num_mod_1.toByteArray(apdubuf, (short) 0); 856 | apdu.setOutgoingAndSend((short) 0, len); 857 | } 858 | } 859 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_applet/PM.java: -------------------------------------------------------------------------------- 1 | package jcprofiler; // TODO: change to your applet package 2 | 3 | import javacard.framework.ISOException; 4 | 5 | /** 6 | * Utility class for performance profiling. Contains currently set trap stop and trap reaction method. 7 | * @author Petr Svenda 8 | */ 9 | public class PM { 10 | public static short m_perfStop = -1; // Performace measurement stop indicator 11 | 12 | // if m_perfStop equals to stopCondition, exception is throws (trap hit) 13 | public static void check(short stopCondition) { 14 | if (PM.m_perfStop == stopCondition) { 15 | ISOException.throwIt(stopCondition); 16 | } 17 | } 18 | 19 | } 20 | 21 | !!! TODO: Move code below into your main applet class into process() method. 22 | If INS value 0xf5 is already taken, change it to any other, but don't forget 23 | to modify correspondingly also the value of JCProfiler_client.PerfTests.INS_PERF_SETTRAPID 24 | // ----- begin of code to be moved 25 | public final static byte INS_PERF_SETSTOP = (byte) 0xf5; 26 | case INS_PERF_SETSTOP: 27 | PM.m_perfStop = Util.makeShort(apdubuf[ISO7816.OFFSET_CDATA], apdubuf[(short) (ISO7816.OFFSET_CDATA + 1)]); 28 | break; 29 | // ----- end of code to be moved 30 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_applet/PMC.java: -------------------------------------------------------------------------------- 1 | package jcprofiler; // TODO: change to your applet package 2 | 3 | /** 4 | * Utility class for performance profiling constants 5 | * @author Petr Svenda 6 | */ 7 | public class PMC { 8 | public static final short PERF_START = (short) 0x0001; 9 | 10 | public static final short TRAP_UNDEFINED = (short) 0xffff; 11 | 12 | //### PLACEHOLDER PMC CONSTANTS 13 | 14 | } 15 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Builds, tests, and runs the project JCProfiler_client. 12 | 13 | 73 | 74 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/manifest.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | X-COMMENT: Main-Class will be added automatically by build 3 | 4 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/nbproject/genfiles.properties: -------------------------------------------------------------------------------- 1 | build.xml.data.CRC32=f227f3f8 2 | build.xml.script.CRC32=8e215913 3 | build.xml.stylesheet.CRC32=8064a381@1.75.2.48 4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. 5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. 6 | nbproject/build-impl.xml.data.CRC32=f227f3f8 7 | nbproject/build-impl.xml.script.CRC32=7e5f8c81 8 | nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 9 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/nbproject/project.properties: -------------------------------------------------------------------------------- 1 | annotation.processing.enabled=true 2 | annotation.processing.enabled.in.editor=false 3 | annotation.processing.processor.options= 4 | annotation.processing.processors.list= 5 | annotation.processing.run.all.processors=true 6 | annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output 7 | build.classes.dir=${build.dir}/classes 8 | build.classes.excludes=**/*.java,**/*.form 9 | # This directory is removed when the project is cleaned: 10 | build.dir=build 11 | build.generated.dir=${build.dir}/generated 12 | build.generated.sources.dir=${build.dir}/generated-sources 13 | # Only compile against the classpath explicitly listed here: 14 | build.sysclasspath=ignore 15 | build.test.classes.dir=${build.dir}/test/classes 16 | build.test.results.dir=${build.dir}/test/results 17 | # Uncomment to specify the preferred debugger connection transport: 18 | #debug.transport=dt_socket 19 | debug.classpath=\ 20 | ${run.classpath} 21 | debug.test.classpath=\ 22 | ${run.test.classpath} 23 | # Files in build.classes.dir which should be excluded from distribution jar 24 | dist.archive.excludes= 25 | # This directory is removed when the project is cleaned: 26 | dist.dir=dist 27 | dist.jar=${dist.dir}/JCProfiler_client.jar 28 | dist.javadoc.dir=${dist.dir}/javadoc 29 | excludes= 30 | includes=** 31 | jar.compress=false 32 | javac.classpath= 33 | # Space-separated list of extra javac options 34 | javac.compilerargs= 35 | javac.deprecation=false 36 | javac.processorpath=\ 37 | ${javac.classpath} 38 | javac.source=1.8 39 | javac.target=1.8 40 | javac.test.classpath=\ 41 | ${javac.classpath}:\ 42 | ${build.classes.dir} 43 | javac.test.processorpath=\ 44 | ${javac.test.classpath} 45 | javadoc.additionalparam= 46 | javadoc.author=false 47 | javadoc.encoding=${source.encoding} 48 | javadoc.noindex=false 49 | javadoc.nonavbar=false 50 | javadoc.notree=false 51 | javadoc.private=false 52 | javadoc.splitindex=true 53 | javadoc.use=true 54 | javadoc.version=false 55 | javadoc.windowtitle= 56 | main.class=simpleapdu.JCProfiler_client 57 | manifest.file=manifest.mf 58 | meta.inf.dir=${src.dir}/META-INF 59 | mkdist.disabled=false 60 | platform.active=default_platform 61 | run.classpath=\ 62 | ${javac.classpath}:\ 63 | ${build.classes.dir} 64 | # Space-separated list of JVM arguments used when running the project. 65 | # You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. 66 | # To set system properties for unit tests define test-sys-prop.name=value: 67 | run.jvmargs= 68 | run.test.classpath=\ 69 | ${javac.test.classpath}:\ 70 | ${build.test.classes.dir} 71 | source.encoding=UTF-8 72 | src.dir=src 73 | test.src.dir=test 74 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.java.j2seproject 4 | 5 | 6 | JCProfiler_client 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/src/jcprofiler/CardManager.java: -------------------------------------------------------------------------------- 1 | package jcprofiler; 2 | 3 | import java.util.List; 4 | import javax.smartcardio.*; 5 | 6 | /** 7 | * 8 | * @author Petr Svenda 9 | */ 10 | public class CardManager { 11 | CardTerminal m_terminal = null; 12 | CardChannel m_channel = null; 13 | Card m_card = null; 14 | Long m_lastTransmitTime = (long) 0; 15 | 16 | public final static byte OFFSET_CDATA = 5; 17 | public final static short SW_NO_ERROR = (short) 0x9000; 18 | 19 | public boolean ConnectToCard(byte[] appletAID) throws Exception { 20 | // Try all readers, connect to fisrt card 21 | List terminalList = GetReaderList(); 22 | 23 | if (terminalList.isEmpty()) { 24 | System.out.println("No terminals found"); 25 | } 26 | 27 | //List numbers of Card readers 28 | for (int i = 0; i < terminalList.size(); i++) { 29 | System.out.println(i + " : " + terminalList.get(i)); 30 | m_terminal = (CardTerminal) terminalList.get(i); 31 | if (m_terminal.isCardPresent()) { 32 | m_card = m_terminal.connect("*"); 33 | System.out.println("card: " + m_card); 34 | m_channel = m_card.getBasicChannel(); 35 | 36 | //reset the card 37 | ATR atr = m_card.getATR(); 38 | System.out.println(bytesToHex(m_card.getATR().getBytes())); 39 | 40 | System.out.println("Selecting applet..."); 41 | CommandAPDU cmd = new CommandAPDU(0x00, 0xa4, 0x04, 0x00, appletAID); 42 | ResponseAPDU response = transmit(cmd); 43 | 44 | return true; 45 | } 46 | } 47 | 48 | return false; 49 | } 50 | 51 | public void DisconnectFromCard() throws Exception { 52 | if (m_card != null) { 53 | m_card.disconnect(false); 54 | m_card = null; 55 | } 56 | } 57 | 58 | public List GetReaderList() { 59 | try { 60 | TerminalFactory factory = TerminalFactory.getDefault(); 61 | List readersList = factory.terminals().list(); 62 | return readersList; 63 | } catch (Exception ex) { 64 | System.out.println("Exception : " + ex); 65 | return null; 66 | } 67 | } 68 | 69 | public ResponseAPDU transmit(CommandAPDU cmd) throws CardException { 70 | log(cmd); 71 | 72 | long elapsed = -System.currentTimeMillis(); 73 | ResponseAPDU response = m_channel.transmit(cmd); 74 | elapsed += System.currentTimeMillis(); 75 | m_lastTransmitTime = elapsed; 76 | 77 | log(response, m_lastTransmitTime); 78 | 79 | return response; 80 | } 81 | 82 | private void log(CommandAPDU cmd) { 83 | System.out.printf("--> %s\n", toHex(cmd.getBytes()), 84 | cmd.getBytes().length); 85 | } 86 | 87 | private void log(ResponseAPDU response, long time) { 88 | String swStr = String.format("%02X", response.getSW()); 89 | byte[] data = response.getData(); 90 | if (data.length > 0) { 91 | System.out.printf("<-- %s %s (%d) [%d ms]\n", toHex(data), swStr, 92 | data.length, time); 93 | } else { 94 | System.out.printf("<-- %s [%d ms]\n", swStr, time); 95 | } 96 | } 97 | 98 | public String byteToHex(byte data) { 99 | StringBuilder buf = new StringBuilder(); 100 | buf.append(toHexChar((data >>> 4) & 0x0F)); 101 | buf.append(toHexChar(data & 0x0F)); 102 | return buf.toString(); 103 | } 104 | 105 | public char toHexChar(int i) { 106 | if ((0 <= i) && (i <= 9)) { 107 | return (char) ('0' + i); 108 | } else { 109 | return (char) ('a' + (i - 10)); 110 | } 111 | } 112 | 113 | public String bytesToHex(byte[] data) { 114 | StringBuilder buf = new StringBuilder(); 115 | for (int i = 0; i < data.length; i++) { 116 | buf.append(byteToHex(data[i])); 117 | buf.append(" "); 118 | } 119 | return (buf.toString()); 120 | } 121 | 122 | public static byte[] hexStringToByteArray(String s) { 123 | String sanitized = s.replace(" ", ""); 124 | byte[] b = new byte[sanitized.length() / 2]; 125 | for (int i = 0; i < b.length; i++) { 126 | int index = i * 2; 127 | int v = Integer.parseInt(sanitized.substring(index, index + 2), 16); 128 | b[i] = (byte) v; 129 | } 130 | return b; 131 | } 132 | 133 | public static String toHex(byte[] bytes) { 134 | return toHex(bytes, 0, bytes.length); 135 | } 136 | 137 | public static String toHex(byte[] bytes, int offset, int len) { 138 | String result = ""; 139 | 140 | for (int i = offset; i < offset + len; i++) { 141 | result += String.format("%02X", bytes[i]); 142 | } 143 | 144 | return result; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/src/jcprofiler/JCProfiler_client.java: -------------------------------------------------------------------------------- 1 | package jcprofiler; 2 | 3 | 4 | /** 5 | * @author Petr Svenda 6 | */ 7 | public class JCProfiler_client { 8 | 9 | public static void main(String[] args) { 10 | JCProfiler_client app = new JCProfiler_client(); 11 | app.run(args); 12 | } 13 | 14 | private void run(String[] args) { 15 | System.out.println("JCProfiler v1.0 by OpenCryptoProject, 2017"); 16 | try { 17 | PerfTests perfTests = new PerfTests(); 18 | perfTests.RunPerformanceTests(1, true); 19 | } catch (Exception ex) { 20 | System.out.println("Exception : " + ex); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/src/jcprofiler/PMC.java: -------------------------------------------------------------------------------- 1 | package jcprofiler; 2 | 3 | /** 4 | * Utility class for performance profiling constants 5 | * @author Petr Svenda 6 | */ 7 | public class PMC { 8 | public static final short PERF_START = (short) 0x0001; 9 | 10 | public static final short TRAP_UNDEFINED = (short) 0xffff; 11 | 12 | //### PLACEHOLDER PMC CONSTANTS 13 | 14 | } 15 | -------------------------------------------------------------------------------- /demo/templates/template_profiler_client/src/jcprofiler/PerfTests.java: -------------------------------------------------------------------------------- 1 | package jcprofiler; 2 | 3 | import javafx.util.Pair; 4 | 5 | import javax.smartcardio.CardException; 6 | import javax.smartcardio.CommandAPDU; 7 | import javax.smartcardio.ResponseAPDU; 8 | import java.io.*; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | 12 | /** 13 | * @author Petr Svenda 14 | */ 15 | public class PerfTests { 16 | final static byte[] APPLET_AID = {0x55, 0x6e, 0x69, 0x74, 0x54, 0x65, 0x73, 0x74, 0x73}; // TODO: fill your applet AID 17 | static final byte APPLET_CLA = (byte) 0xB0; // TODO: fill your applet_CLA 18 | static final byte[] APDU_TRIGGER = {APPLET_CLA, 0x40, 0, 0, 0}; // TODO: set proper APDU which will trigger the target operation 19 | static final byte[] APDU_CLEANUP = {APPLET_CLA, 0x03, 0, 0, 0}; // TODO: set proper on-card cleaning command (if necessary). Set to null if not necessary 20 | static final String CARD_NAME = "noCardNameGiven"; // TODO: fill name of your card; 21 | 22 | static final byte INS_PERF_SETTRAPID = (byte) 0xf5; 23 | static byte[] APDU_SETTRAPID = {APPLET_CLA, INS_PERF_SETTRAPID, 0, 0, 2, 0, 0}; 24 | static final byte[] APDU_SETTRAPID_NONE = {APPLET_CLA, INS_PERF_SETTRAPID, 0, 0, 2, 0, 0}; 25 | 26 | class PerfConfig { 27 | public String cardName = "noCardNameGiven"; 28 | public FileOutputStream perfFile = null; 29 | public ArrayList> perfResultsSingleOp = new ArrayList<>(); 30 | public ArrayList perfResultsSubparts = new ArrayList<>(); 31 | public HashMap> perfResultsSubpartsRaw = new HashMap<>(); // hashmap with key being perf trap id, folowed by pair 32 | public boolean bMeasurePerf = true; 33 | public short[] perfStops = null; 34 | public short perfStopComplete = -1; 35 | public ArrayList failedPerfTraps = new ArrayList<>(); 36 | } 37 | 38 | PerfTests() { 39 | buildPerfMapping(); 40 | } 41 | 42 | void RunPerformanceTests(int numRepeats, boolean MODIFY_SOURCE_FILES_BY_PERF) throws Exception { 43 | PerfConfig cfg = new PerfConfig(); 44 | String experimentID = String.format("%d", System.currentTimeMillis()); 45 | cfg.perfFile = new FileOutputStream(String.format("OC_PERF_log_%s.csv", experimentID)); 46 | 47 | try { 48 | CardManager cardMngr = new CardManager(); 49 | System.out.println("Connecting to card..."); 50 | cardMngr.ConnectToCard(APPLET_AID); 51 | System.out.println(" Done."); 52 | 53 | cardMngr.transmit(new CommandAPDU(APDU_SETTRAPID_NONE)); // erase any previous performance stop 54 | if (APDU_CLEANUP != null) { // reset if required 55 | cardMngr.transmit(new CommandAPDU(APDU_CLEANUP)); 56 | } 57 | 58 | System.out.println("\n-------------- Performance profiling start --------------\n\n"); 59 | 60 | //### PLACEHOLDER PERFTRAPS INIT 61 | for (int repeat = 0; repeat < numRepeats; repeat++) { 62 | CommandAPDU cmd = new CommandAPDU(APDU_TRIGGER); 63 | PerfAnalyzeCommand("insert nice name", cmd, cardMngr, cfg); 64 | } 65 | 66 | System.out.println("\n-------------- Performance profiling finished --------------\n\n"); 67 | System.out.print("Disconnecting from card..."); 68 | cardMngr.DisconnectFromCard(); 69 | System.out.println(" Done."); 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | 74 | if (cfg.failedPerfTraps.size() > 0) { 75 | System.out.println("#########################"); 76 | System.out.println("!!! SOME PERFORMANCE TRAPS NOT REACHED !!!"); 77 | System.out.println("#########################"); 78 | for (String trap : cfg.failedPerfTraps) { 79 | System.out.println(trap); 80 | } 81 | } else { 82 | System.out.println("##########################"); 83 | System.out.println("ALL PERFORMANCE TRAPS REACHED CORRECTLY"); 84 | System.out.println("##########################"); 85 | } 86 | 87 | // Save performance traps into single file 88 | String perfFileName = String.format("TRAP_RAW_%s.csv", experimentID); 89 | SavePerformanceResults(cfg.perfResultsSubpartsRaw, perfFileName); 90 | 91 | // If required, modification of source code files is attempted 92 | if (MODIFY_SOURCE_FILES_BY_PERF) { 93 | String dirPath = "..\\Profiler_applet\\"; 94 | System.out.println(String.format("INFO: going to insert profiled info into files in '%s' directory", dirPath)); 95 | InsertPerfInfoIntoFiles(dirPath, cfg.cardName, experimentID, cfg.perfResultsSubpartsRaw); 96 | } 97 | } 98 | 99 | static void SavePerformanceResults(HashMap> perfResultsSubpartsRaw, String fileName) throws FileNotFoundException, IOException { 100 | // Save performance traps into single file 101 | FileOutputStream perfLog = new FileOutputStream(fileName); 102 | String output = "trapID, previous trapID, time difference between trapID and previous trapID (ms)\n"; 103 | perfLog.write(output.getBytes()); 104 | for (Short perfID : perfResultsSubpartsRaw.keySet()) { 105 | output = String.format("%d, %d, %d\n", perfID, perfResultsSubpartsRaw.get(perfID).getKey(), perfResultsSubpartsRaw.get(perfID).getValue()); 106 | perfLog.write(output.getBytes()); 107 | } 108 | perfLog.close(); 109 | } 110 | 111 | static void LoadPerformanceResults(String fileName, HashMap> perfResultsSubpartsRaw) throws FileNotFoundException, IOException { 112 | BufferedReader br = new BufferedReader(new FileReader(fileName)); 113 | String strLine; 114 | while ((strLine = br.readLine()) != null) { 115 | if (strLine.contains("trapID,")) { 116 | // skip header line 117 | } else { 118 | String[] cols = strLine.split(","); 119 | Short perfID = Short.parseShort(cols[0].trim()); 120 | Short prevPerfID = Short.parseShort(cols[1].trim()); 121 | Long elapsed = Long.parseLong(cols[2].trim()); 122 | 123 | perfResultsSubpartsRaw.put(perfID, new Pair(prevPerfID, elapsed)); 124 | } 125 | } 126 | br.close(); 127 | } 128 | 129 | public static byte[] shortToByteArray(int s) { 130 | return new byte[]{(byte) ((s & 0xFF00) >> 8), (byte) (s & 0x00FF)}; 131 | } 132 | 133 | long PerfAnalyzeCommand(String operationName, CommandAPDU cmd, CardManager cardMngr, PerfConfig cfg) throws CardException, IOException { 134 | System.out.println(operationName); 135 | short prevPerfStop = PMC.PERF_START; 136 | long prevTransmitTime = 0; 137 | long lastFromPrevTime = 0; 138 | try { 139 | for (short trapID : cfg.perfStops) { 140 | System.arraycopy(shortToByteArray(trapID), 0, APDU_SETTRAPID, CardManager.OFFSET_CDATA, 2); // set required stop condition 141 | String operationNamePerf = String.format("%s_%s", operationName, getPerfStopName(trapID)); 142 | cardMngr.transmit(new CommandAPDU(APDU_SETTRAPID)); // set performance trap 143 | ResponseAPDU response = cardMngr.transmit(cmd); // execute target operation 144 | boolean bFailedToReachTrap = false; 145 | if (trapID != cfg.perfStopComplete) { // Check expected error to be equal performance trap 146 | if (response.getSW() != (trapID & 0xffff)) { 147 | // we have not reached expected performance trap 148 | cfg.failedPerfTraps.add(getPerfStopName(trapID)); 149 | bFailedToReachTrap = true; 150 | } 151 | } 152 | writePerfLog(operationNamePerf, response.getSW() == (CardManager.SW_NO_ERROR & 0xffff), cardMngr.m_lastTransmitTime, cfg.perfResultsSingleOp, cfg.perfFile); 153 | long fromPrevTime = cardMngr.m_lastTransmitTime - prevTransmitTime; 154 | if (bFailedToReachTrap) { 155 | cfg.perfResultsSubparts.add(String.format("[%s-%s], \tfailed to reach after %d ms (0x%x)", getPerfStopName(prevPerfStop), getPerfStopName(trapID), cardMngr.m_lastTransmitTime, response.getSW())); 156 | } else { 157 | cfg.perfResultsSubparts.add(String.format("[%s-%s], \t%d ms", getPerfStopName(prevPerfStop), getPerfStopName(trapID), fromPrevTime)); 158 | cfg.perfResultsSubpartsRaw.put(trapID, new Pair(prevPerfStop, fromPrevTime)); 159 | lastFromPrevTime = fromPrevTime; 160 | } 161 | 162 | prevPerfStop = trapID; 163 | prevTransmitTime = cardMngr.m_lastTransmitTime; 164 | 165 | if (APDU_CLEANUP != null) { 166 | cardMngr.transmit(new CommandAPDU(APDU_CLEANUP)); // free memory after command 167 | } 168 | } 169 | } catch (Exception e) { 170 | // Print what we have measured so far 171 | for (String res : cfg.perfResultsSubparts) { 172 | System.out.println(res); 173 | } 174 | throw e; 175 | } 176 | // Print measured performance info 177 | for (String res : cfg.perfResultsSubparts) { 178 | System.out.println(res); 179 | } 180 | 181 | return lastFromPrevTime; 182 | } 183 | 184 | 185 | static void writePerfLog(String operationName, boolean bResult, Long time, ArrayList> perfResults, FileOutputStream perfFile) throws IOException { 186 | perfResults.add(new Pair(operationName, time)); 187 | perfFile.write(String.format("%s,%d,%s\n", operationName, time, bResult).getBytes()); 188 | perfFile.flush(); 189 | } 190 | 191 | static void InsertPerfInfoIntoFiles(String basePath, String cardName, String experimentID, HashMap> perfResultsSubpartsRaw) throws FileNotFoundException, IOException { 192 | File dir = new File(basePath); 193 | String[] filesArray = dir.list(); 194 | if ((filesArray != null) && dir.isDirectory()) { 195 | // make subdir for results 196 | String outputDir = String.format("%s/perf/%s/", basePath, experimentID); 197 | new File(outputDir).mkdirs(); 198 | 199 | for (String fileName : filesArray) { 200 | File dir2 = new File(basePath + fileName); 201 | if (!dir2.isDirectory()) { 202 | InsertPerfInfoIntoFile(String.format("%s/%s", basePath, fileName), cardName, experimentID, outputDir, perfResultsSubpartsRaw); 203 | } 204 | } 205 | } 206 | } 207 | 208 | static final String PERF_TRAP_CALL = "PM.check(PMC."; 209 | static final String PERF_TRAP_CALL_END = ");"; 210 | 211 | static void InsertPerfInfoIntoFile(String filePath, String cardName, String experimentID, String outputDir, HashMap> perfResultsSubpartsRaw) throws FileNotFoundException, IOException { 212 | try { 213 | BufferedReader br = new BufferedReader(new FileReader(filePath)); 214 | String basePath = filePath.substring(0, filePath.lastIndexOf("/")); 215 | String fileName = filePath.substring(filePath.lastIndexOf("/")); 216 | 217 | String fileNamePerf = String.format("%s/%s", outputDir, fileName); 218 | FileOutputStream fileOut = new FileOutputStream(fileNamePerf); 219 | String strLine; 220 | String resLine; 221 | // For every line of program try to find perfromance trap. If found and perf. is available, then insert comment into code 222 | while ((strLine = br.readLine()) != null) { 223 | 224 | if (strLine.contains(PERF_TRAP_CALL)) { 225 | int trapStart = strLine.indexOf(PERF_TRAP_CALL); 226 | int trapEnd = strLine.indexOf(PERF_TRAP_CALL_END); 227 | // We have perf. trap, now check if we also corresponding measurement 228 | String perfTrapName = (String) strLine.substring(trapStart + PERF_TRAP_CALL.length(), trapEnd); 229 | short perfID = getPerfStopFromName(perfTrapName); 230 | 231 | if (perfResultsSubpartsRaw.containsKey(perfID)) { 232 | // We have measurement for this trap, add into comment section 233 | resLine = String.format("%s // %d ms (%s,%s) %s", (String) strLine.substring(0, trapEnd + PERF_TRAP_CALL_END.length()), perfResultsSubpartsRaw.get(perfID).getValue(), cardName, experimentID, (String) strLine.subSequence(trapEnd + PERF_TRAP_CALL_END.length(), strLine.length())); 234 | } else { 235 | resLine = strLine; 236 | } 237 | } else { 238 | resLine = strLine; 239 | } 240 | resLine += "\n"; 241 | fileOut.write(resLine.getBytes()); 242 | } 243 | 244 | fileOut.close(); 245 | } catch (Exception e) { 246 | System.out.println(String.format("Failed to transform file %s ", filePath) + e); 247 | } 248 | } 249 | 250 | public static HashMap PERF_TRAPS_MAPPING = new HashMap<>(); 251 | 252 | public static void buildPerfMapping() { 253 | PERF_TRAPS_MAPPING.put(PMC.PERF_START, "PERF_START"); 254 | 255 | //### PLACEHOLDER PMC MAPPINGS 256 | 257 | } 258 | 259 | public static String getPerfStopName(short stopID) { 260 | if (PERF_TRAPS_MAPPING.containsKey(stopID)) { 261 | return PERF_TRAPS_MAPPING.get(stopID); 262 | } else { 263 | assert (false); 264 | return "PERF_UNDEFINED"; 265 | } 266 | } 267 | 268 | public static short getPerfStopFromName(String stopName) { 269 | for (Short stopID : PERF_TRAPS_MAPPING.keySet()) { 270 | if (PERF_TRAPS_MAPPING.get(stopID).equalsIgnoreCase(stopName)) { 271 | return stopID; 272 | } 273 | } 274 | assert (false); 275 | return PMC.TRAP_UNDEFINED; 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /dist/README.TXT: -------------------------------------------------------------------------------- 1 | ======================== 2 | BUILD OUTPUT DESCRIPTION 3 | ======================== 4 | 5 | When you build an Java application project that has a main class, the IDE 6 | automatically copies all of the JAR 7 | files on the projects classpath to your projects dist/lib folder. The IDE 8 | also adds each of the JAR files to the Class-Path element in the application 9 | JAR files manifest file (MANIFEST.MF). 10 | 11 | To run the project from the command line, go to the dist folder and 12 | type the following: 13 | 14 | java -jar "JCProfiler.jar" 15 | 16 | To distribute this project, zip up the dist folder (including the lib folder) 17 | and distribute the ZIP file. 18 | 19 | Notes: 20 | 21 | * If two JAR files on the project classpath have the same name, only the first 22 | JAR file is copied to the lib folder. 23 | * Only JAR files are copied to the lib folder. 24 | If the classpath contains other types of files or folders, these files (folders) 25 | are not copied. 26 | * If a library on the projects classpath also has a Class-Path element 27 | specified in the manifest,the content of the Class-Path element has to be on 28 | the projects runtime path. 29 | * To set a main class in a standard Java project, right-click the project node 30 | in the Projects window and choose Properties. Then click Run and enter the 31 | class name in the Main Class field. Alternatively, you can manually type the 32 | class name in the manifest Main-Class element. 33 | -------------------------------------------------------------------------------- /lib/commons-cli-1.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCryptoProject/JCProfiler/4a14775f67a4ccf4ee0a5c38d0a2ccb8c0eb70d4/lib/commons-cli-1.3.1.jar -------------------------------------------------------------------------------- /nbproject/build-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | Must set src.dir 227 | Must set test.src.dir 228 | Must set build.dir 229 | Must set dist.dir 230 | Must set build.classes.dir 231 | Must set dist.javadoc.dir 232 | Must set build.test.classes.dir 233 | Must set build.test.results.dir 234 | Must set build.classes.excludes 235 | Must set dist.jar 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | Must set javac.includes 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | No tests executed. 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | Must set JVM to use for profiling in profiler.info.jvm 716 | Must set profiler agent JVM arguments in profiler.info.jvmargs.agent 717 | 718 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | Must select some files in the IDE or set javac.includes 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | To run this application from the command line without Ant, try: 995 | 996 | java -jar "${dist.jar.resolved}" 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | Must select one file in the IDE or set run.class 1044 | 1045 | 1046 | 1047 | Must select one file in the IDE or set run.class 1048 | 1049 | 1050 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | Must select one file in the IDE or set debug.class 1075 | 1076 | 1077 | 1078 | 1079 | Must select one file in the IDE or set debug.class 1080 | 1081 | 1082 | 1083 | 1084 | Must set fix.includes 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1096 | 1099 | 1100 | This target only works when run from inside the NetBeans IDE. 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | Must select one file in the IDE or set profile.class 1110 | This target only works when run from inside the NetBeans IDE. 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | This target only works when run from inside the NetBeans IDE. 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | This target only works when run from inside the NetBeans IDE. 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | Must select one file in the IDE or set run.class 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | Must select some files in the IDE or set test.includes 1177 | 1178 | 1179 | 1180 | 1181 | Must select one file in the IDE or set run.class 1182 | 1183 | 1184 | 1185 | 1186 | Must select one file in the IDE or set applet.url 1187 | 1188 | 1189 | 1190 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | Must select some files in the IDE or set javac.includes 1266 | 1267 | 1268 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | Some tests failed; see details above. 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | Must select some files in the IDE or set test.includes 1299 | 1300 | 1301 | 1302 | Some tests failed; see details above. 1303 | 1304 | 1305 | 1306 | Must select some files in the IDE or set test.class 1307 | Must select some method in the IDE or set test.method 1308 | 1309 | 1310 | 1311 | Some tests failed; see details above. 1312 | 1313 | 1314 | 1319 | 1320 | Must select one file in the IDE or set test.class 1321 | 1322 | 1323 | 1324 | Must select one file in the IDE or set test.class 1325 | Must select some method in the IDE or set test.method 1326 | 1327 | 1328 | 1329 | 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1337 | 1342 | 1343 | Must select one file in the IDE or set applet.url 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1355 | 1356 | Must select one file in the IDE or set applet.url 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 1363 | 1364 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | 1387 | 1388 | 1389 | 1390 | 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | -------------------------------------------------------------------------------- /nbproject/genfiles.properties: -------------------------------------------------------------------------------- 1 | build.xml.data.CRC32=03c39f61 2 | build.xml.script.CRC32=4eeb9406 3 | build.xml.stylesheet.CRC32=8064a381@1.75.2.48 4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. 5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. 6 | nbproject/build-impl.xml.data.CRC32=03c39f61 7 | nbproject/build-impl.xml.script.CRC32=39761f8e 8 | nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 9 | -------------------------------------------------------------------------------- /nbproject/project.properties: -------------------------------------------------------------------------------- 1 | annotation.processing.enabled=true 2 | annotation.processing.enabled.in.editor=false 3 | annotation.processing.processors.list= 4 | annotation.processing.run.all.processors=true 5 | annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output 6 | application.title=JCProfiler 7 | application.vendor=petrs 8 | build.classes.dir=${build.dir}/classes 9 | build.classes.excludes=**/*.java,**/*.form 10 | # This directory is removed when the project is cleaned: 11 | build.dir=build 12 | build.generated.dir=${build.dir}/generated 13 | build.generated.sources.dir=${build.dir}/generated-sources 14 | # Only compile against the classpath explicitly listed here: 15 | build.sysclasspath=ignore 16 | build.test.classes.dir=${build.dir}/test/classes 17 | build.test.results.dir=${build.dir}/test/results 18 | # Uncomment to specify the preferred debugger connection transport: 19 | #debug.transport=dt_socket 20 | debug.classpath=\ 21 | ${run.classpath} 22 | debug.test.classpath=\ 23 | ${run.test.classpath} 24 | # Files in build.classes.dir which should be excluded from distribution jar 25 | dist.archive.excludes= 26 | # This directory is removed when the project is cleaned: 27 | dist.dir=dist 28 | dist.jar=${dist.dir}/JCProfiler.jar 29 | dist.javadoc.dir=${dist.dir}/javadoc 30 | endorsed.classpath= 31 | excludes= 32 | file.reference.commons-cli-1.3.1.jar=lib\\commons-cli-1.3.1.jar 33 | includes=** 34 | jar.compress=false 35 | javac.classpath=\ 36 | ${file.reference.commons-cli-1.3.1.jar} 37 | # Space-separated list of extra javac options 38 | javac.compilerargs= 39 | javac.deprecation=false 40 | javac.processorpath=\ 41 | ${javac.classpath} 42 | javac.source=1.8 43 | javac.target=1.8 44 | javac.test.classpath=\ 45 | ${javac.classpath}:\ 46 | ${build.classes.dir} 47 | javac.test.processorpath=\ 48 | ${javac.test.classpath} 49 | javadoc.additionalparam= 50 | javadoc.author=false 51 | javadoc.encoding=${source.encoding} 52 | javadoc.noindex=false 53 | javadoc.nonavbar=false 54 | javadoc.notree=false 55 | javadoc.private=false 56 | javadoc.splitindex=true 57 | javadoc.use=true 58 | javadoc.version=false 59 | javadoc.windowtitle= 60 | main.class=opencryptoutils.JCProfiler 61 | manifest.file=manifest.mf 62 | meta.inf.dir=${src.dir}/META-INF 63 | mkdist.disabled=false 64 | platform.active=default_platform 65 | run.classpath=\ 66 | ${javac.classpath}:\ 67 | ${build.classes.dir} 68 | # Space-separated list of JVM arguments used when running the project. 69 | # You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. 70 | # To set system properties for unit tests define test-sys-prop.name=value: 71 | run.jvmargs= 72 | run.test.classpath=\ 73 | ${javac.test.classpath}:\ 74 | ${build.test.classes.dir} 75 | source.encoding=UTF-8 76 | src.dir=src 77 | test.src.dir=test 78 | -------------------------------------------------------------------------------- /nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.java.j2seproject 4 | 5 | 6 | JCProfiler 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/opencryptoutils/JCProfiler.java: -------------------------------------------------------------------------------- 1 | package opencryptoutils; 2 | 3 | import java.io.IOException; 4 | import org.apache.commons.cli.*; 5 | 6 | 7 | /** 8 | * 9 | * @author Petr Svenda 10 | */ 11 | public class JCProfiler { 12 | private Options opts = new Options(); 13 | private static final String CLI_HEADER = "\nJCProfiler, a javacard profiler utility.\n\n"; 14 | private static final String CLI_FOOTER = "\nMIT Licensed\nCopyright (c) 2017 Petr Svenda , OpenCryptoProject"; 15 | 16 | public static void main(String[] args) { 17 | JCProfiler app = new JCProfiler(); 18 | app.run(args); 19 | } 20 | 21 | /** 22 | * @param args the command line arguments 23 | */ 24 | private void run(String[] args) { 25 | try { 26 | CommandLine cli = parseArgs(args); 27 | 28 | //if help, print and quit 29 | if (cli.hasOption("help")) { 30 | help(); 31 | return; 32 | } 33 | 34 | if (cli.hasOption("setTraps")) { 35 | PerfCodeGenerator gen = new PerfCodeGenerator(); 36 | 37 | String methodBaseName = cli.getOptionValue("methodBaseName", "EC_GEN"); 38 | String startConstString = cli.getOptionValue("trapIDStartConst", "7770"); 39 | short startTrapIDConst = Short.parseShort(startConstString, 16); 40 | PerfCodeConfig cfg = new PerfCodeConfig("not_set", methodBaseName, methodBaseName, 0, startTrapIDConst); 41 | 42 | String baseDir = cli.getOptionValue("baseDir", ""); 43 | gen.generatePersonalizedProfiler(cfg, baseDir); 44 | } 45 | } catch (MissingArgumentException maex) { 46 | System.err.println("Option, " + maex.getOption().getOpt() + " requires an argument: " + maex.getOption().getArgName()); 47 | } catch (NumberFormatException nfex) { 48 | System.err.println("Not a number. " + nfex.getMessage()); 49 | } catch (ParseException | IOException ex) { 50 | System.err.println(ex.getMessage()); 51 | } finally { 52 | } 53 | } 54 | 55 | 56 | /** 57 | * Parses command-line options. 58 | * 59 | * @param args cli arguments 60 | * @return parsed CommandLine object 61 | * @throws ParseException if there are any problems encountered while 62 | * parsing the command line tokens 63 | */ 64 | private CommandLine parseArgs(String[] args) throws ParseException { 65 | /* 66 | * Actions: 67 | * -st / --setTraps 68 | * 69 | * Options: 70 | * -bd / --baseDir [base_directory] 71 | * -mbd / --methodBaseName [name] 72 | * -tsc / --trapIDStartConst [start_constant] 73 | * 74 | */ 75 | OptionGroup actions = new OptionGroup(); 76 | actions.setRequired(true); 77 | actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); 78 | actions.addOption(Option.builder("st").longOpt("setTraps").desc("Parse input source code files, search for template performance traps and generates both card-side and client-side files for performance profiling.").build()); 79 | opts.addOptionGroup(actions); 80 | 81 | opts.addOption(Option.builder("tsc").longOpt("trapIDStartConst").desc("Initial start value (short) for trapID constants.").hasArg().argName("start_constant").build()); 82 | opts.addOption(Option.builder("bd").longOpt("baseDir").desc("Base directory with template files").hasArg().argName("base_directory").required(true).build()); 83 | opts.addOption(Option.builder("mbd").longOpt("methodBaseName").desc("Base name of method to be profiled.").hasArg().argName("name").required(true).build()); 84 | 85 | CommandLineParser parser = new DefaultParser(); 86 | return parser.parse(opts, args); 87 | } 88 | 89 | /** 90 | * Prints help. 91 | */ 92 | private void help() { 93 | HelpFormatter help = new HelpFormatter(); 94 | help.setOptionComparator(null); 95 | help.printHelp("JCProfiler.jar", CLI_HEADER, opts, CLI_FOOTER, true); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/opencryptoutils/PerfCodeConfig.java: -------------------------------------------------------------------------------- 1 | package opencryptoutils; 2 | 3 | /** 4 | * 5 | * @author Petr Svenda 6 | */ 7 | public class PerfCodeConfig { 8 | 9 | public String methodName; 10 | public String insBase; 11 | public String baseName; 12 | public String testName; 13 | public String apduCode; 14 | public int numStops; 15 | public int baseStopCode; 16 | 17 | PerfCodeConfig(String methodName, String insBase, String testName, int numStops, int baseStopCode) { 18 | this.methodName = methodName; 19 | this.insBase = insBase; 20 | this.baseName = String.format("TRAP_%s", insBase); 21 | this.apduCode = String.format("INS_%s", insBase); 22 | this.testName = testName; 23 | this.numStops = numStops; 24 | this.baseStopCode = baseStopCode; 25 | } 26 | PerfCodeConfig(PerfCodeConfig other) { 27 | this.methodName = other.methodName; 28 | this.insBase = other.insBase; 29 | this.baseName = other.baseName; 30 | this.apduCode = other.apduCode; 31 | this.testName = other.testName; 32 | this.numStops = other.numStops; 33 | this.baseStopCode = other.baseStopCode; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/opencryptoutils/PerfCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package opencryptoutils; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.FileReader; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.OutputStream; 11 | import java.nio.file.Files; 12 | import java.nio.file.NoSuchFileException; 13 | import static java.nio.file.StandardCopyOption.*; 14 | import java.util.ArrayList; 15 | 16 | /** 17 | * 18 | * @author Petr Svenda 19 | */ 20 | public class PerfCodeGenerator { 21 | public final static int MAX_TRAPS_PER_METHOD = 16; 22 | 23 | void generatePerfStopStrings() { 24 | ArrayList testList = new ArrayList<>(); 25 | /* 26 | testList.add(new PerfCodeConfig("EC_MUL", "EC scalar-point multiplication", 6, 0x7780)); 27 | 28 | testList.add(new PerfCodeConfig("BN_STR", "BigNatural Storage", 3, 0x7740)); 29 | testList.add(new PerfCodeConfig("BN_ADD", "BigNatural Addition", 7, 0x7730)); 30 | testList.add(new PerfCodeConfig("BN_SUB", "BigNatural Subtraction", 7, 0x7720)); 31 | testList.add(new PerfCodeConfig("BN_MUL", "BigNatural Multiplication", 6, 0x7710)); 32 | testList.add(new PerfCodeConfig("BN_EXP", "BigNatural Exponentiation", 6, 0x7700)); 33 | testList.add(new PerfCodeConfig("BN_MOD", "BigNatural Modulo", 5, 0x76f0)); 34 | testList.add(new PerfCodeConfig("BN_ADD_MOD", "BigNatural Addition (Modulo)", 7, 0x76e0)); 35 | testList.add(new PerfCodeConfig("BN_SUB_MOD", "BigNatural Subtraction (Modulo)", 6, 0x76d0)); 36 | testList.add(new PerfCodeConfig("BN_MUL_MOD", "BigNatural Multiplication (Modulo)", 6, 0x76c0)); 37 | testList.add(new PerfCodeConfig("BN_EXP_MOD", "BigNatural Exponentiation (Modulo)", 6, 0x76b0)); 38 | testList.add(new PerfCodeConfig("BN_INV_MOD", "BigNatural Inversion (Modulo)", 5, 0x76a0)); 39 | 40 | testList.add(new PerfCodeConfig("INT_STR", "Integer Storage", 2, 0x7690)); 41 | testList.add(new PerfCodeConfig("INT_ADD", "Integer Addition", 4, 0x7680)); 42 | testList.add(new PerfCodeConfig("INT_SUB", "Integer Subtraction", 4, 0x7670)); 43 | testList.add(new PerfCodeConfig("INT_MUL", "Integer Multiplication", 4, 0x7660)); 44 | testList.add(new PerfCodeConfig("INT_DIV", "Integer Division", 4, 0x7650)); 45 | testList.add(new PerfCodeConfig("INT_EXP", "Integer Exponentiation", 4, 0x7640)); 46 | testList.add(new PerfCodeConfig("INT_MOD", "Integer Modulo", 4, 0x7630)); 47 | 48 | testList.add(new PerfCodeConfig("ECCURVE_NEWKEYPAIR", "ECCurve_newKeyPair", 7, 0x75f0)); 49 | testList.add(new PerfCodeConfig("ECPOINT_ADD", "ECPoint_add", 7, 0x75e0)); 50 | testList.add(new PerfCodeConfig("ECPOINT_MULT", "ECPoint_multiplication", 12, 0x75d0)); 51 | */ 52 | testList.add(new PerfCodeConfig("short multiplication_x(", "ECPOINT_MULT_X", "ECPoint_multiplication_x", 5, 0x75c0)); 53 | testList.add(new PerfCodeConfig("void negate(", "ECPOINT_NEGATE", "ECPoint_negate", 5, 0x75b0)); 54 | 55 | generatePerfStopStrings(testList); 56 | } 57 | 58 | 59 | 60 | void generatePerfStopStrings(ArrayList testList) { 61 | 62 | for (PerfCodeConfig item : testList) { 63 | generatePerfTrapsStrings_TrapIDs(item.baseName, item.numStops, item.baseStopCode); 64 | System.out.println(); 65 | } 66 | System.out.println("\n ------------------ \n"); 67 | for (PerfCodeConfig item : testList) { 68 | generatePerfTrapsStrings_Mappings(item.baseName, item.numStops); 69 | System.out.println(); 70 | } 71 | System.out.println("\n ------------------ \n"); 72 | 73 | for (PerfCodeConfig item : testList) { 74 | generatePerfTrapsStrings_InitList(item.baseName, item.testName, item.numStops); 75 | } 76 | System.out.println("\n ------------------ \n"); 77 | 78 | } 79 | 80 | static String generatePerfTrapsStrings_TrapIDs(String baseName, int numStops, int baseOffset) { 81 | String result = String.format(" public static final short %s = (short) 0x%s;\n", baseName, Integer.toHexString(baseOffset)); 82 | for (int i = 1; i <= numStops; i++) { 83 | result += String.format(" public static final short %s_%d = (short) (%s + %d);\n", baseName, i, baseName, i); 84 | } 85 | result += String.format(" public static final short %s_COMPLETE = %s;\n", baseName, baseName); 86 | 87 | return result; 88 | } 89 | 90 | static String generatePerfTrapsStrings_Mappings(String baseName, int numStops) { 91 | String indent = " "; 92 | String result = ""; 93 | for (int i = 1; i <= numStops; i++) { 94 | result += String.format("%sPERF_TRAPS_MAPPING.put(PMC.%s_%d, \"%s_%d\");\n", indent, baseName, i, baseName, i); 95 | } 96 | result += String.format("%sPERF_TRAPS_MAPPING.put(PMC.%s_COMPLETE, \"%s_COMPLETE\");\n", indent, baseName, baseName); 97 | 98 | return result; 99 | } 100 | 101 | static String generatePerfTrapsStrings_InitList(String baseName, String testName, int numStops) { 102 | String indent = " "; 103 | String sanitizedTestName = testName.replace(" ", "_").replace("(", "_").replace(")", "_"); 104 | String result = String.format("%sshort[] PERFTRAPS_%s = {", indent, sanitizedTestName); 105 | for (int i = 1; i <= numStops; i++) { 106 | result += String.format("PMC.%s_%d, ", baseName, i); 107 | } 108 | result += String.format("PMC.%s_COMPLETE};\n", baseName); 109 | result += String.format("%scfg.perfStops = PERFTRAPS_%s;\n", indent, sanitizedTestName); 110 | result += String.format("%scfg.perfStopComplete = PMC.%s_COMPLETE;", indent, baseName); 111 | 112 | return result; 113 | } 114 | 115 | void insertPerfTraps(PerfCodeConfig cfg, String filePath) { 116 | try { 117 | BufferedReader br = new BufferedReader(new FileReader(filePath)); 118 | String filePathTransform = filePath + ".perf"; 119 | 120 | FileOutputStream fileOut = new FileOutputStream(filePathTransform); 121 | String strLine; 122 | String perfTrapLine = String.format("PerfMeasure.check(PerfMeasure.PERF_TEST_%s_0);\n", cfg.insBase); 123 | boolean bInsideTargetFunction = false; 124 | String methodNameEnd = String.format("end %s", cfg.methodName); 125 | 126 | // For every line of program insert generic performance trap 127 | while ((strLine = br.readLine()) != null) { 128 | if (bInsideTargetFunction) { 129 | if (strLine.contains(methodNameEnd)) { 130 | bInsideTargetFunction = false; 131 | } 132 | String strLineTrim = strLine.trim(); 133 | if (strLineTrim.length() > 0) { 134 | int indentCount = strLine.indexOf(strLineTrim); 135 | String indent = strLine.substring(0, indentCount); 136 | // non-zero line detected, insert perf trap with proper indentation 137 | fileOut.write(indent.getBytes()); 138 | fileOut.write(perfTrapLine.getBytes()); 139 | } 140 | } 141 | else { 142 | if (strLine.contains(cfg.methodName)) { 143 | bInsideTargetFunction = true; 144 | } 145 | } 146 | // Insert original line (always) 147 | strLine += "\n"; 148 | fileOut.write(strLine.getBytes()); 149 | } 150 | 151 | br.close(); 152 | fileOut.close(); 153 | } catch (Exception e) { 154 | System.out.println(String.format("Failed to transform file %s ", filePath) + e); 155 | } 156 | } 157 | 158 | void generatePersonalizedProfiler(PerfCodeConfig baseCfg, String baseDirectory) throws IOException { 159 | ArrayList filesWithTraps = new ArrayList<>(); 160 | 161 | // 162 | // Process all input files, try to find performance trap template and transform files with relevant traps 163 | // 164 | // make subdir for results 165 | String outputDirApplet = String.format("%s/target/profiler_applet/", baseDirectory); 166 | new File(outputDirApplet).mkdirs(); 167 | String outputDirClient = String.format("%s/target/profiler_client/", baseDirectory); 168 | new File(outputDirClient).mkdirs(); 169 | String baseAppletFilesDir = String.format("%s/templates/input_applet_files/", baseDirectory); 170 | File dir = new File(baseAppletFilesDir); 171 | String[] filesArray = dir.list(); 172 | if ((filesArray != null) && (dir.isDirectory() == true)) { 173 | 174 | for (String fileName : filesArray) { 175 | String filePath = baseAppletFilesDir + fileName; 176 | File inputFile = new File(filePath); 177 | if (!inputFile.isDirectory()) { 178 | // Copy file from templates to target 179 | String targetFilePathOrig = outputDirApplet + fileName + ".orig"; 180 | String targetFilePath = outputDirApplet + fileName; 181 | Files.copy(inputFile.toPath(), (new File(targetFilePathOrig)).toPath(), REPLACE_EXISTING); 182 | 183 | PerfCodeConfig cfg = new PerfCodeConfig(baseCfg); 184 | if (enumeratePerfTrapsFile(cfg, targetFilePathOrig, targetFilePath)) { 185 | filesWithTraps.add(cfg); 186 | } 187 | } 188 | } 189 | } 190 | 191 | // 192 | // Generate helper files for card-side profiler application 193 | // 194 | String templateAppletDir = String.format("%s/templates/template_profiler_applet/", baseDirectory); 195 | copy(new File(templateAppletDir), new File(outputDirApplet)); 196 | personalizeTemplatesApplet(filesWithTraps, outputDirApplet); //=> PM, PMC 197 | 198 | // 199 | // Generate helper files for client-side profiler application 200 | // 201 | String templateClientDir = String.format("%s/templates/template_profiler_client/", baseDirectory); 202 | copy(new File(templateClientDir), new File(outputDirClient)); 203 | ArrayList filesToCopy = new ArrayList<>(); 204 | filesToCopy.add(String.format("%s/PMC.java", outputDirApplet)); 205 | personalizeTemplatesClient(filesWithTraps, outputDirClient, filesToCopy); // JCProfiler_client 206 | 207 | 208 | System.out.println("\n\n#########################################"); 209 | System.out.println(String.format("INFO: The personalized profiler generation is now finished.")); 210 | System.out.println(String.format("Directory '%s' contains your applet's transformed files with numbered performance traps.\nNow you need to:", outputDirApplet)); 211 | System.out.println("1. Copy applet files (together with PMC.java and PM.java) back to your applet structure."); 212 | System.out.println("2. Open PM.java and PMC.java and update package to your applet's package name."); 213 | System.out.println("3. Open PM.java and *move* specified part of code (INS_PERF_SETSTOP) at the end of file to process() method of your applet."); 214 | System.out.println("4. Convert your applet and upload to target card as usual."); 215 | System.out.println(); 216 | System.out.println(String.format("Directory '%s' contains client-side code of the profiler.\nNow you need to:", outputDirClient)); 217 | System.out.println("1. Open PerfTests.java and correct APPLET_CLA, APPLET_AID according to your applet."); 218 | System.out.println("2. Open PerfTests.java and set proper apdu APDU_TRIGGER which will trigger (let execute) the method you like to profile (method which now have 'PM.check(PMC.TRAP_' inserted)."); 219 | System.out.println("3. (Optional) Set CARD_NAME to sensible string. If APDU_CLEANUP is set, this apdu is send to card after every measurement command (for 'cleaning')."); 220 | System.out.println("4. Compile and run JCProfiler_client. Measurement apdu commands are send to card and resulting measurements are inserted as comment directly behind the correspoding performance trap."); 221 | System.out.println(String.format("5. Inspect console results and modified files which are copied into directory '%s/perf/unique_experiment_id'.", outputDirApplet)); 222 | System.out.println(); 223 | 224 | 225 | } 226 | 227 | void personalizeTemplatesApplet(ArrayList filesWithTraps, String outputDirApplet) throws IOException { 228 | // 229 | // Personalize PMC.java 230 | // 231 | String PLACEHOLDER_PMC_CONSTANTS = "//### PLACEHOLDER PMC CONSTANTS"; 232 | String result = ""; 233 | for (PerfCodeConfig item : filesWithTraps) { 234 | result += generatePerfTrapsStrings_TrapIDs(item.baseName, item.numStops, item.baseStopCode); 235 | } 236 | String inputFilePath = String.format("%sPMC.java", outputDirApplet); 237 | System.out.println(String.format("INFO: Transforming file '%s' for trapID constants.", inputFilePath)); 238 | replaceStringInCopiedFile(inputFilePath, PLACEHOLDER_PMC_CONSTANTS, result, true); 239 | } 240 | 241 | void deleteFileNoExcept(String filePath) { 242 | try { 243 | Files.delete(new File(filePath).toPath()); 244 | } 245 | catch (NoSuchFileException ignored) {} 246 | catch (IOException ignored) {} 247 | } 248 | 249 | void personalizeTemplatesClient(ArrayList filesWithTraps, String outputDirClient, ArrayList filesToCopy) throws IOException { 250 | // 251 | // Personalize PerfTests.java 252 | // 253 | String resultPerfTrapInit = ""; 254 | String resultPerfTrapMappings = ""; 255 | for (PerfCodeConfig item : filesWithTraps) { 256 | resultPerfTrapInit += generatePerfTrapsStrings_InitList(item.baseName, item.testName, item.numStops); 257 | resultPerfTrapMappings += generatePerfTrapsStrings_Mappings(item.baseName, item.numStops); 258 | } 259 | String inputFilePath = String.format("%ssrc/jcprofiler/PerfTests.java", outputDirClient); 260 | 261 | System.out.println(String.format("INFO: Transforming file '%s' for code with trapID to send.", inputFilePath)); 262 | String PLACEHOLDER_PERFTRAPS_INIT = "//### PLACEHOLDER PERFTRAPS INIT"; 263 | replaceStringInCopiedFile(inputFilePath, PLACEHOLDER_PERFTRAPS_INIT, resultPerfTrapInit, true); 264 | 265 | System.out.println(String.format("INFO: Transforming file '%s' for code with mapping between name and trapID.", inputFilePath)); 266 | String PLACEHOLDER_PMC_MAPPINGS = "//### PLACEHOLDER PMC MAPPINGS"; 267 | replaceStringInCopiedFile(inputFilePath, PLACEHOLDER_PMC_MAPPINGS, resultPerfTrapMappings, true); 268 | 269 | // 270 | // Copy required personalized files from applet into client (constants etc.) 271 | // 272 | for (String fileToCopy : filesToCopy) { 273 | File file = new File(fileToCopy); 274 | String localPath = String.format("%s/src/jcprofiler/%s", outputDirClient, file.getName()); 275 | copy(new File(fileToCopy), new File(localPath)); 276 | } 277 | } 278 | 279 | boolean enumeratePerfTrapsFile(PerfCodeConfig cfg, String inputFilePath, String outputFilePath) { 280 | boolean bSomeTrapFound = false; 281 | System.out.println(String.format("INFO: Processing file '%s'", inputFilePath)); 282 | 283 | try { 284 | BufferedReader br = new BufferedReader(new FileReader(inputFilePath)); 285 | String filePathTransform = outputFilePath; 286 | FileOutputStream fileOut = new FileOutputStream(filePathTransform); 287 | String strLine; 288 | String perfTrapLineTemplate = String.format("PM.check(PMC.TRAP_%s_0);", cfg.insBase); 289 | String perfTrapCounterTemplate = String.format("%s_0", cfg.insBase); 290 | int perfTrapCount = 1; 291 | 292 | // For every line of program insert generic performance trap 293 | while ((strLine = br.readLine()) != null) { 294 | if (strLine.contains(perfTrapLineTemplate)) { 295 | bSomeTrapFound = true; // We found at least one trap! 296 | 297 | // Replace by trap with counter 298 | String perfTrapCounter = String.format("%s_%d", cfg.insBase, perfTrapCount); 299 | perfTrapCount++; 300 | if (perfTrapCount > MAX_TRAPS_PER_METHOD) { 301 | System.out.println(" Too much traps templates found - try to decrease below " + MAX_TRAPS_PER_METHOD); 302 | } 303 | 304 | strLine = strLine.replaceFirst(perfTrapCounterTemplate, perfTrapCounter); 305 | 306 | } 307 | // Insert original or modified final line 308 | strLine += "\n"; 309 | fileOut.write(strLine.getBytes()); 310 | } 311 | 312 | br.close(); 313 | fileOut.close(); 314 | 315 | if (!bSomeTrapFound) { 316 | System.out.println(String.format(" No template performance traps found in file '%s'", inputFilePath)); 317 | } 318 | else { 319 | System.out.println(String.format(" OK: Total '%d' traps found in file '%s'", perfTrapCount, inputFilePath)); 320 | } 321 | 322 | cfg.numStops = perfTrapCount - 1; 323 | } catch (Exception e) { 324 | System.out.println(String.format("Failed to transform file %s ", inputFilePath) + e); 325 | } 326 | 327 | return bSomeTrapFound; 328 | } 329 | 330 | boolean replaceStringInCopiedFile(String targetFilePath, String stringToFind, String stringReplace, boolean bLeaveFind) { 331 | boolean bReplacePerformed = false; 332 | try { 333 | String inputFilePathTmp = String.format("%s.tmp", targetFilePath); 334 | // make local copy 335 | deleteFileNoExcept(inputFilePathTmp); 336 | new File(targetFilePath).renameTo(new File(inputFilePathTmp)); 337 | 338 | // Transform file 339 | BufferedReader br = new BufferedReader(new FileReader(inputFilePathTmp)); 340 | FileOutputStream fileOut = new FileOutputStream(targetFilePath); 341 | String strLine; 342 | 343 | while ((strLine = br.readLine()) != null) { 344 | if (strLine.contains(stringToFind)) { 345 | if (bLeaveFind) { 346 | strLine = strLine.replaceFirst(stringToFind, String.format("%s\n\n%s", stringToFind, stringReplace)); 347 | } 348 | else { 349 | strLine = strLine.replaceFirst(stringToFind, stringReplace); 350 | } 351 | bReplacePerformed = true; 352 | } 353 | // Insert original or modified final line 354 | strLine += "\n"; 355 | fileOut.write(strLine.getBytes()); 356 | } 357 | br.close(); 358 | fileOut.close(); 359 | 360 | // Delete temp file 361 | deleteFileNoExcept(inputFilePathTmp); 362 | 363 | } catch (Exception e) { 364 | System.out.println(String.format(" Failed to transform file '%s' ", targetFilePath) + e); 365 | } 366 | 367 | if (!bReplacePerformed) { 368 | System.out.println(String.format(" Problem: no occurence of '%s' in file '%s'", stringToFind, targetFilePath)); 369 | } 370 | else { 371 | System.out.println(String.format(" OK: '%s' found and replaced", stringToFind)); 372 | } 373 | 374 | return bReplacePerformed; 375 | } 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | public void copy(File sourceLocation, File targetLocation) throws IOException { 385 | if (sourceLocation.isDirectory()) { 386 | copyDirectory(sourceLocation, targetLocation); 387 | } else { 388 | copyFile(sourceLocation, targetLocation); 389 | } 390 | } 391 | 392 | private void copyDirectory(File source, File target) throws IOException { 393 | if (!target.exists()) { 394 | target.mkdir(); 395 | } 396 | 397 | for (String f : source.list()) { 398 | copy(new File(source, f), new File(target, f)); 399 | } 400 | } 401 | 402 | private void copyFile(File source, File target) throws IOException { 403 | try ( 404 | InputStream in = new FileInputStream(source); 405 | OutputStream out = new FileOutputStream(target)) { 406 | byte[] buf = new byte[1024]; 407 | int length; 408 | while ((length = in.read(buf)) > 0) { 409 | out.write(buf, 0, length); 410 | } 411 | } 412 | } 413 | } 414 | --------------------------------------------------------------------------------