Class SHADebitUnsigned
- java.lang.Object
-
- com.dalsemi.onewire.application.sha.SHATransaction
-
- com.dalsemi.onewire.application.sha.SHADebitUnsigned
-
public class SHADebitUnsigned extends SHATransaction
This class implements an account debit application for unsigned SHA Transactions. Account data is stored on user iButtons with no digital signature (unlike
SHADebit
which signs the data with a coprocessor iButton).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.
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.
The account file consists of the following:
- 1 byte: Length of the account file
- 1 byte: Account data type (dynamic or static)
- 2 bytes: Account Money Conversion Factor
- 4 bytes: Don't Care
- Record A
- 3 bytes: Account Balance
- 2 bytes: Transaction ID
- 1 byte: File continuation pointer
- 2 bytes: CRC16 of 14 bytes seeded with the page number
- Record B
- 3 bytes: Account Balance
- 2 bytes: Transaction ID
- 1 byte: File continuation pointer
- 2 bytes: CRC16 of 22 bytes seeded with the page number
- 24 bytes Total
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.
A typical use case for this class might be as follows:
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()); }
This class makes use of several performance enhancements for TINI. For instance, most methods are
synchronized
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 incom.dalsemi.onewire.adapter.DSPortAdapter
beginExclusive(boolean)
andendExclusive()
should be used.- See Also:
SHATransaction
,SHAiButtonCopr
,SHAiButtonUser
-
-
Field Summary
Fields Modifier and Type Field Description static int
DEBIT_AMOUNT
Update the amount this transaction will debitstatic int
INITIAL_AMOUNT
Update the amount for initial account balancestatic int
USER_BALANCE
Retrieve the amount for user's current balance-
Fields inherited from class com.dalsemi.onewire.application.sha.SHATransaction
copr, COPR_BIND_SECRET_FAILED, COPR_COMPUTE_CHALLENGE_FAILED, COPR_WRITE_DATAPAGE_FAILED, COPR_WRITE_SCRATCHPAD_FAILED, COPROCESSOR_FAILURE, lastError, MATCH_SCRATCHPAD_FAILED, NO_ERROR, SHA_FUNCTION_FAILED, USER_BAD_ACCOUNT_DATA, USER_DATA_NOT_UPDATED, USER_READ_AUTH_FAILED, USER_WRITE_DATA_FAILED
-
-
Constructor Summary
Constructors Modifier Constructor Description protected
SHADebitUnsigned()
User apps should never call thisSHADebitUnsigned(SHAiButtonCopr copr)
SHADebitUnsigned constructor.SHADebitUnsigned(SHAiButtonCopr copr, int initialAmount, int debitAmount)
SHADebitUnsigned constructor.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description boolean
executeTransaction(SHAiButtonUser user, boolean verifySuccess)
Performs the unsigned debit, subtracting the debit amount from the user's balance and storing the new, unsigned account data on the user's iButton.int
getParameter(int type)
Retrieves the value of a particular parameter for this debit transaction.void
resetParameters()
Resets all transaction parameters to default valuesboolean
setParameter(int type, int param)
Sets the value of a particular parameter for this debit transaction.boolean
setupTransactionData(SHAiButtonUser user)
Setup account data on a fresh user iButton.boolean
verifyTransactionData(SHAiButtonUser user)
Verifies user's account data.boolean
verifyUser(SHAiButtonUser user)
Verifies user's authentication response.-
Methods inherited from class com.dalsemi.onewire.application.sha.SHATransaction
getLastCoprError, getLastError
-
-
-
-
Field Detail
-
DEBIT_AMOUNT
public static final int DEBIT_AMOUNT
Update the amount this transaction will debit- See Also:
- Constant Field Values
-
INITIAL_AMOUNT
public static final int INITIAL_AMOUNT
Update the amount for initial account balance- See Also:
- Constant Field Values
-
USER_BALANCE
public static final int USER_BALANCE
Retrieve the amount for user's current balance- See Also:
- Constant Field Values
-
-
Constructor Detail
-
SHADebitUnsigned
protected SHADebitUnsigned()
User apps should never call this
-
SHADebitUnsigned
public SHADebitUnsigned(SHAiButtonCopr copr)
SHADebitUnsigned constructor.copr
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.- Parameters:
copr
- The coprocessor used for authentication and data signing in this transaction.
-
SHADebitUnsigned
public SHADebitUnsigned(SHAiButtonCopr copr, int initialAmount, int debitAmount)
SHADebitUnsigned constructor.copr
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.- Parameters:
copr
- The coprocessor used for authentication and data signing in this transaction.
-
-
Method Detail
-
setupTransactionData
public boolean setupTransactionData(SHAiButtonUser user) throws OneWireException, OneWireIOException
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
SHAiButtonUser(SHAiButtonCopr,OneWireContainer18,boolean,byte[])
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.You can set the value of the initial account balance by calling
transaction.setParameter(SHADebit.INITIAL_AMOUNT,10000)
where the value of the units is in cents (i.e. 10000 = $100).Flow of action:
- Generate generic account page
- Insert the initial balance into account data
- Insert the (constant) digital signature
- Write account data page to iButton
- Specified by:
setupTransactionData
in classSHATransaction
- Parameters:
user
- SHAiButtonUser upon which the transaction occurs.- Returns:
true
if and only if the signature is successfully created by the coprocessor AND the data is successfully written to the user iButton.- Throws:
OneWireException
OneWireIOException
- See Also:
SHAiButtonUser.writeAccountData(byte[],int)
,SHATransaction.getLastError()
-
verifyUser
public boolean verifyUser(SHAiButtonUser user) throws OneWireException, OneWireIOException
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.
Flow of action:
- Generate 3-byte "challenge" on coprocessor
- Write challenge to scratchpad of user
- Read account data page with signature
- Attempt to match user's signature with the coprocessor
- Specified by:
verifyUser
in classSHATransaction
- Parameters:
user
- SHAiButtonUser upon which the transaction occurs.- Throws:
OneWireException
OneWireIOException
- See Also:
SHAiButtonCopr.generateChallenge(int,byte[],int)
,SHAiButtonCopr.verifyAuthentication(byte[],byte[],byte[],byte[],byte)
,SHAiButtonUser.readAccountData(byte[],int,byte[],int,byte[],int)
,SHATransaction.getLastError()
-
verifyTransactionData
public boolean verifyTransactionData(SHAiButtonUser user) throws OneWireException, OneWireIOException
Verifies user's account data. Account data is "verified" if and only if the account balance is greater than zero. No digital signature is checked by this transaction.
Flow of action:
- Read the account data from user
- Extract account balance
- Debit money from balance
- Insert the new balance
- Write the account data to the user
If previous steps have been executed, all "Read" commands on the user are reading from cached data.
- Specified by:
verifyTransactionData
in classSHATransaction
- Parameters:
user
- SHAiButtonUser upon which the transaction occurs.- Returns:
true
if and only if the account balance is greater than zero.- Throws:
OneWireException
OneWireIOException
- See Also:
SHAiButtonUser.readAccountData(byte[],int)
,SHATransaction.getLastError()
-
executeTransaction
public boolean executeTransaction(SHAiButtonUser user, boolean verifySuccess) throws OneWireException, OneWireIOException
Performs the unsigned debit, subtracting the debit amount from the user's balance and storing the new, unsigned account data on the user's iButton. The debit amount can be set using
transaction.setParameter(SHADebit.DEBIT_AMOUNT, 50)
, where the value is in units of cents (i.e. for 1 dollar, use 100).Flow of action:
- Read the account data from user
- Extract account balance
- Assert balance greater than debit amount
- Debit money from balance
- Insert the new balance
- Write the account data to the user
If previous steps have been executed, all "Read" commands on the user are reading from cached data.
- Specified by:
executeTransaction
in classSHATransaction
- Parameters:
user
- SHAiButtonUser upon which the transaction occurs.- Returns:
true
if and only if the user has enough in the account balance to perform the requested debit AND the account data has been written to the button.- Throws:
OneWireException
OneWireIOException
- See Also:
SHAiButtonUser.readAccountData(byte[],int)
,SHAiButtonUser.writeAccountData(byte[],int)
,SHATransaction.getLastError()
-
getParameter
public int getParameter(int type)
Retrieves the value of a particular parameter for this debit transaction.
Valid Parameters
SHADebit.DEBIT_AMOUNT
SHADebit.INITIAL_AMOUNT
SHADebit.USER_BALANCE
Note that the value of
SHADebit.USER_BALANCE
will be set after callingverifyTransactionData(SHAiButtonUser)
and after callingexecuteTransaction(SHAiButtonUser)
.- Specified by:
getParameter
in classSHATransaction
- Returns:
- The value of the requested parameter.
- Throws:
java.lang.IllegalArgumentException
- if an invalid parameter type is requested.
-
setParameter
public boolean setParameter(int type, int param)
Sets the value of a particular parameter for this debit transaction.
Valid Parameters
SHADebit.DEBIT_AMOUNT
SHADebit.INITIAL_AMOUNT
- Specified by:
setParameter
in classSHATransaction
- Parameters:
type
- Specifies the parameter type (SHADebit.DEBIT_AMOUNT
orSHADebit.INITIAL_AMOUNT
)- Returns:
- true if a valid parameter type was specified and the value of the parameter is positive.
- Throws:
java.lang.IllegalArgumentException
- if an invalid parameter type is requested.
-
resetParameters
public void resetParameters()
Resets all transaction parameters to default values
- Specified by:
resetParameters
in classSHATransaction
-
-