How to Parse received Hex bytes into readable string - c#

As the title says, I've been working on MiFare Classic reading a card.
I'm using the MiFare v1.1.3 Library from NuGet
and it returns a byte array, which I parse to readable Hex strings, by looping thru it.
Here's the code snippet:
int sector = 1;
int block = 0;
int size = 16;
var data = await localCard.GetData(sector, block, size);
string hexString = "";
for (int i = 0; i < data.Length; i++)
{
hexString += data[i].ToString("X2") + " ";
}
// hexString returns 84 3D 17 B0 1E 08 04 00 02 63 B5 F6 B9 BE 77 1D
Now, how can I parse it properly?
I've tried parsing it into ASCII, ANSI, Int, Int64, Base64, Long
and all of them didn't match the 'data' that it's suppose to contain
EDIT:
The expected output: 1206058
HEX String returned: 84 3D 17 B0 1E 08 04 00 02 63 B5 F6 B9 BE 77 1D

I've checked the source code
it looks like both Task<byte[]> GetData Task SetData methods do not have any special logic to transform the data. Data are just saved (and read) as byte[]
I suppose that you have to contact author/company that has wrote data you are trying to read.
The expected output: 1206058
Looks strange since you are reading 16 bytes size = 16 and expecting 7 characters to be read.
Is it possible that block or sector values are incorrect ?

I have written a simple program to solve your problem. Perhaps this is what you want to achieve:
// The original byte data array; some random data
byte[] data = { 0, 1, 2, 3, 4, 85, 128, 255 };
// Byte data -> Hex string
StringBuilder hexString = new StringBuilder();
foreach (byte item in data)
{
hexString.Append($"{item.ToString("X2")} ");
}
Console.WriteLine(hexString.ToString().Trim());
// Hex string -> List of bytes
string[] hexArray = hexString.ToString().Trim().Split(' ');
List<byte> dataList = new List<byte>();
foreach (string item in hexArray)
{
dataList.Add(byte.Parse(item, System.Globalization.NumberStyles.HexNumber));
}
dataList.ForEach(b => Console.Write($"{b} "));
Console.WriteLine();
If it is not the right solution please provide us more info about your problem.

If var data potentially is string - you can reverse it from hex by:
// To Hex
byte[] plainBytes = Encoding.ASCII.GetBytes("MiFare v1.1.3");
string hexString = "";
for (int i = 0; i < plainBytes.Length; i++)
hexString += plainBytes[i].ToString("X2") + " ";
Console.WriteLine(hexString); // Result: "4D 69 46 61 72 65 20 76 31 2E 31 2E 33"
// From Hex
hexString = hexString.Replace(" ", ""); // Remove whitespaces to have "4D69466172652076312E312E33"
byte[] hexBytes = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length / 2; i++)
hexBytes[i] = Convert.ToByte(hexString.Substring(2 * i, 2), 16);
string plainString = Encoding.ASCII.GetString(hexBytes);
Console.WriteLine(plainString); // Result: "MiFare v1.1.3"
Just, probably, should be needed to define correct Encoding.

Related

How to get a string from a bytes array?

I'm creating my own DNS server and host blocker, I want to get host from DNS request message byte[]
dns message hex dump:
e07901000001000000000000057961686f6f03636f6d0000010001
.y...........yahoo.com.....
code:
using System;
using System.Text;
public class Program
{
public static void Main()
{
string b64 = "4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB";
int pad = b64.Length % 4;
if (pad > 0 )
{
b64 += new string('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while(decoded[end] != 0){
end++;
}
int hostLength = end-start;
byte[] byteHost = new byte[hostLength];
Array.Copy(decoded, start, byteHost, 0, hostLength);
string host = Encoding.Default.GetString(byteHost);
Console.WriteLine(host); // yahoo♥com
}
}
The questions:
is my method above to get host name right/efficient/fastest ?
why I get weird character replacing the dot yahoo♥com ?
change to Encoding.ASCII or Encoding.UTF8 has no effect
There's no need for the second array; Encoding.GetString allows you to pass in an offset and count, so: GetString(decoded, start, hostLength)
Never use Encoding.Default; that is badly named - it should be called Encoding.Wrong :) Find out what encoding the data is in (probably UTF-8 or ASCII), and use that
You should be able to use IndexOf to find the terminating '\0'; also consider what your code should do if it doesn't find one
As for the unusual character: the data contains an 03 byte where you would expect the .; check the DNS protocol specification to see if this is expected. 03 is ETX (end of text). Beyond that: I don't know.
Found the answer, 03 is not ETX but length of the next string, let see the the example
00 05 79 61 68 6F 6F 03 63 6F 6D
. . y a h o o . c o m
05 mean is the length of yahoo and 03 is for com
Valid host or domain name contains only ASCII range from 44-127 or [a-z0-9-\.], domain like bücher.nu will be converted into xn--bcher-kva.nu, so I replace byte like 03,0C,09 or under 44 with the dot .
and thanks to #Marc Gravell for GetString(decoded, start, hostLength)
/*
I0sBAAABAAAAAAAABmMtcmluZwZtc2VkZ2UDbmV0AAABAAE
ldgBAAABAAAAAAAABWZwLXZwCWF6dXJlZWRnZQNuZXQAAAEAAQ
4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB
*/
string b64 = "4VoBAAABAAAAAAAAIGYyNWIzNjgyMGUyNDljNGQxY2I0YzQzNGUxNjc5YTljA2Nsbwxmb290cHJpbnRkbnMDY29tAAABAAE";
int pad = b64.Length % 4;
if (pad > 0)
{
b64 += new string ('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);
Console.WriteLine(host);
edit: micro optimization, benchmark with 1e9 or 1 billion loop
Convert.ToChar() finished in 00:00:04
for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
host += Convert.ToChar(decoded[end]);
end++;
}
}
VS Encoding.ASCII.GetString() finished in 00:03:20 (200 seconds)
for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);

How would I parse a file (which seperates unicode text with 00 bytes) into a list?

Given a selection of bytes in a hex editor shows the file separates text with 00 bytes, it's a coloring file, with the material name, follolwed by a 3 byte hex code that determines colour. which is why it contains bytes like FF. the bytes are shown like this:
00 11 46 6F 6C 69 61 67 65 5F 45 76 65 72 67 72 65 65 6E 00 FF FF FF 00 0D 46 6F 6C 69 61 67 65 5F 42 69 72 63 68 00 80 A7 55
which translates into ascii as such:
Foliage_Evergreen�ÿÿÿ�
Foliage_Birch�€§U
How would I separate these bytes down into a list and convert them into text list of the bytes' values? I'm having trouble understanding how I'd go about doing it... this is what I'm doing right now:
OpenFileDialog openFileDialog1 = new OpenFileDialog();
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
}
string line = System.IO.File.ReadAllText(openFileDialog1.FileName);
byte[] bytes = Encoding.ASCII.GetBytes(line);
List<string> listtext = line.Split('.').ToList();
listBox1.DataSource = listtext;
You shouldn’t do that, will crash for some files with encoding exception:
string line = System.IO.File.ReadAllText(openFileDialog1.FileName);
byte[] bytes = Encoding.ASCII.GetBytes(line);
Use File.ReadAllBytes instead, no need to read text then convert to bytes.
Then you’ll need to parse array of bytes into your records.
Based on your example data, your format uses 0 as field separator, and strings are prepended by their lengths. Here’s an example how to parse, untested:
static IEnumerable<(string, Color)> parse( byte[] data )
{
for( int p = 0; p < data.Length; )
{
// '\0'
if( 0 != data[ p++ ] ) throw new ApplicationException();
// String length byte
int length = data[ p++ ];
// The string; assuming the encoding is UTF8
string name = Encoding.UTF8.GetString( data, p, length );
p += length;
// '\0'
if( 0 != data[ p++ ] ) throw new ApplicationException();
// 3 color bytes, assuming the order is RGB
Color color = Color.FromArgb( 0xFF, data[ p ], data[ p + 1 ], data[ p + 2 ] );
p += 3;
yield return (name, color);
}
}

How to read and write to NFC tags in NDEF format using C# compatible with Android?

I am working with Mifare Ultralight C tags and write data in NDEF format to them. Am using NDEF-NFC library to create raw bytes for my NDEF message. My NDEF message is
var spRecord = new NdefTextRecord {
Text = "1",
LanguageCode = "en"
};
var msg = new NdefMessage { spRecord };
The output I get is D1 01 04 54 02 65 6E 31 (hexadecimal). If I write this byte array to the tag as-is:
After reading from the tag and using the same NDEF-NFC library I am able to convert back to the desired NDEF message.
Android applications do not recognize the NDEF message. I tried NFC Tools for Android.
Following the suggestions in Writing Ndef to NFC tag in Windows Form Application C# using ACR122U as Reader/Writer, I modified my byte array to write 03 08 D1 01 04 54 02 65 6E 31 FE 00 instead of the original byte array produced by the library.
Now I'm able to read the NDEF message using Android apps.
But on trying to convert the byte array to an NDEF message object using the library, I get the following error:
Ndef parse error: Expected Message Begin missing in first record.
How can I read back the NDEF message correctly?
As you already found, NFC Forum Type 2 tags (such as MIFARE Ultralight, NTAG, etc.) require an NDEF message to be embedded into a NDEF TLV (tag-length-value) structure. This means that you prepend the tag 03 and the length of the NDEF message to the message (value) itself. Thus, you get
+-----+--------+-------------------------+
| TAG | LENGTH | VALUE |
| 03 | 08 | D1 01 04 54 02 65 6E 31 |
+-----+--------+-------------------------+
In addition you may add a Terminator TLV (tag = FE, length = 00) to indicate that the remaining data area on the tag can be skipped from processing.
The NDEF library that you use only processes NDEF messages and not the container format that is needed for storing the data on an NFC tag. Thus, you need to process that part yourself.
Pack NDEF message into TLV structure
var msg = new NdefMessage { ... };
var msgBytes = msg.toByteArray();
var ndefTlvLen = new byte[(msgBytes.Length < 255) ? 1 : 3];
if (msgBytes.Length < 255) {
ndefTlvLen[0] = (byte)(msgBytes.Length);
} else {
ndefTlvLen[0] = (byte)0x0FF;
ndefTlvLen[1] = (byte)((msgBytes.Length >> 8) & 0x0FF);
ndefTlvLen[2] = (byte)(msgBytes.Length & 0x0FF);
}
var tagData = new byte[1 + ndefTlvLen.Length + msgBytes.Length + 2];
int offset = 0;
tagData[offset++] = (byte)0x003;
Array.Copy(ndefTlvLen, 0, tagData, offset, ndefTlvLen.Length);
offset += ndefTlvLen.Length;
Array.Copy(msgBytes, 0, tagData, offset, msgBytes.Length);
offset += msgBytes.Length;
tagData[offset++] = (byte)0x0FE;
tagData[offset++] = (byte)0x000;
Unpack NDEF message from TLV structure
var tagData = ...; // byte[]
var msg;
int offset = 0;
while (offset < tagData.Length) {
byte tag = tagData[offset++];
int len = (tagData[offset++] & 0x0FF);
if (len == 255) {
len = ((tagData[offset++] & 0x0FF) << 8);
len |= (tagData[offset++] & 0x0FF);
}
if (tag == (byte)0x03) {
var msgBytes = new byte[len];
Array.Copy(tagData, offset, msgBytes, 0, len);
msg = NdefMessage.FromByteArray(msgBytes);
} else if (tag == (byte)0xFE) {
break;
}
offset += len;
}

How can I get the hex value in C#?

I am using some sensor with Serial Communication. Because the sensor data have HEX value, I should convert string data to hex data. So, I am using Encoding.Default.GetBytes():
byte[] Bytdata0 = Encoding.Default.GetBytes(st.Substring(0, 1));
byte[] Bytdata1 = Encoding.Default.GetBytes(st.Substring(1, 1));
foreach (byte byte_str in Bytdata0) Whole_data[0] = string.Format("{0:X2}", byte_str);
foreach (byte byte_str in Bytdata1) Whole_data[1] = string.Format("{0:X2}", byte_str);
In this example, there is a problem - the converted value of sensor is wrong when the value is bigger than 0x80.
For example
74 61 85 0A FF 34 00 :: Original signal.
74 61 3F 0A 3F 34 00 :: Converted signal.
the fifth bytes differ. I don't know what is wrong.
string input = "Hello World!";
char[] values = input.ToCharArray();
foreach (char letter in values)
{
// Get the integral value of the character.
int value = Convert.ToInt32(letter);
// Convert the decimal value to a hexadecimal value in string form.
string hexOutput = String.Format("{0:X}", value);
Console.WriteLine("Hexadecimal value of {0} is {1}", letter, hexOutput);
}
/* Output:
Hexadecimal value of H is 48
Hexadecimal value of e is 65
Hexadecimal value of l is 6C
Hexadecimal value of l is 6C
Hexadecimal value of o is 6F
Hexadecimal value of is 20
Hexadecimal value of W is 57
Hexadecimal value of o is 6F
Hexadecimal value of r is 72
Hexadecimal value of l is 6C
Hexadecimal value of d is 64
Hexadecimal value of ! is 21
*/
SOURCE: http://msdn.microsoft.com/en-us/library/bb311038.aspx
// Store integer 182
int decValue = 182;
// Convert integer 182 as a hex in a string variable
string hexValue = decValue.ToString("X");
// Convert the hex string back to the number
int decAgain = int.Parse(hexValue, System.Globalization.NumberStyles.HexNumber);
from http://www.geekpedia.com/KB8_How-do-I-convert-from-decimal-to-hex-and-hex-to-decimal.html

RC4 Encryption non-alphanumeric wrong

Background: I'm trying to convert Mike Shaffer's VB RC4 encryption to C# (https://web.archive.org/web/20210927195845/https://www.4guysfromrolla.com/articles/091802-1.3.aspx). See a previous question of mine at Converting Mike Shaffer's RC4Encryption to C#.
It seems my encryption is not working.
Using the demo page at: https://web.archive.org/web/20000303125329/http://www.4guysfromrolla.com:80/demos/rc4test.asp, with password of "abc":
Plain text: og;|Q{Fe should result in
A2 FA E2 55 09 A4 AB 16
However, my code is generating the 5th char as 9, instead of 09:
A2 FA E2 55 9 A4 AB 16
Another example - Plain text: cl**z!Ss should result in
AE F1 F3 03 22 FE BE 00
However, my code is generating:
AE F1 F3 3 22 FE BE 0
It seems it's only a problem with certain non-alphanumeric characters.
Here's my code:
private static string EnDeCrypt(string text)
{
int i = 0;
int j = 0;
string cipher = "";
// Call our method to initialize the arrays used here.
RC4Initialize(password);
// Set up a for loop. Again, we use the Length property
// of our String instead of the Len() function
for (int a = 1; a <= text.Length; a++)
{
// Initialize an integer variable we will use in this loop
int itmp = 0;
// Like the RC4Initialize method, we need to use the %
// in place of Mod
i = (i + 1) % 256;
j = (j + sbox[i]) % 256;
itmp = sbox[i];
sbox[i] = sbox[j];
sbox[j] = itmp;
int k = sbox[(sbox[i] + sbox[j]) % 256];
// Again, since the return type of String.Substring is a
// string, we need to convert it to a char using
// String.ToCharArray() and specifying that we want the
// first value, [0].
char ctmp = text.Substring(a - 1, 1).ToCharArray()
[0];
itmp = ctmp; //there's an implicit conversion for char to int
int cipherby = itmp ^ k;
cipher += (char)cipherby; //just cast cipherby to a char
}
// Return the value of cipher as the return value of our
// method
return cipher;
}
public static string ConvertAsciiToHex(string input)
{
return string.Join(string.Empty, input.Select(c => Convert.ToInt32(c).ToString("X")).ToArray());
}
public static string Encrypt(string text)
{
return ConvertAsciiToHex(EnDeCrypt(text));
}
Here's how I get my encrypted result:
var encryptedResult = RC4Encrypt.Encrypt(valuetoencrypt);
The output is correct (leading zeros don't change the value), your code is simply not padding values that fit into a single hex digit (such as 9 or 3 or 0). Use .ToString("X2") instead of .ToString("X").

Categories