Advertisement
Guest User

Untitled

a guest
Apr 22nd, 2019
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.52 KB | None | 0 0
  1. /**
  2. * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
  3. *
  4. */
  5.  
  6. /*
  7. */
  8.  
  9. /*
  10. * @(#)Wallet.java 1.11 06/01/03
  11. */
  12.  
  13. package com.sun.jcclassic.samples.wallet;
  14.  
  15. import javacard.framework.APDU;
  16. import javacard.framework.Applet;
  17. import javacard.framework.ISO7816;
  18. import javacard.framework.ISOException;
  19. import javacard.framework.OwnerPIN;
  20.  
  21. public class Wallet extends Applet {
  22.  
  23. /* constants declaration */
  24.  
  25. // code of CLA byte in the command APDU header
  26. final static byte Wallet_CLA = (byte) 0x80;
  27. final static byte Cash_P1 = (byte) 0x01;
  28. final static byte Points_P1 = (byte) 0x02;
  29.  
  30. // codes of INS byte in the command APDU header
  31. final static byte VERIFY = (byte) 0x20;
  32. final static byte CREDIT = (byte) 0x30;
  33. final static byte DEBIT = (byte) 0x40;
  34. final static byte GET_BALANCE = (byte) 0x50;
  35. final static byte UPDATE_PIN = (byte) 0x70;
  36.  
  37. // maximum balance
  38. final static short MAX_BALANCE = 0x2710;
  39. // maximum transaction amount
  40. final static short MAX_TRANSACTION_AMOUNT = 0x2710;
  41.  
  42. // maximum points balance
  43. final static short MAX_POINTS_BALANCE = 0x12c;
  44.  
  45. // maximum number of incorrect tries before the
  46. // PIN is blocked
  47. final static byte PIN_TRY_LIMIT = (byte) 0x03;
  48. // maximum size PIN
  49. final static byte MAX_PIN_SIZE = (byte) 0x08;
  50.  
  51. // signal that the PIN verification failed
  52. final static short SW_VERIFICATION_FAILED = 0x6300;
  53. // signal the the PIN validation is required
  54. // for a credit or a debit transaction
  55. final static short SW_PIN_VERIFICATION_REQUIRED = 0x6301;
  56. // signal invalid transaction amount
  57. // amount > MAX_TRANSACTION_AMOUNT or amount < 0
  58. final static short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83;
  59.  
  60. // signal that the balance exceed the maximum
  61. final static short SW_EXCEED_MAXIMUM_BALANCE = 0x6A84;
  62. // signal the the balance becomes negative
  63. final static short SW_NEGATIVE_BALANCE = 0x6A85;
  64.  
  65. /* instance variables declaration */
  66. OwnerPIN pin;
  67. short balance;
  68. short pointsBalance;
  69. byte[] maxPointsReached = new byte[] { 0, 0, 0 };
  70.  
  71. private Wallet(byte[] bArray, short bOffset, byte bLength) {
  72.  
  73. // It is good programming practice to allocate
  74. // all the memory that an applet needs during
  75. // its lifetime inside the constructor
  76. pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
  77.  
  78. byte iLen = bArray[bOffset]; // aid length
  79. bOffset = (short) (bOffset + iLen + 1);
  80. byte cLen = bArray[bOffset]; // info length
  81. bOffset = (short) (bOffset + cLen + 1);
  82. byte aLen = bArray[bOffset]; // applet data length
  83.  
  84. // The installation parameters contain the PIN
  85. // initialization value
  86. pin.update(bArray, (short) (bOffset + 1), aLen);
  87. register();
  88.  
  89. } // end of the constructor
  90.  
  91. public static void install(byte[] bArray, short bOffset, byte bLength) {
  92. // create a Wallet applet instance
  93. new Wallet(bArray, bOffset, bLength);
  94. } // end of install method
  95.  
  96. @Override
  97. public boolean select() {
  98.  
  99. // The applet declines to be selected
  100. // if the pin is blocked.
  101. if (pin.getTriesRemaining() == 0) {
  102. return false;
  103. }
  104.  
  105. return true;
  106.  
  107. }// end of select method
  108.  
  109. @Override
  110. public void deselect() {
  111.  
  112. // reset the pin value
  113. pin.reset();
  114.  
  115. }
  116.  
  117. @Override
  118. public void process(APDU apdu) {
  119.  
  120. // APDU object carries a byte array (buffer) to
  121. // transfer incoming and outgoing APDU header
  122. // and data bytes between card and CAD
  123.  
  124. // At this point, only the first header bytes
  125. // [CLA, INS, P1, P2, P3] are available in
  126. // the APDU buffer.
  127. // The interface javacard.framework.ISO7816
  128. // declares constants to denote the offset of
  129. // these bytes in the APDU buffer
  130.  
  131. byte[] buffer = apdu.getBuffer();
  132. // check SELECT APDU command
  133.  
  134. if (apdu.isISOInterindustryCLA()) {
  135. if (buffer[ISO7816.OFFSET_INS] == (byte) (0xA4)) {
  136. return;
  137. }
  138. ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
  139. }
  140.  
  141. // verify the reset of commands have the
  142. // correct CLA byte, which specifies the
  143. // command structure
  144. if (buffer[ISO7816.OFFSET_CLA] != Wallet_CLA) {
  145. ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
  146. }
  147.  
  148. switch (buffer[ISO7816.OFFSET_INS]) {
  149. case GET_BALANCE:
  150. getBalance(apdu);
  151. return;
  152. case DEBIT:
  153. debit(apdu);
  154. return;
  155. case CREDIT:
  156. credit(apdu);
  157. return;
  158. case VERIFY:
  159. verify(apdu);
  160. return;
  161. case UPDATE_PIN:
  162. update(apdu);
  163. return;
  164. default:
  165. ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
  166. }
  167.  
  168. } // end of process method
  169.  
  170. private void credit(APDU apdu) {
  171.  
  172. // access authentication
  173. if (!pin.isValidated()) {
  174. ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
  175. }
  176.  
  177. byte[] buffer = apdu.getBuffer();
  178.  
  179. // Lc byte denotes the number of bytes in the
  180. // data field of the command APDU
  181. byte numBytes = buffer[ISO7816.OFFSET_LC];
  182.  
  183. // indicate that this APDU has incoming data
  184. // and receive data starting from the offset
  185. // ISO7816.OFFSET_CDATA following the 5 header
  186. // bytes.
  187. byte byteRead = (byte) (apdu.setIncomingAndReceive());
  188.  
  189. // it is an error if the number of data bytes
  190. // read does not match the number in Lc byte
  191. if ((numBytes != 2) || (byteRead != 2)) {
  192. ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  193. }
  194.  
  195. // get the credit amount
  196. short creditAmount = (short) (buffer[ISO7816.OFFSET_CDATA] & 0xFF);
  197. creditAmount = (short) (creditAmount << 8);
  198. creditAmount = (short) (creditAmount | (buffer[ISO7816.OFFSET_CDATA + 1] & 0xFF));
  199. // check the credit amount
  200. if ((creditAmount > MAX_TRANSACTION_AMOUNT) || (creditAmount < 0)) {
  201. ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
  202. }
  203.  
  204. // check the new balance
  205. if ((short) (balance + creditAmount) > MAX_BALANCE) {
  206. ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);
  207. }
  208.  
  209. // credit the amount
  210. balance = (short) (balance + creditAmount);
  211.  
  212. } // end of deposit method
  213.  
  214. private void debit(APDU apdu) {
  215.  
  216. // access authentication
  217. if (!pin.isValidated()) {
  218. ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
  219. }
  220.  
  221. byte[] buffer = apdu.getBuffer();
  222.  
  223. byte numBytes = (buffer[ISO7816.OFFSET_LC]);
  224.  
  225. byte byteRead = (byte) (apdu.setIncomingAndReceive());
  226.  
  227. if ((numBytes != 5) || (byteRead != 5)) {
  228. ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  229. }
  230.  
  231. // get debit amount
  232. short debitAmount = (short) (buffer[ISO7816.OFFSET_CDATA] & 0xFF);
  233. debitAmount = (short) (debitAmount << 8);
  234. debitAmount = (short) (debitAmount | (buffer[ISO7816.OFFSET_CDATA + 1] & 0xFF));
  235.  
  236. // check debit amount
  237. if ((debitAmount > MAX_TRANSACTION_AMOUNT) || (debitAmount < 0)) {
  238. ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
  239. }
  240.  
  241. if (buffer[ISO7816.OFFSET_P1] == Cash_P1) {
  242. // check the new balance
  243. if ((short) (balance - debitAmount) < (short) 0) {
  244. ISOException.throwIt(SW_NEGATIVE_BALANCE);
  245. }
  246.  
  247. balance = (short) (balance - debitAmount);
  248. if (pointsBalance < MAX_POINTS_BALANCE) {
  249. pointsBalance = (short) (pointsBalance + debitAmount / 20);
  250. if (pointsBalance >= MAX_POINTS_BALANCE) {
  251. pointsBalance = MAX_POINTS_BALANCE;
  252. maxPointsReached[0] = buffer[ISO7816.OFFSET_CDATA + 2];
  253. maxPointsReached[1] = buffer[ISO7816.OFFSET_CDATA + 3];
  254. maxPointsReached[2] = buffer[ISO7816.OFFSET_CDATA + 4];
  255.  
  256. }
  257. }
  258. } else if (buffer[ISO7816.OFFSET_P1] == Points_P1) {
  259. short bonus_period = 0;
  260. if (maxPointsReached[2] == buffer[ISO7816.OFFSET_CDATA + 4])
  261. if (maxPointsReached[1] == buffer[ISO7816.OFFSET_CDATA + 3]) {
  262. if (buffer[ISO7816.OFFSET_CDATA + 2] - maxPointsReached[0] <= 30)
  263. bonus_period = 1;
  264. } else if (maxPointsReached[1] < buffer[ISO7816.OFFSET_CDATA + 3]) {
  265. short days = (short) (30 - maxPointsReached[1] + buffer[ISO7816.OFFSET_CDATA + 2]);
  266. if (days <= 30)
  267. bonus_period = 1;
  268.  
  269. }
  270. if (bonus_period == 1 && pointsBalance == MAX_POINTS_BALANCE) {
  271. if ((short) (2 * pointsBalance - debitAmount) < (short) 0) {
  272. ISOException.throwIt(SW_NEGATIVE_BALANCE);
  273. }
  274. pointsBalance = (short) ((short)(2 * pointsBalance - debitAmount) / 2);
  275. } else {
  276. if ((short) (pointsBalance - debitAmount) < (short) 0) {
  277. ISOException.throwIt(SW_NEGATIVE_BALANCE);
  278. }
  279. pointsBalance = (short) (pointsBalance - debitAmount);
  280. }
  281. }
  282.  
  283. } // end of debit method
  284.  
  285. private void getBalance(APDU apdu) {
  286.  
  287. byte[] buffer = apdu.getBuffer();
  288.  
  289. // inform system that the applet has finished
  290. // processing the command and the system should
  291. // now prepare to construct a response APDU
  292. // which contains data field
  293. short le = apdu.setOutgoing();
  294.  
  295. if (le < 2) {
  296. ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  297. }
  298.  
  299. // informs the CAD the actual number of bytes
  300. // returned
  301. apdu.setOutgoingLength((byte) 2);
  302.  
  303. if (buffer[ISO7816.OFFSET_P1] == Cash_P1) {
  304. // move the balance data into the APDU buffer
  305. // starting at the offset 0
  306. buffer[0] = (byte) (balance >> 8);
  307. buffer[1] = (byte) (balance & 0xFF);
  308.  
  309. // send the 2-byte balance at the offset
  310. // 0 in the apdu buffer
  311. apdu.sendBytes((short) 0, (short) 2);
  312. } else if (buffer[ISO7816.OFFSET_P1] == Points_P1) {
  313. buffer[0] = (byte) (pointsBalance >> 8);
  314. buffer[1] = (byte) (pointsBalance & 0xFF);
  315. apdu.sendBytes((short) 0, (short) 2);
  316. }
  317.  
  318. } // end of getBalance method
  319.  
  320. private void verify(APDU apdu) {
  321.  
  322. byte[] buffer = apdu.getBuffer();
  323. // retrieve the PIN data for validation.
  324. byte byteRead = (byte) (apdu.setIncomingAndReceive());
  325.  
  326. // check pin
  327. // the PIN data is read into the APDU buffer
  328. // at the offset ISO7816.OFFSET_CDATA
  329. // the PIN data length = byteRead
  330. if (pin.check(buffer, ISO7816.OFFSET_CDATA, byteRead) == false) {
  331. ISOException.throwIt(SW_VERIFICATION_FAILED);
  332. }
  333.  
  334. } // end of validate method
  335.  
  336. private void update(APDU apdu) {
  337. byte[] buffer = apdu.getBuffer();
  338. // retrieve the PIN data for validation.
  339. byte byteRead = (byte) (apdu.setIncomingAndReceive());
  340. byte oldPinLen = buffer[(short) (ISO7816.OFFSET_CDATA)]; // old pin length
  341. byte newPinLen = buffer[(short) (ISO7816.OFFSET_CDATA + oldPinLen + 1)];
  342.  
  343. // check pin
  344. // the PIN data is read into the APDU buffer
  345. // at the offset ISO7816.OFFSET_CDATA
  346. // the PIN data length = byteRead
  347. if (pin.getTriesRemaining() == 0) {
  348. ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
  349. }
  350.  
  351. if (pin.check(buffer, (short) (ISO7816.OFFSET_CDATA + 1), oldPinLen) == false) {
  352. ISOException.throwIt(SW_VERIFICATION_FAILED);
  353. }
  354.  
  355. pin.update(buffer, (short) (ISO7816.OFFSET_CDATA + oldPinLen + 2), newPinLen);
  356.  
  357. }
  358. } // end of class Wallet
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement