Example #1
0
        /// <summary>
        /// Does the writing of transaction data to the user button as well
        /// as actually signing the data with the coprocessor.
        /// </summary>
        private bool writeTransactionData(SHAiButtonUser user, int transID, int balance, byte[] accountData)
        {
            //init local vars
            SHAiButtonCopr copr        = this.copr;
            int            acctPageNum = user.AccountPageNumber;

            byte[] scratchpad = this.writeTransactionData_scratchpad;

            // length of the TMEX file - 28 data, 1 cont. ptr
            accountData[I_FILE_LENGTH] = (byte)29;

            // transaction ID - 2 data bytes
            accountData[I_TRANSACTION_ID + 0] = (byte)transID;
            accountData[I_TRANSACTION_ID + 1] = (byte)((int)((uint)transID >> 8));

            // conversion factor - 2 data bytes
            accountData[I_CONVERSION_FACTOR + 0] = 0x8B;
            accountData[I_CONVERSION_FACTOR + 1] = 0x48;

            // account balance - 3 data bytes
            Convert.toByteArray(balance, accountData, I_BALANCE, 3);

            // 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.WriteCycleCounter;

            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 = SHATransaction.USER_READ_AUTH_FAILED;
                    return(false);
                }
                Array.Copy(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);

            //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
            OneWireEventSource.Log.Debug("------------------------------------");
            OneWireEventSource.Log.Debug("writing transaction data");
            OneWireEventSource.Log.Debug("acctPageNum: " + acctPageNum);
            OneWireEventSource.Log.Debug("accountData: " + Convert.toHexString(accountData));
            OneWireEventSource.Log.Debug("------------------------------------");
            //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//

            // write it to the button
            try
            {
                if (user.writeAccountData(accountData, 0))
                {
                    return(true);
                }
            }
            catch (OneWireException owe)
            {
                OneWireEventSource.Log.Debug(owe.ToString());
            }

            this.lastError = SHATransaction.USER_WRITE_DATA_FAILED;
            return(false);
        }
Example #2
0
        /// <summary>
        /// <P>Verifies user's account data.  Account data is "verified" if and
        /// only if the account balance is greater than zero and 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> Extract account balance </li>
        ///     <li> Debit money from balance </li>
        ///     <li> Insert the new 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>
        /// </summary>
        /// <param name="user"> SHAiButtonUser upon which the transaction occurs.
        /// </param>
        /// <returns> <code>true</code> if and only if the account balance is
        /// greater than zero and digital signature matches the signature
        /// recreated by the coprocessor.
        /// </returns>
        /// <seealso cref= SHAiButtonUser#readAccountData(byte[],int) </seealso>
        /// <seealso cref= SHAiButtonCopr#verifySignature(byte[],byte[],byte[]) </seealso>
        /// <seealso cref= #getLastError() </seealso>
        public override bool verifyTransactionData(SHAiButtonUser user)
        {
            lock (this)
            {
                //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.WriteCycleCounter;

                //if verifyUser was called, this is a read of cached data
                user.readAccountData(accountData, 0);

                //get the user's balance from accountData
                int balance = Convert.toInt(accountData, I_BALANCE, 3);
                if (balance < 0)
                {
                    this.lastError = USER_BAD_ACCOUNT_DATA;
                    return(false);
                }
                this.userBalance = balance;

                //get the mac from the account data page
                Array.Copy(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] = 0;
                accountData[I_FILE_CRC16 + 1] = 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
                    Array.Copy(ffBlock, 0, scratchpad, 8, 4);
                }
                else
                {
                    //copy the write cycle counter into scratchpad
                    Convert.toByteArray(wcc, scratchpad, 8, 4);
                }
                scratchpad[12] = (byte)user.AccountPageNumber;
                user.getAddress(scratchpad, 13, 7);

                copr.getSigningChallenge(scratchpad, 20);

                if (!copr.verifySignature(accountData, scratchpad, verify_mac))
                {
                    this.lastError = COPROCESSOR_FAILURE;
                    return(false);
                }

                return(true);
            }
        }