Exemplo n.º 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);
        }
Exemplo n.º 2
0
        /// <summary>
        /// <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>
        /// </summary>
        /// <param name="user"> SHAiButtonUser upon which the transaction occurs.
        /// </param>
        /// <seealso cref= SHAiButtonCopr#generateChallenge(int,byte[],int) </seealso>
        /// <seealso cref= SHAiButtonCopr#verifyAuthentication(byte[],byte[],byte[],byte[],byte) </seealso>
        /// <seealso cref= SHAiButtonUser#readAccountData(byte[],int,byte[],int,byte[],int) </seealso>
        /// <seealso cref= #getLastError() </seealso>
        public override bool verifyUser(SHAiButtonUser user)
        {
            lock (this)
            {
                //clear any error
                this.lastError = SHATransaction.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;

                int wcc;

                //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
                wcc = user.readAccountData(chlg, 0, accountData, 0, mac, 0);

                if (wcc < 0)
                {
                    if (user.hasWriteCycleCounter())
                    {
                        // failed to read account data
                        this.lastError = SHATransaction.USER_READ_AUTH_FAILED;
                        return(false);
                    }
                    Array.Copy(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
                Array.Copy(fullBindCode, 4, scratchpad, 12, 8);

                //set the same challenge bytes
                Array.Copy(chlg, 0, scratchpad, 20, 3);

                OneWireEventSource.Log.Debug("------------------------------------");
                OneWireEventSource.Log.Debug("Verifying user");
                OneWireEventSource.Log.Debug("chlg: " + Convert.toHexString(chlg));
                OneWireEventSource.Log.Debug("accountData: " + Convert.toHexString(accountData));
                OneWireEventSource.Log.Debug("mac: " + Convert.toHexString(mac));
                OneWireEventSource.Log.Debug("wcc: " + user.WriteCycleCounter);
                OneWireEventSource.Log.Debug("fullBindCode: " + Convert.toHexString(fullBindCode));
                OneWireEventSource.Log.Debug("scratchpad: " + Convert.toHexString(scratchpad));
                OneWireEventSource.Log.Debug("------------------------------------");

                if (!copr.verifyAuthentication(fullBindCode, accountData, scratchpad, mac, user.AuthorizationCommand))
                {
                    this.lastError = SHATransaction.COPROCESSOR_FAILURE;
                    return(false);
                }

                return(true);
            }
        }
Exemplo n.º 3
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);
            }
        }