number value to byte[6] array card reader

1.4k views Asked by At

What's the best way to convert a number to a byte[6] in C#?

I'm using MagTek Card reader and trying to display desired amount on device screen, it should be 6-byte array. The amount needs to be used and authorized, EMV Tag 9F02, format n12.

Function:

 int requestSmartCard(int cardType, int comfirmationTime, int pinEnteringTime, int beepTones, int option, byte [] amount, int transactionType, byte[] cashback, byte [] reserved);

And the description for amount param is: - amount The amount to be used and authorized, EMV Tag 9F02, format n12. It should be a 6-byte array.

EDIT:

This is example code from their example in C#:

          byte []amount = new byte[6];
          amount[3] = 1;
          byte []cashBack = new byte[6];

          PrintMsg(String.format("start a emv transaction"));
          byte reserved[]  = new byte[26];

          byte cardType = 2;
          byte confirmWaitTime = 20;
          byte pinWaitTime = 20;
          byte tone = 1;
          byte option = 0;
          byte transType = 4;
          retCode = m_MTSCRA.requestSmartCard(cardType, confirmWaitTime, pinWaitTime, tone, option, amount, transType, cashBack, reserved);

and then on device's screen amount of 100.00 $ is shown.

EDIT: I changed the question form float to byte[6] to number to byte[6].

2

There are 2 answers

5
xanatos On BEST ANSWER

The method should be something like:

public static byte[] NumberToByteArray(float f, int decimals)
{
    // A string in the format 0000000000.00 for example
    string format = new string('0', 12 - decimals) + "." + new string('0', decimals);

    // We format the number f, removing the decimal separator
    string str = f.ToString(format, CultureInfo.InvariantCulture).Replace(".", string.Empty);

    if (str.Length != 12)
    {
        throw new ArgumentException("f");
    }

    var bytes = new byte[6];

    for (int i = 0; i < 6; i++)
    {
        // For each group of two digits, the first one is shifted by
        // 4 binary places
        int digit1 = str[i * 2] - '0';
        bytes[i] = (byte)(digit1 << 4);

        // And the second digit is "added" with the logical | (or)
        int digit2 = str[(i * 2) + 1] - '0';
        bytes[i] |= (byte)digit2;
    }

    return bytes;
}

Note (1) that it isn't an optimized method. I could have multiplied by 10^decimals instead, but I don't want to do useless multiplications.

Note (2) you shouldn't really use float. float has a precision of 6 or 7 digits (when you are lucky), while that format can store 12 digits. Use double or even better decimal. You can replace float with decimal and it will work correctly.

Note (3) you need the number of decimal places you want to use. 2 for Euro or Dollars, but for other currencies it could be different.

Note (4) this is a problem of conversion from a number to a BCD. It can be made without going through a string. Too lazy to do it (and I don't want to do multiplications on float)

0
Jacou Mata On

Some processors when not sending the pre-determined amount in EMV kernel tag 9F02 may get you "Do No Honor" error message back from the bank, which is a generic error.

By sending the final/charge amount in tag 9F02 transactions get approved.

The results from these two cases, seem to indicate that your processor is validating the tag 9F02 against the final amount.

Which goes against Visa spec.

https://www.visa.com/chip/merchants/grow-your-business/payment-technologies/credit-card-chip/docs/quick-chip-emv-specification.pdf

enter image description here

The above solution by xanatos does the trick tho. I tested it too.