📄 shasoftauth.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 software authrization account application for * SHA Transactions. The account data is stored on the user iButtons after * being digitally signed by a virtual machine coprocessor. Account data * consists of the following: * <UL> * <LI> 1 byte: Length of the account file</LI> * <LI> 2 bytes: Transaction ID</LI> * <LI> 2 bytes: Account Money Conversion Factor</LI> * <LI> 3 bytes: Account Balance</LI> * <LI>20 bytes: Account Data Signature</LI> * <LI> 1 byte: Account data type (dynamic or static)</LI> * <LI> 1 byte: File continuation pointer</LI> * <LI> 2 bytes: CRC16 of entire 30 bytes seeded with the page number</LI> * <LI> <B>32 bytes Total</B></LI> * </UL></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 * byte[] ver_data = new byte[] {0x00,0x01,0x02,0x03,0x04,0x05,0x06}; * SATransaction trans = new SHAsoftauth(copr, ver_data, 7); * * OneWireContainer18 owc18 = new OneWireContainer18(adapter, userAddress); * * //The following constructor erases all transaction data from the user and * //installs the system authentication secret on the user iButton. * SHAiButtonUser user = new SHAiButtonUser18(copr, owc18, 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"); * * //... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... * * //"challenges" user iButton * if(trans.verifyUser(user)) * { * System.out.println("User Verified Successfully"); * * //checks data signature * if(trans.verifyTransactionData(user)) * { * System.out.println("Account Data Verified Successfully"); * * //writes verification data to user iButton * System.out.println("User's verification data: "); * softauth.getParameter(SHASoftAuth.VERIFICATION_DATA, * ver_data,0,7); * IOHelper.writeBytes(ver_data); * } * } * * //... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... * * 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 SHASoftAuth 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 verification data */ public static final int VERIFICATION_DATA = 2; /** indices for fields in user account file */ public static final int I_FILE_LENGTH = 0; public static final int I_DATA_TYPE_CODE = 1; public static final int I_SIGNATURE = 2; public static final int I_VERDATA = 22; public static final int I_CONTINUATION_PTR = 29; public static final int I_FILE_CRC16 = 30; // ************************************************************** // // Member variables // ************************************************************** // /** Data to be stored on the iButton for Verification */ private byte[] ver_data = new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /** Data that is to be written to the iButton for Verification */ private byte[] master_ver_data = new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /** User apps should never call this */ protected SHASoftAuth() {;} /** * SHADebit 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 SHASoftAuth(SHAiButtonCopr copr) { super(copr); resetParameters(); } /** * SHADebit 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. * @param extra_data The 7 bytes of extra data to be used instead * of the balance. * @param len The len, 7 or less of the data. It is 0 padded. */ public SHASoftAuth(SHAiButtonCopr copr, byte[] extra_data, int len) { super(copr); System.arraycopy(extra_data,0,this.master_ver_data,0,len); } /** * <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> Create a signature using coprocessor </li> * <li> Insert the 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 SHAiButtonCopr#createDataSignature(byte[],byte[],byte[],int) * @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, this.master_ver_data, 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) * @see SHAiButtonCopr#verifyAuthentication(byte[],byte[],byte[],byte[],byte) * @see SHAiButtonUser#readAccountData(byte[],int,byte[],int,byte[],int) * @see #getLastError() */ public synchronized boolean verifyUser(SHAiButtonUser user) throws OneWireException, OneWireIOException { //clear any error this.lastError = this.NO_ERROR; //local vars byte[] fullBindCode = this.verifyUser_fullBindCode; byte[] scratchpad = this.verifyUser_scratchpad; byte[] accountData = this.verifyUser_accountData; byte[] mac = this.verifyUser_mac; byte[] chlg = this.verifyUser_chlg; //Generate random challenge. This must be done on the //coprocessor, otherwise flags aren't setup for VALIDATE_PAGE. if(!copr.generateChallenge(0, chlg, 0)) { lastError = COPR_COMPUTE_CHALLENGE_FAILED; return false; } //have user answer the challenge int wcc = user.readAccountData(chlg, 0, accountData, 0, mac, 0); if(wcc<0) { if(user.hasWriteCycleCounter()) { // failed to read account data this.lastError = this.USER_READ_AUTH_FAILED; return false; } System.arraycopy(ffBlock, 0, scratchpad, 8, 4); } else { //copy the write cycle counter into scratchpad Convert.toByteArray(wcc, scratchpad, 8, 4); } //get the user's fullBindCode, formatted for user device user.getFullBindCode(fullBindCode, 0); //get the user address and page num from fullBindCode System.arraycopy(fullBindCode, 4, scratchpad, 12, 8); //set the same challenge bytes System.arraycopy(chlg, 0, scratchpad, 20, 3); //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// if(DEBUG) { IOHelper.writeLine("------------------------------------"); IOHelper.writeLine("Verifying user"); IOHelper.writeLine("chlg"); IOHelper.writeBytesHex(chlg); IOHelper.writeLine("accountData"); IOHelper.writeBytesHex(accountData); IOHelper.writeLine("mac"); IOHelper.writeBytesHex(mac); IOHelper.writeLine("wcc: " + user.getWriteCycleCounter()); IOHelper.writeLine("fullBindCode"); IOHelper.writeBytesHex(fullBindCode); IOHelper.writeLine("scratchpad"); IOHelper.writeBytesHex(scratchpad); IOHelper.writeLine("------------------------------------"); } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// if(!copr.verifyAuthentication(fullBindCode, accountData, scratchpad, mac, user.getAuthorizationCommand())) { this.lastError = this.COPROCESSOR_FAILURE; return false; } return true; } //prevent malloc'ing in the critical path private byte[] verifyData_fullBindCode = new byte[32]; private byte[] verifyData_scratchpad = new byte[32]; private byte[] verifyData_accountData = new byte[32]; private byte[] verifyData_mac = new byte[20]; /** * <P>Verifies user's account data. Account data is "verified" if the * digital signature matches the signature recreated by the * coprocessor.</P> * * <P><B>Flow of action: </B> * <ul> * <li> Read the account data from user </li> * <li> Get verification data </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. * * @return <code>true</code> if and only if the account balance is * greater than zero and digital signature matches the signature * recreated by the coprocessor. * * @see SHAiButtonUser#readAccountData(byte[],int) * @see SHAiButtonCopr#verifySignature(byte[],byte[],byte[]) * @see #getLastError() */ public synchronized boolean verifyTransactionData(SHAiButtonUser user) throws OneWireException, OneWireIOException { //clear any error this.lastError = NO_ERROR; //init local vars byte[] scratchpad = this.verifyData_scratchpad; byte[] accountData = this.verifyData_accountData; byte[] verify_mac = this.verifyData_mac; //if verifyUser was called, this is a read of cached data int wcc = user.getWriteCycleCounter(); //if verifyUser was called, this is a read of cached data
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -