1

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].

Nikola Zivkovic
  • 819
  • 1
  • 9
  • 20
  • 2
    Floats are 4 byte(32-bit) long, not 6. Unless you mean that you want to format the number as a six character string? – Panagiotis Kanavos Jun 17 '15 at 10:08
  • And what is the specification of "EMV Tag 9F02, format n12" ? It is very unlikely to be built in, so you'll either need to do the switch yourself, or find a library that does. – Marc Gravell Jun 17 '15 at 10:10
  • "The amount to be used and authorized, EMV Tag 9F02, format n12. It should be a 6-byte array. " this is the description for amount parameter in MagTek documentation for DynaPro device. I also don't now what is that specification... – Nikola Zivkovic Jun 17 '15 at 10:12
  • @user1819018 then you need to ask them for more info – Marc Gravell Jun 17 '15 at 10:13
  • @MarcGravell looks like a simple format but the OP should post the specification *in the question*, not expect others to go find it. – Panagiotis Kanavos Jun 17 '15 at 10:13
  • @PanagiotisKanavos well, maybe; one reference I found says "for example the six bytes '00 00 00 00 01 23' represent USD 1.23 when the currency code is '840'" - but I'd still have lots of questions – Marc Gravell Jun 17 '15 at 10:15
  • I will edit my question end post complete function with explanation from documentation. – Nikola Zivkovic Jun 17 '15 at 10:16
  • @user1819018 that's not exactly what the standard says. I see floats encoded as BCDs in 6 bytes, thus encoding 12 digits. You should put this requirement in the question if you want people to be able to answer. Also post the requirement for implicit decimals – Panagiotis Kanavos Jun 17 '15 at 10:18
  • @MarcGravell I have a lot of questions too. At first it looked like it was simple formatting, but now it looks like generating an integer from a float and converting to BCD. Which makes this a possible duplicate – Panagiotis Kanavos Jun 17 '15 at 10:23
  • That edit adds **nothing** useful. Sorry, but you're going to have to find out what the payload it wants is. By reading the documentation. – Marc Gravell Jun 17 '15 at 10:25
  • 1
    On an unrelated note: don't use `float` or `double` for money: always use `decimal` (or `long`, etc, if you choose to handle the decimal split manually) – Marc Gravell Jun 17 '15 at 10:26
  • @Marc Gravell thank you for the tip. Thank you all for the answers, i will try to figure out how it works. – Nikola Zivkovic Jun 17 '15 at 10:38
  • @user1819018 multiply the fload by 10 raised to the number of digits (eg 100 for USD), convert to int then generate a BCD array – Panagiotis Kanavos Jun 17 '15 at 10:47

2 Answers2

3

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)

xanatos
  • 109,618
  • 12
  • 197
  • 280
0

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.

Jacou Mata
  • 91
  • 2