📄 javapursecrypto.java
字号:
short currentBalance = Util.getShort(balancesRecord, OFFSET_BAL_CURRENT); short maxBalance = Util.getShort(balancesRecord, OFFSET_BAL_MAX); short maxAmount = Util.getShort(balancesRecord, OFFSET_AMOUNT_MAX); switch (transactionType) { case CREDIT : { newBalance = (short)(currentBalance + amount); transientShorts[NEW_BALANCE_IX] = newBalance; if (newBalance > maxBalance || newBalance < 0) //to prevent rollover ISOException.throwIt(SW_CREDIT_TOO_HIGH); break; } case DEBIT : { if (amount > maxAmount) ISOException.throwIt(SW_AMOUNT_TOO_HIGH); newBalance = (short)(currentBalance - amount); transientShorts[NEW_BALANCE_IX] = newBalance; if (newBalance < 0)ISOException.throwIt(SW_NOT_ENOUGH_FUNDS); break; } default : ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } transientShorts[CURRENT_BALANCE_IX] = currentBalance; return currentBalance; } /** * Updates PIN. * @param apdu APDU object * @param PIN OwnerPIN object (masterPIN or userPIN) */ private void updatePIN(APDU apdu, OwnerPIN PIN){ byte[] buffer = apdu.getBuffer(); PIN.update(buffer, (short)(TLV_OFFSET + 2), buffer[TLV_OFFSET + 1]); } /** * Set JavaPurse in personalized state. * It happens only once - after the first update of masterPIN */ private void setIsPersonalized() { if (!isPersonalized) isPersonalized = true;//happens only once } /** * Update value of a Expiration Date or ID_Purse. Also updates corresponding * records in Parameters File * @param apdu APDU object * @param value the byte array to be updated */ private void updateParameterValue(APDU apdu, byte[] value){ byte[] buffer = apdu.getBuffer(); Util.arrayCopyNonAtomic(buffer, (short)(TLV_OFFSET + 2), value, START, buffer[TLV_OFFSET + 1]); updateParametersFile(apdu); } /** * Updates values of maximum balance or maximum amount for transaction in the * balancesRecord. * @param apdu APDU object * @param offset the offset in balancesRecord to be updated */ private void updateBalanceValue(APDU apdu, short offset){ byte[] buffer = apdu.getBuffer(); Util.arrayCopyNonAtomic(buffer, (short)(TLV_OFFSET + 2), balancesRecord, offset, SHORT_LENGTH); } /** * Updates record in Parameters File. * @param apdu APDU object */ private void updateParametersFile(APDU apdu){ byte[] buffer = apdu.getBuffer(); byte recordNumber = parametersFile.findRecord(buffer[TLV_OFFSET]);//match tag if (recordNumber == (byte)0) { /* * The record is not found. We have to create a new record. * NOTE: This is an example that a requirement to perform all memory * allocations (all "new") in class constructor is not an absolute one. */ byte[] newRecord = new byte[buffer[TLV_OFFSET + 1] + 2]; Util.arrayCopyNonAtomic(buffer, TLV_OFFSET, newRecord, START, (short)(buffer[TLV_OFFSET + 1] + 2)); parametersFile.addRecord(newRecord); } else { byte[] theRecord = parametersFile.getRecord(recordNumber); Util.arrayCopyNonAtomic(buffer, TLV_OFFSET, theRecord, START, (short)(buffer[TLV_OFFSET + 1] + 2)); } } /** * Selects file by FID according to ISO7816-4. * This implementation doesn't support all variations of SELECT command * in the standard, but provides reasonable subset for selection by FID * (P1==2). * @param apdu APDU object */ private void processSelectFile(APDU apdu){ byte[] buffer = apdu.getBuffer(); // get the apdu data apdu.setIncomingAndReceive(); if (buffer[ISO7816.OFFSET_P1] == (byte)2) { // select file by FID if ( buffer[ISO7816.OFFSET_LC] != (byte)2) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); short fid = Util.getShort(buffer, ISO7816.OFFSET_CDATA); switch (fid) { case PARAMETERS_FID: case TRANSACTION_LOG_FID: case BALANCES_FID: transientShorts[SELECTED_FILE_IX] = fid; break; default: ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } } else ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } /** * Reads a record by the record number or reads the first occurrence * of the record by the record identifier. * This implementation doesn't support all variations of READ RECORD command * in the ISO 7816-4 standard, but provides reasonable subset of it. It is * here to demonstrate that even without "built-in" support for ISO 7816 * File System an Applet can have the behavior prescribed by the standard. * * @param apdu APDU object */ private void processReadRecord(APDU apdu){ // used to hold the record read byte record[] = null; short fid = 0; // get the APDU buffer and fields in the APDU header byte buffer[] = apdu.getBuffer(); byte P1 = buffer[ISO7816.OFFSET_P1]; byte P2 = buffer[ISO7816.OFFSET_P2]; // process file selection here according to ISO 7816-4, 6.5.3 // P2 = xxxxxyyy // if xxxxx = 0, use the current selected file // xxxxx(not all equal) = other value, select EF by SFI as // specified in xxxxx if ( (P2 >> 3) == 0 ) { if (transientShorts[SELECTED_FILE_IX] == (short)0) ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); else fid = transientShorts[SELECTED_FILE_IX]; } else { // Short file identifier byte sfi = (byte) ( ( P2 >> 3 ) & 0x1F ); fid = Util.makeShort(FID_BYTE, sfi); switch (fid) { case PARAMETERS_FID: case TRANSACTION_LOG_FID: case BALANCES_FID: transientShorts[SELECTED_FILE_IX] = fid; break; default: ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } } // check for security status (validated PIN) switch (fid) { case TRANSACTION_LOG_FID: case BALANCES_FID: if (!userPIN.isValidated()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); break; case PARAMETERS_FID: if (!masterPIN.isValidated()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); } // get the last three bits of P2 P2 = (byte) (P2 & 0x07); // select the record by record number if ( ( P2 & 0x04 ) != 0 ){ if ( P2 == 0x04 ) { // P1 = 00 indicates in ISO 7816-4 the current record: we don't // support it in this implementation if (P1 == 0) ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND); switch (fid) { case BALANCES_FID: // There is only one record in balancesRecord if (P1 == 1) record = balancesRecord; else ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND); break; case TRANSACTION_LOG_FID: record = transactionLogFile.getRecord(P1); break; case PARAMETERS_FID: record = parametersFile.getRecord(P1); } if (record == null) ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); }else ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } else { // select record by record identifier (first byte of the record) // read the first occurrence if ( P2 == 0) { switch (fid) { case BALANCES_FID: // There is only one record in balancesRecords if (balancesRecord[0] == P1) record = balancesRecord; else ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND); break; case TRANSACTION_LOG_FID: P1 = transactionLogFile.findRecord(P1); if (P1 == 0 ) ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND); else record = transactionLogFile.getRecord(P1); break; case PARAMETERS_FID: P1 = parametersFile.findRecord(P1); if (P1 == 0 ) ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND); else record = parametersFile.getRecord(P1); } } else { // function not supported, when P2 = 1, 2, 3 ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } } // set the data transfer direction to outbound short Le = apdu.setOutgoing(); // if Lr < Le, set Le == Lr // otherwise send exactly Le bytes back if (record.length < Le) { Le = (short)record.length; } apdu.setOutgoingLength(Le); apdu.sendBytesLong(record, (short)0, Le); } /** * Updates loyalty program. * It takes standard TLV record for Parameter Update, interprets first * two bytes as loyaltyCAD (to be compared with first two bytes of CAD ID * in a transaction), the rest of record as AID for loyalty applet. * In case of successful retrieval of Shareable Interface Object with this AID * it is stored as an element of array, and method grantPoints of this loyalty * applet will be called in transaction to grant loyalty points. If SIO is not * returned, or loyaltyCAD in parameter is 0 the corresponding elements in * loyaltyCAD and loyaltySIO arrays are cleared. The Parameters File is updated. * * @param apdu APDU object * @param loyaltyIndex index to loyaltyCAD and loyaltySIO arrays * @see com.sun.javacard.JavaLoyalty.JavaLoyalty */ private void updateLoyaltyProgram(APDU apdu, byte loyaltyIndex){ byte[] buffer = apdu.getBuffer(); loyaltyCAD[loyaltyIndex] = Util.getShort(buffer,(short) (TLV_OFFSET+2)); if (loyaltyCAD[loyaltyIndex] != (short)0) { AID loyaltyAID = JCSystem.lookupAID(buffer, (short) (TLV_OFFSET+4), (byte)(buffer[TLV_OFFSET+1]-2)); if (loyaltyAID != null) { loyaltySIO[loyaltyIndex] = (JavaLoyaltyInterface) JCSystem.getAppletShareableInterfaceObject(loyaltyAID, (byte)0); if (loyaltySIO[loyaltyIndex] == null) loyaltyCAD[loyaltyIndex] = (short)0; } else loyaltyCAD[loyaltyIndex] = (short)0; } if (loyaltyCAD[loyaltyIndex] == (short)0) { // clean-up buffer[TLV_OFFSET+1] = (byte)2; Util.arrayFillNonAtomic (buffer,(short) (TLV_OFFSET+2), (short) (buffer.length - TLV_OFFSET - 2), (byte)0); } updateParametersFile(apdu); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -