📄 shadebitunsigned.java
字号:
/*--------------------------------------------------------------------------- * Copyright (C) 1999-2001 Dallas Semiconductor Corporation, All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Dallas Semiconductor * shall not be used except as stated in the Dallas Semiconductor * Branding Policy. *--------------------------------------------------------------------------- */package com.dalsemi.onewire.application.sha;import java.io.*;import com.dalsemi.onewire.*;import com.dalsemi.onewire.adapter.*;import com.dalsemi.onewire.container.*;import com.dalsemi.onewire.utils.*;/** * <P>This class implements an account debit application for unsigned SHA * Transactions. Account data is stored on user iButtons with no digital * signature (unlike <code>SHADebit</code> which signs the data with a * coprocessor iButton).</P> * * <P>You may be wondering, "Why use a SHA transaction interface for * unsigned account data?" The answer is for increasing transaction times * with the DS1961S user iButton. All data writes to the DS1961S require * knowledge of the iButton's unique secret, which prevents tampering with * the account data. Since a data signature on account data is designed * for the same purpose, it is removed from this transaction to remove * redundancy and achieve better performance with the DS1961S.</P> * * <P>Due to the nature of the DS1961S/DS2432 (i.e. it's designed as * a battery-less EEPROM device for 'touch' environments), it is possible * that account data could be corrupted if the writing of the data is * interrupted. In fact, it is also possible that if the writing of a single * bit is interrupted, that bit could become borderline (i.e. right on * the line of being a 1 or a 0, such that the 1-Wire I/O logic reads it as * a 1 and the SHA engine reads it as a 0) and could be permanently corrupted. * As a workaround to problems of this nature, a double-write scheme is used * where the length indicates which record is the actual account balance.<P> * * <P>The account file consists of the following: * <UL> * <LI> 1 byte: Length of the account file</LI> * <LI> 1 byte: Account data type (dynamic or static)</LI> * <LI> 2 bytes: Account Money Conversion Factor</LI> * <LI> 4 bytes: Don't Care</LI> * <LI> <B>Record A</B> * <LI> 3 bytes: Account Balance</LI> * <LI> 2 bytes: Transaction ID</LI> * <LI> 1 byte: File continuation pointer</LI> * <LI> 2 bytes: CRC16 of 14 bytes seeded with the page number</LI> * <LI> <B>Record B</B> * <LI> 3 bytes: Account Balance</LI> * <LI> 2 bytes: Transaction ID</LI> * <LI> 1 byte: File continuation pointer</LI> * <LI> 2 bytes: CRC16 of 22 bytes seeded with the page number</LI> * <LI> <B>24 bytes Total</B></LI> * </UL></P> * * <P>If the length of the account file is 13, then the current record is * Record A. If the length of the account file is 21, then the current record * is Record B. When updating the button, first the other record is updated * (i.e. if Record A is current, then update Record B with the new balance) and * write the new data for that record to the button. After verifying that * the data was written correctly, the file pointer is the updated to point to * the new record. If data corruption occurs at any point in the transaction * (and the user doesn't hang around long enough to allow the transaction * system a chance to fix it), the next time the user performs a transaction * it is possible to discern what the last known good value is.<P> * * <P>A typical use case for this class might be as follows: * <pre> * OneWireContainer18 coprOWC18 = new OneWireContainer18(adapter,address); * * //COPR.0 is the filename for coprocessor service data * SHAiButtonCopr copr = new SHAiButtonCopr(coprOWC18,"COPR.0"); * * //Initial amount for new users is $100, and debit amount is 50 cents * SHATransaction trans = new SHADebitUnsigned(copr, 10000, 50); * * OneWireContainer33 owc33 = new OneWireContainer33(adapter, userAddress); * * //The following constructor erases all transaction data from the user and * //installs the system authentication secret on the user iButton. * //The second instance of coprocessor is used for write-authorization. If you're * //not using the system coprocessor for data signing, it can be re-used for this * //purpose. * SHAiButtonUser user = new SHAiButtonUser33(copr, copr, owc33, true, authSecret); * * //creates account data on iButton * if(trans.setupTransactionData(user)) * System.out.println("Account data installed successfully"); * else * System.out.println("Account data installation failed"); * * //... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... * * //verifies authentication response of user iButton from "challenge" * if(trans.verifyUser(user)) * { * System.out.println("User Verified Successfully"); * * //Checks to see that account balance is greater than zero * if(trans.verifyTransactionData(user)) * { * System.out.println("Account Data Verified Successfully"); * * //performs the debit and writes the new account balance * if(trans.executeTransaction(user)) * { * System.out.println("Account debited."); * System.out.println("New Balance: " + * trans.getParameter(SHADebit.USER_BALANCE)); * } * } * } * * //... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... * * if(trans.getLastError()!=0) * { * System.err.println("Error code: " + trans.getLastError()); * } * </pre></P> * * <p>This class makes use of several performance enhancements for TINI. * For instance, most methods are <code>synchronized</code> to access instance * variable byte arrays rather than creating new byte arrays every time a * transaction is performed. This could hurt performance in multi-threaded * applications, but the usefulness of having several threads contending * to talk to a single iButton is questionable since the methods in * <code>com.dalsemi.onewire.adapter.DSPortAdapter</code> * <code>beginExclusive(boolean)</code> and <code>endExclusive()</code> * should be used.</p> * * @see SHATransaction * @see SHAiButtonCopr * @see SHAiButtonUser * * @version 1.00 * @author SKH */public class SHADebitUnsigned extends SHATransaction{ /** Used for fast FF copy */ private static final byte[] ffBlock = new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF }; //--------- // Type constants // used to update/retrieve parameters of transaction //--------- /** Update the amount this transaction will debit */ public static final int DEBIT_AMOUNT = 0; /** Update the amount for initial account balance */ public static final int INITIAL_AMOUNT = 1; /** Retrieve the amount for user's current balance */ public static final int USER_BALANCE = 2; /** indices for fields in user account file */ /** header indices */ private static final int I_FILE_LENGTH = 0; private static final int I_DATA_TYPE_CODE = 1; private static final int I_CONVERSION_FACTOR = 2; // 2 conversion bytes private static final int I_DONT_CARE = 4; // 4 don't care bytes /** Record A indices */ private static final int I_BALANCE_A = 8; private static final int I_TRANSACTION_ID_A = 11; private static final int I_CONTINUATION_PTR_A = 13; private static final int I_FILE_CRC16_A = 14; /** Record B indices */ private static final int I_BALANCE_B = 16; private static final int I_TRANSACTION_ID_B = 19; private static final int I_CONTINUATION_PTR_B = 21; private static final int I_FILE_CRC16_B = 22; /** Constants for record length */ private static final int RECORD_A_LENGTH = 13; private static final int RECORD_B_LENGTH = 21; //--------- // Member variables //--------- /** Amount to debit from user */ private int debitAmount; /** Amount to initialize new user with */ private int initialAmount; /** Most recent user's account balance */ private int userBalance; //--------- // Constructors //--------- /** User apps should never call this */ protected SHADebitUnsigned() {;} /** * SHADebitUnsigned constructor. <code>copr</code> is the SHAiButtonCopr * that is used to perform this transaction. After saving a * reference to the SHA coprocessor, this constructor resets all * parameters for this type of transaction to their default values. * * @param copr The coprocessor used for authentication and data * signing in this transaction. */ public SHADebitUnsigned(SHAiButtonCopr copr) { super(copr); resetParameters(); } /** * SHADebitUnsigned constructor. <code>copr</code> is the SHAiButtonCopr * that is used to perform this transaction. After saving a * reference to the SHA coprocessor, this constructor resets all * parameters for this type of transaction to their default values. * * @param copr The coprocessor used for authentication and data * signing in this transaction. */ public SHADebitUnsigned(SHAiButtonCopr copr, int initialAmount, int debitAmount) { super(copr); this.initialAmount = initialAmount; this.debitAmount = debitAmount; } /** * <P>Setup account data on a fresh user iButton. Prior to calling * setup transaction data, the authentication secret for the iButton * should already be setup and a directory entry (as well as at least * an empty placeholder file) should exist for the account data. If * you constructed the SHAiButtonUser using * <code>SHAiButtonUser(SHAiButtonCopr,OneWireContainer18,boolean,byte[])</code> * the secret has been setup for you and you should know call this * function. If you try to install the authentication secret after * creating the account data, you will destroy all account data on the * iButton.</P> * * <P>You can set the value of the intial account balance by calling * <code>transaction.setParameter(SHADebit.INITIAL_AMOUNT,10000)</code> * where the value of the units is in cents (i.e. 10000 = $100).</P> * * <P><B>Flow of action: </B> * <ul> * <li> Generate generic account page </li> * <li> Insert the initial balance into account data </li> * <li> Insert the (constant) digital signature </li> * <li> Write account data page to iButton </li> * </ul></P> * * @param user SHAiButtonUser upon which the transaction occurs. * * @return <code>true</code>if and only if the signature is * successfully created by the coprocessor AND the data is * successfully written to the user iButton. * * @see SHAiButtonUser#writeAccountData(byte[],int) * @see #getLastError() */ public boolean setupTransactionData(SHAiButtonUser user) throws OneWireException, OneWireIOException { //clear any error lastError = NO_ERROR; // not in critical path, so malloc'ing is okay byte[] accountData = new byte[32]; return writeTransactionData(user, 0, this.initialAmount, accountData); } //prevent malloc'ing in the critical path private byte[] verifyUser_fullBindCode = new byte[15]; private byte[] verifyUser_scratchpad = new byte[32]; private byte[] verifyUser_accountData = new byte[32]; private byte[] verifyUser_mac = new byte[20]; private byte[] verifyUser_chlg = new byte[3]; /** * <P>Verifies user's authentication response. User is "authenticated" if * and only if the digital signature generated the user iButton matches * the digital signature generated by the coprocessor after the user's * unique secret has been recreated on the coprocessor.</P> * * <P><B>Flow of action: </B> * <ul> * <li> Generate 3-byte "challenge" on coprocessor </li> * <li> Write challenge to scratchpad of user </li> * <li> Read account data page with signature </li> * <li> Attempt to match user's signature with the coprocessor </li> * </ul></P> * * @param user SHAiButtonUser upon which the transaction occurs. * * @see SHAiButtonCopr#generateChallenge(int,byte[],int)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -