📄 shasoftauth.java
字号:
user.readAccountData(accountData,0); //get the user's verification data System.arraycopy(accountData,I_VERDATA,this.ver_data,0,7); //get the mac from the account data page System.arraycopy(accountData, I_SIGNATURE, verify_mac, 0, 20); //now lets reset the mac copr.getInitialSignature(accountData, I_SIGNATURE); //and reset the CRC accountData[I_FILE_CRC16+0] = (byte)0; accountData[I_FILE_CRC16+1] = (byte)0; //now we also need to get things like wcc, user_page_number, user ID if(wcc<0) { if(user.hasWriteCycleCounter()) { // failed to read account data this.lastError = USER_READ_AUTH_FAILED; return false; } //has no write cycle counter System.arraycopy(ffBlock, 0, scratchpad, 8, 4); } else { //copy the write cycle counter into scratchpad Convert.toByteArray(wcc, scratchpad, 8, 4); } scratchpad[12] = (byte)user.getAccountPageNumber(); user.getAddress(scratchpad, 13, 7); copr.getSigningChallenge(scratchpad, 20); if(!copr.verifySignature(accountData, scratchpad, verify_mac)) { this.lastError = COPROCESSOR_FAILURE; return false; } return true; } //prevent malloc'ing in critical path private byte[] executeTransaction_accountData = new byte[32]; private byte[] executeTransaction_oldAcctData = new byte[32]; private byte[] executeTransaction_newAcctData = new byte[32]; //private byte[] executeTransaction_scratchpad = new byte[32]; /** * <P>Performs the signed debit, subtracting the debit amount from * the user's balance and storing the new, signed account data on the * user's iButton. The debit amount can be set using * <code>transaction.setParameter(SHADebit.DEBIT_AMOUNT, 50)</code>, * where the value is in units of cents (i.e. for 1 dollar, use 100).</P> * * <P><B>Flow of action: </B> * <ul> * <li> Read the account data from user </li> * <li> Extract account balance </li> * <li> Reset the digital signature </li> * <li> Use coprocessor to sign account data </li> * <li> Insert the new digital signature </li> * <li> Write the account data to the user </li> * </ul></P> * * <P>If previous steps have been executed, all "Read" commands on * the user are reading from cached data.</P> * * @param user SHAiButtonUser upon which the transaction occurs. * @param verifySuccess A boolean to let this method know if verification * was successful. * * @return <code>true</code> if and only if the user has enough in the * account balance to perform the requested debit AND a new digital * signature is successfully created AND the account data has been written * to the button. * * @see SHAiButtonUser#readAccountData(byte[],int) * @see SHAiButtonUser#writeAccountData(byte[],int) * @see SHAiButtonCopr#createDataSignature(byte[],byte[],byte[],int) * @see #getLastError() */ public synchronized boolean executeTransaction(SHAiButtonUser user, boolean verifySuccess) throws OneWireException, OneWireIOException { //clear any error this.lastError = NO_ERROR; //init local vars //holds the working copy of account data byte[] accountData = this.executeTransaction_accountData; //holds the backup copy of account data before writing byte[] oldAcctData = this.executeTransaction_oldAcctData; //holds the account data read back for checking byte[] newAcctData = this.executeTransaction_newAcctData; //if verifyUser was called, this is a read of cached data user.readAccountData(accountData,0); //before we update the account data array at all, let's make a backup copy System.arraycopy(accountData, 0, oldAcctData, 0, 32); //get the user's verification data System.arraycopy(accountData,I_VERDATA,this.ver_data,0,7); boolean success = writeTransactionData(user, this.master_ver_data, accountData); //if write didn't succeeded or if we need to perform //a verification step anyways, let's double-check what //the user has on the button. if(verifySuccess || !success) { boolean dataOK = false; int cnt = MAX_RETRY_CNT; do { //calling verify user re-issues a challenge-response //and reloads the cached account data in the user object. if(verifyUser(user)) { //compare the user's account data against the working //copy and the backup copy. if(user.readAccountData(newAcctData,0)) { boolean isOld = true; boolean isCur = true; for(int i=0; i<32 && (isOld||isCur); i++) { //match the backup isOld = isOld && (newAcctData[i]==oldAcctData[i]); //match the working copy isCur = isCur && (newAcctData[i]==accountData[i]); } if(isOld) { //if it matches the backup copy, we didn't write anything //and the data is still okay, but we didn't do a debit dataOK = true; success = false; } else if(isCur) { dataOK = true; } else { //iBUTTON DATA IS TOTALLY HOSED //keep trying to get account data on the button success = writeTransactionData(user, this.ver_data, accountData); } } } } while(!dataOK && cnt-->0); if(!dataOK) { //couldn't fix the data after 255 retries IOHelper.writeLine("Catastrophic Failure!"); success = false; } } return success; } private byte[] writeTransactionData_scratchpad = new byte[32]; /** * Does the writing of transaction data to the user button as well * as actually signing the data with the coprocessor. */ private final boolean writeTransactionData(SHAiButtonUser user, byte[] ver_data, byte[] accountData) throws OneWireException, OneWireIOException { //init local vars SHAiButtonCopr copr = this.copr; int acctPageNum = user.getAccountPageNumber(); byte[] scratchpad = this.writeTransactionData_scratchpad; // length of the TMEX file - 28 data, 1 cont. ptr accountData[I_FILE_LENGTH] = (byte)29; System.arraycopy(ver_data,0,accountData,I_VERDATA,7); // initial signature - 20 data bytes copr.getInitialSignature(accountData, I_SIGNATURE); // data type code - dynamic: 0x00, static: 0x01 accountData[I_DATA_TYPE_CODE] = 0x01; // continuation pointer for TMEX file accountData[I_CONTINUATION_PTR] = 0x00; // clear out the crc16 - 2 data bytes accountData[I_FILE_CRC16+0] = 0x00; accountData[I_FILE_CRC16+1] = 0x00; //we need to increment the writeCycleCounter since we will be writing to the part int wcc = user.getWriteCycleCounter(); if(wcc>0) { //copy the write cycle counter into scratchpad Convert.toByteArray(wcc+1, scratchpad, 8, 4); } else { if(user.hasWriteCycleCounter()) { // failed to read account data this.lastError = this.USER_READ_AUTH_FAILED; return false; } System.arraycopy(ffBlock, 0, scratchpad, 8, 4); } // svcPageNumber, followed by address of device scratchpad [12] = (byte)acctPageNum; user.getAddress(scratchpad, 13, 7); // copy in the signing challenge copr.getSigningChallenge(scratchpad, 20); // sign the data, return the mac right into accountData copr.createDataSignature(accountData, scratchpad, accountData, I_SIGNATURE); //after signature make sure to dump in the inverted CRC int crc = ~CRC16.compute(accountData, 0, accountData[I_FILE_LENGTH] + 1, acctPageNum); //set the the crc16 bytes accountData[I_FILE_CRC16+0] = (byte)crc; accountData[I_FILE_CRC16+1] = (byte)(crc>>8); //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// if(DEBUG) { IOHelper.writeLine("------------------------------------"); IOHelper.writeLine("writing transaction data"); IOHelper.writeLine("acctPageNum: " + acctPageNum); IOHelper.writeLine("accountData"); IOHelper.writeBytesHex(accountData); IOHelper.writeLine("------------------------------------"); } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// // write it to the button try { if(user.writeAccountData(accountData, 0)) return true; } catch(OneWireException owe) { if(DEBUG) IOHelper.writeLine(owe); } this.lastError = this.USER_WRITE_DATA_FAILED; return false; } /** * <P>Retrieves the value of a particular parameter for this * debit transaction.</P> * * <P><B>Valid Parameters</B> * <UL> * <LI><code>SHADebit.DEBIT_AMOUNT</code></LI> * <LI><code>SHADebit.INITIAL_AMOUNT</code></LI> * <LI><code>SHADebit.USER_BALANCE</code></LI> * </UL> * </P> * * <P>Note that the value of <code>SHADebit.USER_BALANCE</code> will * be set after calling <code>verifyTransactionData(SHAiButtonUser)</code> * and after calling <code>executeTransaction(SHAiButtonUser)</code>.</P> * * @return The value of the requested parameter. * * @throws IllegalArgumentException if an invalid parameter type * is requested. */ public synchronized int getParameter(int type) { return 0; } /** * <P>Retrieves the value of a particular parameter for this * debit transaction.</P> * * <P><B>Valid Parameters</B> * <UL> * <LI><code>SHADebit.DEBIT_AMOUNT</code></LI> * <LI><code>SHADebit.INITIAL_AMOUNT</code></LI> * <LI><code>SHADebit.USER_BALANCE</code></LI> * </UL> * </P> * * <P>Note that the value of <code>SHADebit.USER_BALANCE</code> will * be set after calling <code>verifyTransactionData(SHAiButtonUser)</code> * and after calling <code>executeTransaction(SHAiButtonUser)</code>.</P> * * @return The value of the requested parameter. * * @throws IllegalArgumentException if an invalid parameter type * is requested. */ public synchronized int getParameter(int type, byte[] data, int offset, int len) { if(type==VERIFICATION_DATA) { System.arraycopy(this.ver_data,0,data,offset,len); return 0; } throw new IllegalArgumentException("Invalid Parameter type"); } /** * <P>Sets the value of a particular parameter for this * debit transaction.</P> * * <P><B>Valid Parameters</B> * <UL> * <LI><code>SHADebit.DEBIT_AMOUNT</code></LI> * <LI><code>SHADebit.INITIAL_AMOUNT</code></LI> * </UL> * </P> * * @param type Specifies the parameter type (<code>SHADebit.DEBIT_AMOUNT</code> or * <code>SHADebit.INITIAL_AMOUNT</code>) * @return </code>true</code> if a valid parameter type was specified * and the value of the parameter is positive. * * @throws IllegalArgumentException if an invalid parameter type * is requested. */ public synchronized boolean setParameter(int type, byte[] data, int offset, int len) { if(type==VERIFICATION_DATA) System.arraycopy(data,offset,this.master_ver_data,0,len); else return false; return true; } /** * <P>Sets the value of a particular parameter for this * debit transaction.</P> * * <P><B>Valid Parameters</B> * <UL> * <LI><code>SHADebit.DEBIT_AMOUNT</code></LI> * <LI><code>SHADebit.INITIAL_AMOUNT</code></LI> * </UL> * </P> * * @param type Specifies the parameter type (<code>SHADebit.DEBIT_AMOUNT</code> or * <code>SHADebit.INITIAL_AMOUNT</code>) * @return </code>true</code> if a valid parameter type was specified * and the value of the parameter is positive. * * @throws IllegalArgumentException if an invalid parameter type * is requested. */ public synchronized boolean setParameter(int type, int param) { return false; } /** * <p>Resets all transaction parameters to default values</p> */ public synchronized void resetParameters() { for(int i=0; i<7; i++) { ver_data[i] = 0x00; master_ver_data[i] = 0x00; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -