I try parse a byte array to struct but it doesnt work with Sequential. The values are wrong in the Sequential struct but it work correct with Explicit struct? I need sequential the byte array have no fix length. The DwLength field is the size of Data field.
Values
MessageType 128 (Sequential 128)
DwLength 20 (Sequential 33554432)
Slot 0 (Sequential 0)
Seq 0 (Sequential 0)
Status 2 (Sequential 59)
Error 0 (Sequential 143)
ChainParameter 0 (Sequential 128)
Test Code
var bytes = new byte[] { 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x3B, 0x8F, 0x80, 0x01, 0x80, 0x4F, 0x0C, 0xA0, 0x00, 0x00, 0x03, 0x06, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x68 };
var result1 = GetStruct<RdrToPcDataBlock1>(bytes);
var result2 = GetStruct<RdrToPcDataBlock2>(bytes);
struct RdrToPcDataBlock Sequential
[StructLayout(LayoutKind.Sequential)]
public struct RdrToPcDataBlock1
{
public byte MessageType;
public int DwLength;
public byte Slot;
public byte Seq;
public byte Status;
public byte Error;
public byte ChainParameter;
[MarshalAs(UnmanagedType.ByValArray)]
public byte[] Data;
}
struct RdrToPcDataBlock Explicit
[StructLayout(LayoutKind.Explicit)]
public struct RdrToPcDataBlock2
{
[FieldOffset(0)]
public byte MessageType;
[FieldOffset(1)]
public int DwLength;
[FieldOffset(5)]
public byte Slot;
[FieldOffset(6)]
public byte Seq;
[FieldOffset(7)]
public byte Status;
[FieldOffset(8)]
public byte Error;
[FieldOffset(9)]
public byte ChainParameter;
[FieldOffset(10)]
public byte Data;
}
GetStruct
public T GetStruct<T>(byte[] bytes)
{
try
{
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
var item = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
handle.Free();
return item;
}
catch
{
return default(T);
}
}
When you do [StructLayout(LayoutKind.Sequential)] that is the same as doing [StructLayout(LayoutKind.Sequential, Pack=0)] which will use the default packing for the bitness of the process (4 for 32 bit and 8 for 64 bit). To get the behavior your want you need to explicitly say you don't want any padding by setting [StructLayout(LayoutKind.Sequential, Pack=1)]
UPDATE: You still are going to run in to problems with your variable length byte array. See the comment by Jean-Bernard Pellerin
You will have to use a custom marshaller. Otherwise you can't deal with variable length arrays. Here's an example: https://stackoverflow.com/a/38884095/103959
Related
I want to store a known AES key (retrieved offline) by entering it into the application once, saving it to Cng for storage, then reference it only by name on subsequent use.
I want to save the key in the Key Storage Provider so my application won't load it into memory.
I can create (generate) a AES key (that I can retreive and create an instance of AesCng with) like this:
CngProvider keyStorageProvider = CngProvider.MicrosoftSoftwareKeyStorageProvider;
CngKeyCreationParameters keyCreationParameters = new CngKeyCreationParameters()
{
ExportPolicy = CngExportPolicies.AllowPlaintextExport,
KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey
};
var name = "mykey";
var algo = new CngAlgorithm("AES");
var created = CngKey.Create(algo, name, keyCreationParameters);
But how can I add my already known AES symmetric key and just reference it by name the next time I run my application to run encryption/decryption using Cng?
Using CngKey.Import won't let me specify a name and I think I've tried all overloads but all yield some kind of error.
UPDATE:
This is a complete working example when creating a key.
// Calling code
byte[] key = //<from external input>;
byte[] data = new byte[] { 0xA, 0xB, 0xC, 0xD };
crypto.StoreKey("appkey", key);
var encryptedData = crypto.EncryptWithStoredKey("appkey", data);
// Implementation
public void StoreKey(string name, byte[] key)
{
CngKeyCreationParameters keyCreationParameters = new CngKeyCreationParameters()
{
KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey
};
var algo = new CngAlgorithm("AES");
// Question: How can I import the byte[] key with name "appkey" instead of generating a new key here?
CngKey.Create(algo, name, keyCreationParameters);
}
public byte[] EncryptWithStoredKey(string name, byte[] data)
{
using (var cng = new AesCng(name))
using (var encryptor = cng.CreateEncryptor())
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return memoryStream.ToArray();
}
}
}
It's... not nice. But it's technically doable. Reusing some of the import definitions from X509Certificate2.Import with NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG:
private static unsafe CngKey ImportPersistedAesKey(string keyName, byte[] key)
{
switch (key.Length * 8)
{
case 128:
case 192:
case 256:
break;
default:
throw new ArgumentOutOfRangeException(nameof(key));
}
byte[] blob = new byte[s_cipherKeyBlobPrefix.Length + key.Length];
Buffer.BlockCopy(s_cipherKeyBlobPrefix, 0, blob, 0, s_cipherKeyBlobPrefix.Length);
blob[12] = (byte)(12 /* sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) */ + key.Length);
blob[32] = (byte)key.Length;
Buffer.BlockCopy(key, 0, blob, s_cipherKeyBlobPrefix.Length, key.Length);
fixed (char* keyNamePtr = keyName)
fixed (byte* blobPtr = blob)
{
NativeMethods.NCrypt.NCryptBuffer nameBuf;
nameBuf.BufferType = NativeMethods.NCrypt.BufferType.PkcsName;
nameBuf.cbBuffer = (keyName.Length + 1) * 2;
nameBuf.pvBuffer = (IntPtr)keyNamePtr;
NativeMethods.NCrypt.NCryptBufferDesc bufferDesc;
bufferDesc.ulVersion = 0;
bufferDesc.cBuffers = 1;
bufferDesc.pBuffers = (IntPtr)(&nameBuf);
int ret = NativeMethods.NCrypt.NCryptOpenStorageProvider(
out SafeNCryptProviderHandle hProv,
CngProvider.MicrosoftSoftwareKeyStorageProvider.Provider,
0);
using (hProv)
{
if (ret != 0)
{
throw new Win32Exception(ret);
}
ret = NativeMethods.NCrypt.NCryptImportKey(
hProv,
IntPtr.Zero,
"CipherKeyBlob",
ref bufferDesc,
out SafeNCryptKeyHandle hKey,
(IntPtr)blobPtr,
blob.Length,
NativeMethods.NCrypt.NCryptImportFlags.NCRYPT_OVERWRITE_KEY_FLAG);
using (hKey)
{
if (ret != 0)
{
throw new Win32Exception(ret);
}
return CngKey.Open(hKey, CngKeyHandleOpenOptions.None);
}
}
}
}
private static byte[] s_cipherKeyBlobPrefix = {
// NCRYPT_KEY_BLOB_HEADER.cbSize (16)
0x10, 0x00, 0x00, 0x00,
// NCRYPT_KEY_BLOB_HEADER.dwMagic (NCRYPT_CIPHER_KEY_BLOB_MAGIC (0x52485043))
0x43, 0x50, 0x48, 0x52,
// NCRYPT_KEY_BLOB_HEADER.cbAlgName (8)
0x08, 0x00, 0x00, 0x00,
// NCRYPT_KEY_BLOB_HEADER.cbKeyData (to be determined)
0x00, 0x00, 0x00, 0x00,
// UTF16-LE "AES\0"
0x41, 0x00, 0x45, 0x00, 0x53, 0x00, 0x00, 0x00,
// BCRYPT_KEY_DATA_BLOB_HEADER.dwMagic (BCRYPT_KEY_DATA_BLOB_MAGIC (0x4D42444B))
0x4B, 0x44, 0x42, 0x4D,
// BCRYPT_KEY_DATA_BLOB_HEADER.dwVersion (1)
0x01, 0x00, 0x00, 0x00,
// BCRYPT_KEY_DATA_BLOB_HEADER.cbKeyData (to be determined)
0x00, 0x00, 0x00, 0x00
};
internal static class NativeMethods
{
internal static class NCrypt
{
[StructLayout(LayoutKind.Sequential)]
internal struct NCryptBufferDesc
{
public int ulVersion;
public int cBuffers;
public IntPtr pBuffers;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NCryptBuffer
{
public int cbBuffer;
public BufferType BufferType;
public IntPtr pvBuffer;
}
internal enum BufferType
{
PkcsName = 45,
}
[DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
internal static extern int NCryptOpenStorageProvider(
out SafeNCryptProviderHandle phProvider,
string pszProviderName,
int dwFlags);
internal enum NCryptImportFlags
{
None = 0,
NCRYPT_MACHINE_KEY_FLAG = 0x00000020,
NCRYPT_OVERWRITE_KEY_FLAG = 0x00000080,
NCRYPT_DO_NOT_FINALIZE_FLAG = 0x00000400,
}
[DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
internal static extern int NCryptImportKey(
SafeNCryptProviderHandle hProvider,
IntPtr hImportKey,
string pszBlobType,
ref NCryptBufferDesc pParameterList,
out SafeNCryptKeyHandle phKey,
IntPtr pbData,
int cbData,
NCryptImportFlags dwFlags);
[DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
internal static extern int NCryptFinalizeKey(SafeNCryptKeyHandle hKey, int dwFlags);
}
}
The expected flow is that you should be able to create a key and then use NCryptSetKeyProperty to set the NCRYPT_CIPHER_KEY_BLOB property for the NCRYPT_CIPHER_KEY_BLOB payload (from the .NET perspective that'd be you call CngKey.Create with creation parameters and specify it as a creation property). But it looks like CNG didn't wire that up for persisted symmetric keys, so you have to use the complicated form of NCryptImportKey directly.
The Premise
I am continually polling custom modbus frames from an embedded device with my c# wpf application at a low interval. At the moment the bytes in the frame i receive are located at the same position every time(e.g. frame[15]+frame[16] = 0x0532 = errorcode2).
The Questions
Are there smart procedures (other than simply hardcoding the bytestorage) I could use to go from frame receiving to splitting/parsing?
What data structures would be preferrable to enable frames to be processed dynamically further down the line?
Method 1:
You can define an explicitly laid out struct in C# and marshal the data to it like is done in the code below. However, you will have problems with the data due to endian ordering if you are not running on big endian hardware (Modbus data is sent in big endian). This also won't handle variable length Modbus packets (i.e. Read Input Registers). NOTE: It is assumed that the frame has already been CRC checked so there is no need to declare and read it.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyPacket
{
public Byte Address; // Byte 0
public Byte FunctionCode; // Byte 1
public Byte ByteField; // Byte 2
public UInt32 UInt32Field; // Bytes 3-6
public UInt64 UInt64Field; // Byte 7-14
public UInt16 ErrorCode; // Bytes 15-16
}
public static bool TryParse<T>(byte[] array, out T packet) where T : struct
{
try
{
var size = Marshal.SizeOf(typeof(T));
var p = Marshal.AllocHGlobal(size);
Marshal.Copy(array, 0, p, size);
packet = (T)Marshal.PtrToStructure(p, typeof(T));
Marshal.FreeHGlobal(p);
return true;
}
catch
{
packet = default(T);
return false;
}
}
static int Main(string[] args)
{
// Create a sample frame
byte[] bytes = new byte[] { 0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
MyPacket packet;
if (TryParse<MyPacket>(bytes, out packet))
{
// Process packet here...
}
return 0;
}
Method 2:
What I think is a better solution is to define a class for each function type that you use and read each field individually as shown in the code below. NOTE: It is assumed that the frame has already been CRC checked so there is no need to declare and read it.
// VERY SIMPLE BigEndianReader class
public class BigEndianReader
{
private Stream _stream;
public BigEndianReader(Stream stream)
{
if (stream == null) throw new ArgumentNullException(nameof(stream));
if (!stream.CanRead) throw new ArgumentException(nameof(stream));
_stream = stream;
}
public byte ReadByte()
{
int b = _stream.ReadByte();
if (b < 0) throw new EndOfStreamException();
return (byte)b;
}
public UInt16 ReadUInt16()
{
UInt16 v = 0;
for (int i = 0; i < sizeof(UInt16); i++){v <<= 8;v |= ReadByte();}
return v;
}
public UInt32 ReadUInt32()
{
UInt32 v = 0;
for (int i = 0; i < sizeof(UInt32); i++){v <<= 8;v |= ReadByte();}
return v;
}
public UInt64 ReadUInt64()
{
UInt64 v = 0;
for (int i = 0; i < sizeof(UInt64); i++) { v <<= 8; v |= ReadByte(); }
return v;
}
}
class MyPacket
{
public Byte Address { get; private set; }
public Byte FunctionCode { get; private set; }
public Byte ByteField { get; private set; }
public UInt32 UInt32Field { get; private set; }
public UInt64 UInt64Field { get; private set; }
public UInt16 ErrorCode { get; private set; }
public static bool TryParse(byte[] bytes, out MyPacket result)
{
result = null;
try
{
BigEndianReader r = new BigEndianReader(new MemoryStream(bytes));
MyPacket p = new MyPacket();
p.Address = r.ReadByte();
p.FunctionCode = r.ReadByte();
p.ByteField = r.ReadByte();
p.UInt32Field = r.ReadUInt32();
p.UInt64Field = r.ReadUInt64();
p.ErrorCode = r.ReadUInt16();
result = p;
return true;
}
catch
{
return false;
}
}
}
static int Main(string[] args)
{
// Create a sample frame
byte[] bytes = new byte[] { 0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 };
MyPacket packet;
if (MyPacket.TryParse(bytes, out packet))
{
// Process packet here...
}
//==================================================================
Console.Write("(press any key to exit)");
Console.ReadKey(true);
return 0;
}
I have little bit problem with USB communication. I can connect to USB device but I cannot write any data to USB device.
This is my code to write data to USB device:
public byte[] GetUID = { 0xFF, 0xCA, 0x00, 0x00, 0x00 };
public byte[] SCardConnect = { 0x68, 0x92, 0x01, 0x00, 0x03, 0x01, 0x00, 0x00 };
public bool WriteBulk(byte[] str)
{
//ErrorCode ec = ErrorCode.None;
if (IsConnected == false)
return false;
else Console.WriteLine("connected");
/*endpointWriter = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02, EndpointType.Bulk);
int bytesWritten = length;
ec = endpointWriter.Write(protocol, 5000, out bytesWritten);
if (ec != ErrorCode.None) return false;
else return true;*/
UsbSetupPacket packet = new UsbSetupPacket((byte)UsbRequestType.TypeVendor, 0x04, 0, 0, (short)str.Length);
int lengthTransfered;
return MyUsbDevice.ControlTransfer(ref packet, str, str.Length, out lengthTransfered);
}
public bool checkUID()
{
return WriteBulk(GetUID);
}
public bool checkSCardConnect()
{
return WriteBulk(SCardConnect);
}
When I use checkUID() or checkSCardConnect(), it always returns false. Is there any other procedure to write using USB Communication?
I am sending an API frame using the following code:
byte[] bytesToSend5 = new byte[]
{
0x7E, 0x00, 0x10, 0x01, 0x00, 0x13,
0xA2, 0x00, 0x40, 0xA6, 0x5E, 0x23,
0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04, 0x4D
};
serialPort1.Write(bytesToSend5, 0, bytesToSend5.Length);
It's split up like this:
byte[] bytesToSend5 = new byte[]
{
5Startbits(won't change),
8IDbits(changes when a part of the device is swapped),
6determinationbits(tells the device what to do),
1checksumbit(calculated based on previous bits)
};
The first code example works as is desired with the current product. If, for whatever reason, a part of the device needs to be changed, it will not work because the ID bits won't fit. The ID number is printed on the device, 16 digits with numbers and letters, such as "0013A20043A25E86".
What I want to do is make a textbox where the user can input the new ID number and it will be replaced with the appropriate bits in the aforementioned byte array.
Here is my attempt using the Array.Copy function, trying to display the result in a textbox - but no change is detected. I've tried typing "1" "1,2,3" etc as well as the actual ID's "0013A20043A25E86":
string xbee_serienr = prop1_serienr.Text;
byte[] front = { 0x7E, 0x00, 0x10, 0x17, 0x01 };
byte[] back = { 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04 };
string[] xbee = { xbee_serienr };
byte[] combined = new byte[front.Length + xbee.Length + back.Length];
Array.Copy(front, combined, front.Length);
Array.Copy(back, 0, combined, 5, back.Length);
var result = string.Join(",", combined.Select(x => x.ToString()).ToArray());
OutputWindow.Text = result;
It would have to be possible to change the 8ID bits based on user input, and calculate the last checksum bit based on the rest of the bits.
I have searched the internet and tried Array.copy, Concat etc. but I haven't made any progress with it. Any guidance or input on this would be highly appreciated, even if it means guiding me in a direction of taking a different approach.
EDIT:
I now have the desired information in the byte array "result" using roughly the same example as below (taking user input for the var "xbee_serienr"). I now want to pass this to a method that looks like this:
private void button_D07_Lav_Click(object sender, EventArgs e)
{
byte[] bytesToSend5 = new byte[] { 0x7E, 0x00, 0x10, 0x01, 0x00, 0x13, 0xA2, 0x00, 0x40, 0xA6, 0x5E, 0x23, 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04, 0x4D };
serialPort1.Write(bytesToSend5, 0, bytesToSend5.Length);
And make the "bytesToSend5" use the array "result" from the other method.
I've tried using this example, like so:
byte result { get; set; } //above and outside of the two methods
var result = string.Join(string.Empty, combined.Select(x => x.ToString("X2")).ToArray()); //this is the end of the first method
private void button_D07_Lav_Click(object sender, EventArgs e)
{
byte[] bytesToSend5 = new byte[] { 0x7E, 0x00, 0x10, 0x01, 0x00, 0x13, 0xA2, 0x00, 0x40, 0xA6, 0x5E, 0x23, 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04, 0x4D };
bytesToSend5 = result; //using the array stored in result instead of the one currently in bytesToSend5.
serialPort1.Write(bytesToSend5, 0, bytesToSend5.Length);
}
I realize the obvious problem here, that it's not on the same form. This is why I wanted to split the array and add 0x in front of every item in the array, and separate them with commas.
I'm also going to use this for several different devices once I figure it out properly, which makes me fear there will be a lot of duplicated code, but I suspect once I'm understanding how to pass and use the array in a different method, I can always "duplicate" the code for every device, since the ID will indeed need to be different for the different devices.
Well, you never add the parsed string.
var xbee_serienr = "0013A20043A25E86";
byte[] front = { 0x7E, 0x00, 0x10, 0x17, 0x01 };
byte[] back = { 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04 };
var xbee = new byte[xbee_serienr.Length / 2];
for (var i = 0; i < xbee.Length; i++)
{
xbee[i] = byte.Parse(xbee_serienr.Substring(i * 2, 2), NumberStyles.HexNumber);
}
byte[] combined;
using (var ms = new MemoryStream(front.Length + xbee.Length + back.Length))
{
ms.Write(front, 0, front.Length);
ms.Write(xbee, 0, xbee.Length);
ms.Write(back, 0, back.Length);
combined = ms.ToArray();
}
var result = string.Join(string.Empty, combined.Select(x => x.ToString("X2")).ToArray());
Since you're adding multiple arrays one after another, I just used a MemoryStream. If you already have the byte[] ready (and mutable), you can write directly to that byte array and avoid allocating (and collecting) the extra array, but it doesn't make much of a difference when the limiting factor is the UI anyway.
am using BouncyCastel to make a CfbBlockCipher so here is the codes.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
namespace Common.Encryption
{
public class BlowfishCryptographer
{
private bool forEncryption;
private IBufferedCipher cipher;
public BlowfishCryptographer(bool forEncryption)
{
this.forEncryption = forEncryption;
cipher = new BufferedBlockCipher(new CfbBlockCipher(new BlowfishEngine(), 64));
cipher.Init(forEncryption, new ParametersWithIV(new KeyParameter(Encoding.ASCII.GetBytes("DR654dt34trg4UI6")), new byte[8]));
}
public void ReInit(byte[] IV,BigInteger pubkey)
{
cipher.Init(forEncryption, new ParametersWithIV(new KeyParameter(pubkey.ToByteArrayUnsigned()),IV));
}
public byte[] DoFinal()
{
return cipher.DoFinal();
}
public byte[] DoFinal(byte[] buffer)
{
return cipher.DoFinal(buffer);
}
public byte[] DoFinal(byte[] buffer, int startIndex, int len)
{
return cipher.DoFinal(buffer, startIndex, len);
}
public byte[] ProcessBytes(byte[] buffer)
{
return cipher.ProcessBytes(buffer);
}
public byte[] ProcessBytes(byte[] buffer, int startIndex, int len)
{
return cipher.ProcessBytes(buffer, startIndex, len);
}
public void Reset()
{
cipher.Reset();
}
}
}
so...
byte[] buf = new byte[] { 0x83, 0x00, 0xEE, 0x03, 0x26, 0x6D, 0x14, 0x00, 0xF1, 0x65, 0x27, 0x00, 0x19, 0x02, 0xD8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xD7, 0x0F, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
if i said ProcessBytes(buf, 0, 17) it will only return 16, i also tried DoFinal() but it's not doing it's job!!!
is that up to IBufferedCipher should i use IStreamCipher or something else to get the exact amount of what am dec/enc-ing? And i believe CfbBlockCipher is broken somehow or am doing something worng here.
I don't know what you consider not doing the job here. You need to call ProcessBytes multiple times and finish with DoFinal(). It's normal that ProcessBytes() only returns 16 bytes because that is x times the block size. The cipher does not know if you've finished feeding it bytes, so it cannot calculate another block until you call DoFinal(). Of course, you need to append the output of the ProcessBytes() and DoFinal() calls to get the end result...