📄 javapursecrypto.java
字号:
// AID buffer[2] = FCI_AID_TAG; buffer[3] = JCSystem.getAID().getBytes(buffer, (short)4); short offset=(short)(3+buffer[3]); // PROPRIETARY DATA buffer[offset++] = (byte)FCI_PROPERIETARY.length; offset = Util.arrayCopyNonAtomic(FCI_PROPERIETARY, (short)0, buffer, offset, (short)FCI_PROPERIETARY.length); // FCI template length buffer[1] = (byte)(offset-(short)2); apdu.setOutgoingAndSend((short)0, offset); } /** * Handles Initialize Transaction APDU. * <p>See <em>Java Card 2.1 Reference Implementation User's Guide</em> for details. * * @param apdu APDU object */ private void processInitializeTransaction(APDU apdu) { if (transientBools[TRANSACTION_INITIALIZED]) ISOException.throwIt(SW_COMMAND_OUT_OF_SEQUENCE); if (!userPIN.isValidated()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); byte[] buffer = apdu.getBuffer(); if (buffer[ISO7816.OFFSET_LC] != LC_IT) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); if (buffer[ISO7816.OFFSET_P2] != 0) ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); apdu.setIncomingAndReceive(); // get expected data byte transactionType = buffer[ISO7816.OFFSET_P1]; transientShorts[TRANSACTION_TYPE_IX] = transactionType; short amount = Util.getShort(buffer, ISO7816.OFFSET_CDATA); transientShorts[AMOUNT_IX] = amount; short balance = checkTransactionValues(transactionType, amount); // Increment TN in Transient Memory & compute signature short newTN = (short)(TN + 1); transientShorts[TN_IX] = newTN; Util.arrayCopyNonAtomic(buffer, CAD_ID_OFFSET, CAD_ID_array, START, ID_LENGTH); // Send R-APDU short offset = Util.arrayCopyNonAtomic(ID_Purse, START, buffer, START, ID_LENGTH); offset = Util.arrayCopyNonAtomic(ExpDate, START, buffer, offset, DATE_LENGTH); offset = Util.setShort(buffer, offset, balance); offset = Util.setShort(buffer, offset, newTN); // The crypto processing could be done here sig.init(deskey, Signature.MODE_SIGN); short sigLength = sig.sign(buffer, START, (short)(offset - START), byteArray8, (short)0); offset = Util.arrayCopyNonAtomic(byteArray8, START, buffer, offset, SIGNATURE_LENGTH); apdu.setOutgoingAndSend(START, (short)(offset - START)); transientBools[TRANSACTION_INITIALIZED] = true; } /** * Handles Complete Transaction APDU. * @param apdu APDU object */ private void processCompleteTransaction(APDU apdu) { if (!transientBools[TRANSACTION_INITIALIZED]) ISOException.throwIt(SW_COMMAND_OUT_OF_SEQUENCE); byte[] buffer = apdu.getBuffer(); if (buffer[ISO7816.OFFSET_LC] != LC_CT) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); if ((buffer[ISO7816.OFFSET_P1] != 0) || (buffer[ISO7816.OFFSET_P2] != 0)) ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); apdu.setIncomingAndReceive(); // get expected data //restore transaction data from transient short newTN = transientShorts[TN_IX]; short amount = transientShorts[AMOUNT_IX]; short newBalance = transientShorts[NEW_BALANCE_IX]; //The signature verification //get CLA, INS, P1, P2, LC short offset = Util.arrayCopyNonAtomic(buffer, (short)0, MAC_buffer,(byte)0, (short)5); Util.arrayCopyNonAtomic(buffer, offset, byteArray8,(byte)0, SIGNATURE_LENGTH); Util.arrayCopyNonAtomic(buffer, (short)(offset + SIGNATURE_LENGTH), MAC_buffer,(byte)5, (short)DATETIME_LENGTH); sig.init(deskey, Signature.MODE_VERIFY); boolean signatureOK = sig.verify(MAC_buffer, (short)0, (short)10, byteArray8, START, SIGNATURE_LENGTH); //prepare transaction record in APDU buffer offset = Util.setShort(buffer, START, newTN); buffer[offset] = (byte)transientShorts[TRANSACTION_TYPE_IX]; offset++; offset = Util.setShort(buffer, offset, amount); //CAD ID was left in this array from Initialize Transaction offset = Util.arrayCopyNonAtomic(CAD_ID_array, START, buffer, offset, ID_LENGTH); //Date and time are copied in APDU buffer to where they should go //in the transaction record. short balanceOffset = offset = Util.arrayCopyNonAtomic(buffer, (short)(ISO7816.OFFSET_CDATA + 8), buffer, offset, DATETIME_LENGTH); //Balance and SW will be added to transactionRecord later if (!signatureOK){ //Branch for unsuccessful transaction. Balance is not updated, //otherwise transactionLog is recorded the same way as in successful transaction offset = Util.setShort(buffer, offset, transientShorts[CURRENT_BALANCE_IX]); // old balance Util.setShort(buffer, offset, SW_WRONG_SIGNATURE); //done with preparing transaction record byte[] theRecord = transactionLogFile.getNewLogRecord(); //The following few steps have to be performed atomically! JCSystem.beginTransaction(); TN = newTN; Util.arrayCopy(buffer, START, theRecord, START, TRANSACTION_RECORD_LENGTH); transactionLogFile.updateNewLogRecord(); JCSystem.commitTransaction(); //Now we can throw exception transientBools[TRANSACTION_INITIALIZED] = false; ISOException.throwIt(SW_WRONG_SIGNATURE); } else { //Branch for successful transaction. offset = Util.setShort(buffer, offset, transientShorts[NEW_BALANCE_IX]); Util.setShort(buffer, offset, ISO7816.SW_NO_ERROR); // done with preparing transaction record byte[] theRecord = transactionLogFile.getNewLogRecord(); //The following few steps have to be performed atomically! JCSystem.beginTransaction(); TN = transientShorts[TN_IX]; //Update balance Util.setShort(balancesRecord, START, newBalance); Util.arrayCopy(buffer, START, theRecord, START, TRANSACTION_RECORD_LENGTH); transactionLogFile.updateNewLogRecord(); JCSystem.commitTransaction(); } // Do loyalty work // We have all the information in the buffer, the loyalty applets shouldn't // know transaction number and the balance of purse - so we zero out these // fields first Util.setShort(buffer, START, (short)0); Util.setShort(buffer, balanceOffset, (short)0); short loyaltyCADValue = Util.getShort(CAD_ID_array, START); for (byte loyaltyIndex = 0; loyaltyIndex < MAX_LOYALTY; loyaltyIndex++) if (loyaltyCAD[loyaltyIndex] == loyaltyCADValue) { loyaltySIO[loyaltyIndex].grantPoints (buffer);break;} offset = Util.setShort(MAC_buffer, START, newBalance); Util.setShort(MAC_buffer, offset, SW_SUCCESS); sig.init(deskey, Signature.MODE_SIGN); short sigLength = sig.sign(MAC_buffer, (short)0, (short)4, byteArray8, (short)0); //send R-APDU offset = Util.setShort(buffer, START, newBalance); offset = Util.arrayCopyNonAtomic(byteArray8, START, buffer, offset, SIGNATURE_LENGTH); apdu.setOutgoingAndSend(START, (short)(offset - START)); transientBools[TRANSACTION_INITIALIZED] = false; } /** * Handles Initialize Parameter Update APDU. * * <p><em>NOTE:</em> In this sample implementation we assume that all the * Parameter Updates are performed in somewhat secured facility and therefor * the tearing of the card is not an issue. That's why we don't do any * transactional protection while processing Initialize and Complete * Parameter Update APDU commands. * * @param apdu APDU object */ private void processInitializeUpdate(APDU apdu) { if (transientBools[UPDATE_INITIALIZED]) ISOException.throwIt(SW_COMMAND_OUT_OF_SEQUENCE); if (!masterPIN.isValidated() && isPersonalized) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); byte[] buffer = apdu.getBuffer(); if ((buffer[ISO7816.OFFSET_P1] != 0) || (buffer[ISO7816.OFFSET_P2] != 0)) ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); // Because this is a case 2 command (outgoing data only), the contents of P3 // are undefined. In T=0, P3 is Le. In T=1, P3 is Lc. Therefore, we don't // bother to test the contents of buffer[ISO7816.OFFSET_LC]. PUN++; //Increment parameter Update Number // Send R-APDU short offset = Util.arrayCopyNonAtomic(ID_Purse, START, buffer, START, ID_LENGTH); offset = Util.arrayCopyNonAtomic(ExpDate, START, buffer, offset, DATE_LENGTH); offset = Util.setShort(buffer, offset, PUN); apdu.setOutgoingAndSend(START, (short)(offset - START)); transientBools[UPDATE_INITIALIZED] = true; } /** * Handles Complete Parameter Update APDU. * @param apdu APDU object */ private void processCompleteUpdate(APDU apdu) { if (!transientBools[UPDATE_INITIALIZED]) ISOException.throwIt(SW_COMMAND_OUT_OF_SEQUENCE); byte[] buffer = apdu.getBuffer(); if ((buffer[ISO7816.OFFSET_P1] != 0) || (buffer[ISO7816.OFFSET_P2] != 0)) ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); short count = apdu.setIncomingAndReceive(); // get expected data byte lc = buffer[ISO7816.OFFSET_LC]; //The signature verification //get CLA, INS, P1, P2, LC //message to sign length short messageLength = (short)(lc - SIGNATURE_LENGTH + 5); short offset = Util.arrayCopyNonAtomic(buffer, (short)0, MAC_buffer,(byte)0, (short)messageLength); offset = Util.arrayCopyNonAtomic(buffer, offset, byteArray8,(byte)0, SIGNATURE_LENGTH); // verify signature if in coming apdu sig.init(deskey, Signature.MODE_VERIFY); boolean signatureOK = sig.verify(MAC_buffer, (short)0, messageLength, byteArray8, START, SIGNATURE_LENGTH); if (!signatureOK) ISOException.throwIt(SW_WRONG_SIGNATURE); switch (buffer[TLV_OFFSET]) { case MASTER_PIN_UPDATE: updatePIN(apdu, masterPIN); setIsPersonalized(); break; case USER_PIN_UPDATE: updatePIN(apdu, userPIN); break; case EXP_DATE_UPDATE: updateParameterValue(apdu, ExpDate); break; case PURSE_ID_UPDATE: updateParameterValue(apdu, ID_Purse); break; case MAX_BAL_UPDATE: updateBalanceValue(apdu, OFFSET_BAL_MAX); break; case MAX_M_UPDATE: updateBalanceValue(apdu, OFFSET_AMOUNT_MAX); break; case VERSION_UPDATE: updateParametersFile(apdu); break; case LOYALTY1_UPDATE: updateLoyaltyProgram(apdu, (byte)0); break; case LOYALTY2_UPDATE: updateLoyaltyProgram(apdu, (byte)1); break; case LOYALTY3_UPDATE: updateLoyaltyProgram(apdu, (byte)2); break; case LOYALTY4_UPDATE: updateLoyaltyProgram(apdu, (byte)3); break; default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } //sign the return message //Admittedly, this is a poor MAC, but this message only returns the status //(what is MACed here) and the MAC itself. A real application should return a //little more information. offset = Util.setShort(MAC_buffer, START, SW_SUCCESS); sig.init(deskey, Signature.MODE_SIGN); short sigLength = sig.sign(MAC_buffer, (short)0, (short)2, byteArray8, (short)0); //send R-APDU //offset = Util.arrayCopyNonAtomic(byteArray8, START, buffer, offset, SIGNATURE_LENGTH); Util.arrayCopyNonAtomic(byteArray8, START, buffer, START, SIGNATURE_LENGTH); apdu.setOutgoingAndSend(START, SIGNATURE_LENGTH); transientBools[UPDATE_INITIALIZED] = false; } /** * Handles Verify Pin APDU. * @param apdu APDU object */ private void processVerifyPIN(APDU apdu) { byte[] buffer = apdu.getBuffer(); byte pinLength = buffer[ISO7816.OFFSET_LC]; byte triesRemaining = (byte)0; short count = apdu.setIncomingAndReceive(); // get expected data if (count < pinLength) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); byte pinType = buffer[ISO7816.OFFSET_P2]; switch (pinType) { case MASTER_PIN: if (!masterPIN.check(buffer, ISO7816.OFFSET_CDATA, pinLength)){ triesRemaining = masterPIN.getTriesRemaining(); //The last nibble of return code is number of remaining tries ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining)); } break; case USER_PIN: if (!userPIN.check(buffer, ISO7816.OFFSET_CDATA, pinLength)){ triesRemaining = userPIN.getTriesRemaining(); //The last nibble of return code is number of remaining tries ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining)); } break; default: ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } } /** * Verifies numerical limitations on Transaction Amount. * * <p><em>NOTE:</em> With some values of maxBalance and maxAmount the logic * in this method might become somewhat unrealistic. It's the result of using * short arithmetic on values which might be too big to fit in short variables. * * @param transactionType type of transaction. * @param amount transaction amount. * @return new balance */ private short checkTransactionValues(byte transactionType, short amount) { short newBalance;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -