This question is somewhat extension of a question asked previously c# using marshalling for packet parsing by me.
I have to parse a variable size packet although header size is fixed but data packets inside it can be of different size and may be of more than 1 type are present in same packet.
For example the packet has following fields in its header :
1) username(12 bytes)
2 password(12 bytes)
3) id_number(4 bytes)
4) may be 1 or combination of other data packets of variable size(size can be 12, 16 or 512 bytes)
5) crc(2 bytes)
Now data packets can be following
a) data packet type 1
1) size(2 bytes)
2) name(12 bytes)
3) id_number(2 bytes)
b) data packet type 2
1) size(2 bytes)
2) data(24 bytes)
3) id_number(1 byte).
So there can be either type1 or type2. It is also possible for both type to be present. My question is how can I use marshalling to parse these packets or anyone can suggest some other way.
One more thing I want to add is that 1st and 3rd field of data packets will always be the data packet size(2 bytes) and data packet id number(1 byte) respectively. The 2nd field of data packets can be anything and of variable size(2, 3, 13, 18, 515).
As an alternative, you may use LINQ (assuming that ASCII encoding is being used):
var packet = new byte[]{
97, 108, 101, 120, 0, 0, 0, 0, 0, 0, 0, 0, // username
112, 97, 115, 115, 119, 111, 114, 100, 0, 0, 0, 0, //password
49, 50, 51, 0, // id_number
0, 53, 0, 0, 1, // 1st data packet
0, 54, 1, 2, 5, 2, // 2nd data packet
49, 0 // crc
};
var username = Encoding.ASCII.GetString(packet.Take(12).ToArray());
var password = Encoding.ASCII.GetString(packet.Skip(12).Take(12).ToArray());
var idNumber = Encoding.ASCII.GetString(packet.Skip(24).Take(4).ToArray());
var data = packet.Skip(28).Take(packet.Length - 30).ToArray();
var crc = Encoding.ASCII.GetString(packet.Skip(packet.Length - 2).ToArray());
var nextDataPackedPos = 0;
var nextDataPackedPos = 0;
var dataPackets = data
.TakeWhile(b => nextDataPackedPos < data.Length)
.Zip(data.Skip(nextDataPackedPos), (a, b) =>
{
var size = Int32.Parse(
Encoding.ASCII
.GetString(data.Skip(nextDataPackedPos).Take(2).ToArray())
.Trim('\0')
);
var result = data.Skip(nextDataPackedPos).Take(size).ToArray();
nextDataPackedPos += size;
return result;
}).ToList();
The code first separates the data section from the packet bytes. Then it reads the size of each packet and based on it, it creates an equaly sized array containing the bytes of the data packet. It hen advances to the beginning of the next packet until the end of the array is reached.
Related
LabVIEW code:
C# code I tried:
var freqArray = new byte[] { 67, 179, 84, 45 };
// 358.658
var r1 = BitConverter.ToDouble(freqArray, 0);
First you are dealing with a 4 byte values and double require 8 bytes. What you want is using single as it's a 4 bytes.
var r1 = BitConverter.ToSingle(freqArray, 0);
Secondly your array is backward and it should be :
var freqArray = new byte[] { 45, 84 , 179, 67 };
this might sound unclear but i know its difficult but we can remove specific bytes from byte[] array but if the array contain similiar values while removing values it can remove other values i m using :
byte[] B = new byte[] { 10, 0, 0, 10 };
byte[] D = new byte[] { 0, 0 };
byte[] NewArray = B.Except(D).ToArray();
BytesDisplayer.Text = String.Join(",", NewArray);
but lets say i have a byte as:
byte[] Data = new byte[] {0,10,10,10,0,5,5,5,10,10,10};
and i want to remove the last 3 values (10) My method will remove all the 10 value on that array , so basically i want to know is there is a way to remove specific bytes in specific indexes and how ?
try this:
byte[] Data = new byte[] { 0, 10, 10, 10, 0, 5, 5, 5, 10, 10, 10 };
Data = Data.Where((item, index) => index < 8).ToArray();
Why is this program not working? I convert a byte array to long. Then from the long I convert back to a byte array. The resulting byte array is not the same as original.
class Program
{
static void Main(string[] args)
{
byte[] myBytes = { 0, 0, 0, 32, 56, 99, 87, 34, 56, 56, 34, 33, 67
, 56, 66, 72, 1, 0, 0, 56, 0, 22};
long data = BitConverter.ToInt64(myBytes, 0);
byte[] byteData = BitConverter.GetBytes(data);
Console.WriteLine("byte array: " + BitConverter.ToString(myBytes));
Console.WriteLine("byte array: " + BitConverter.ToString(byteData));
}
}
Since l4V already gave the right assumption, I just want to add it as an aswer but I think my answer doesn't deserve any votes since all upvotes should go to l4V. Upvote his comment.
From BitConverter.ToInt64
The ToInt64 method converts the bytes from index startIndex to
startIndex + 7 to a Int64 value.
So basicly, this conversations takes only 8 bytes (0, 0, 0, 32, 56, 99, 87, 34) of your byte array. Other bytes of your array are ignored at this situation.
The length of bytes exceed a long can hold(8 bytes, 64 bits).
For alternative solution, I'd suggest to use BigInteger if your target framework is higher than(including) .Net 4.0.
I have two byte[] (like this { 0, 0, 0, 0, 52, 246, 141, 6 }) that represent two Oracle's timestamps.
How do I know which one is older?
Convert the binary timestamp to Int64 and then compare the corresponding long values:
var value = new byte[] { 0, 0, 0, 0, 52, 246, 141, 6 };
long timestamp = BitConverter.ToInt64(value, 0);
The bigger the long value, the more recent the timestamp. I haven't used Oracle but I would guess this represents the number of ticks since the Epoch.
I should implement a MAC-CBC generation method in C# with some information about the cryptography algorithm. Here's what I have:
I should use DES.
The key is byte[] {11, 11, 11, 11, 11, 11, 11, 11}
The data (16 bytes) should be encrypted in 8-byte parts. First 8 bytes is encrypted using Instance Vector = new byte[8] (8 bytes with 0 value). (CBC?)
that last 8 bytes of the encrypted value should be converted to Hex string. this is the result I should send.
With this information, I have implemented the following method:
public static string Encrypt(byte[] data)
{
var IV = new byte[8];
var key = new byte[] { 11, 11, 11, 11, 11, 11, 11, 11 };
var result = new byte[16];
// Create DES and encrypt.
var des = DES.Create();
des.Key = key;
des.IV = IV;
des.Padding = PaddingMode.None;
des.Mode = CipherMode.CBC;
ICryptoTransform cryptoTransform = des.CreateEncryptor(key, IV);
cryptoTransform.TransformBlock(data, 0, 16, result, 0);
// Get the last eight bytes of the encrypted data.
var lastEightBytes = new byte[8];
Array.Copy(result, 8, lastEightBytes, 0, 8);
// Convert to hex.
var hexResult = string.Empty;
foreach (byte ascii in lastEightBytes)
{
int n = (int)ascii;
hexResult += n.ToString("X").PadLeft(2, '0');
}
return hexResult;
}
The sample raw data they have provided me is: input=byte[] {0, 6, 4, 1, 6, 4, 1, 7, E, E, F, F, F, F, B, B) which should return the output of value: A7CBFB3C730B059C. This means the last eight bytes of encrypted data should be: byte[] {167, 203, 251, 60, 115, 11, 05, 156}.
But unfortunately using the above method, I get: 32D91200D0007632. meaning my encrypted data is not correct. (the last eight byte of my method's generated encrypted value is byte[] {50, 207, 18, 0, 208, 0, 118, 50}).
Is there any way that I can find out what I should do to get to A7CB...? Am I doing something wrong?
CBC-MAC requires a zero Initialisation Vector. Much better to specify the IV explicitly:
var IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
You say your key is byte[] { 11, 11, 11, 11, 11, 11, 11, 11 } are those bytes in hex or in base 10? You might want to try:
var key = new byte[] { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 };
and see if that works better.
The Mono project has a generic MAC-CBC implementation that should work on any SymmetricAlgorithm - even if it's used, internally, only to implement MACTripleDES.
You can find the MIT.X11 licensed source code here. Use it as-is or compare it to your own code.