I have a byte array result. I would like to convert my type called Info which are all int to the byte array but all of them are in different size.
a = 4 bytes
b = 3 bytes
c = 2 bytes
d = 1 bytes
This is the code I've tried.
private byte[] getInfoByteArray(Info data)
{
byte[] result = new byte[10];
BitConverter.GetBytes((data.a)).CopyTo(result, 0);
BitConverter.GetBytes((data.b)).CopyTo(result, 4);
BitConverter.GetBytes((data.c)).CopyTo(result, 7);
result [9] = Convert.ToByte(data.d);
return result;
}
However, I found out that BitConverter.GetBytes returns 4 bytes.
Are there any general solutions that can get different size of bytes to a byte array?
Use Array.Copy(Array, Int32, Array, Int32, Int32) method:
byte[] result = new byte[10];
Array.Copy(BitConverter.GetBytes(data.a), 0, result, 0, 4);
Array.Copy(BitConverter.GetBytes(data.b), 0, result, 4, 3);
Array.Copy(BitConverter.GetBytes(data.c), 0, result, 7, 2);
Array.Copy(BitConverter.GetBytes(data.d), 0, result, 9, 1);
This assumes little endian hardware. If your hardware is big endian, use
byte[] result = new byte[10];
Array.Copy(BitConverter.GetBytes(data.a), 0, result, 0, 4);
Array.Copy(BitConverter.GetBytes(data.b), 1, result, 4, 3);
Array.Copy(BitConverter.GetBytes(data.c), 2, result, 7, 2);
Array.Copy(BitConverter.GetBytes(data.d), 3, result, 9, 1);
Related
I'd like to use an array initializer to build one byte array out of another byte array as well as some other bytes that form a header/trailer. Basically, I'd like to do something like this:
byte[] DecorateByteArray(byte[] payload)
{
return new byte[] { 0, 1, 2, payload.GetBytes(), 3, 4, 5};
}
GetBytes() above is fictional, unfortunately.
Is there any nice/elegant way to do this? I solved this by using a BinaryWriter to write everything to a MemoryStream, and then converting this into a byte array with MemoryStream.ToArray(), but it feels kind of clunky.
The closest you could get would be:
byte[] DecorateByteArray(byte[] payload) =>
new byte[] { 0, 1, 2 }
.Concat(payload)
.Concat(new byte[] { 3, 4, 5 })
.ToArray();
That would be pretty inefficient though. You'd be better off doing something like:
static T[] ConcatArrays<T>(params T[][] arrays)
{
int length = arrays.Sum(a => a.Length);
T[] ret = new T[length];
int offset = 0;
foreach (T[] array in arrays)
{
Array.Copy(array, 0, ret, offset, array.Length);
offset += array.Length;
}
return ret;
}
(Consider using Buffer.BlockCopy too, where appropriate.)
Then call it with:
var array = ConcatArrays(new byte[] { 0, 1, 2 }, payload, new byte[] { 3, 4, 5 });
You can create a new collection that is a List<byte>, but that has an overload of Add that adds a whole array of bytes:
public class ByteCollection: List<byte>
{
public void Add(IEnumerable<byte> bytes)
{
AddRange(bytes);
}
}
This then lets you use the collection initializer for this type to supply either a single byte or a sequence of bytes, which you can then turn back into an array if you need an array:
byte[] DecorateByteArray(byte[] payload)
{
return new ByteCollection() { 0, 1, 2, payload, 3, 4, 5 }.ToArray();
}
One easy way is to break out each into parts and then concat them
byte[] DecorateByteArray(byte[] payload)
{
return new byte[] { 0, 1, 2}
.Concat(payload.GetBytes())
.Concat(new byte[] { 3, 4, 5});
}
So I need to cut off the first 16 bytes from my byte array. I followed another post I saw on Stack Overflow to use the following code:
//split message into iv and encrypted bytes
byte[] iv = new byte[16];
byte[] workingHash = new byte[rage.Length - 16];
//put first 16 bytes into iv
for (int i = 0; i < 16; i++)
{
iv[i] = rage[i];
}
Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length);
What we are trying here is to cut off the first 16 bytes from the byte[] rage and put the rest into byte[] workingHash
The error occurs at Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length);
Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.
Any help will be much appreciated.
The problem is trivial: Buffer.BlockCopy's last argument requires the correct number of bytes to be copied, which (taking the starting index into account) may not exceed the array's bounds (docs).
Hence the code should look like this, avoiding any for cycles:
Buffer.BlockCopy(rage, 0, iv, 0, 16);
Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length - 16);
Notice the “- 16” at the second line, fixing the original code. The first line replaces the for cycle for the sake of consistency.
Lets assume rage is a byte array of length 20:
var rage = new byte[20]
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
};
After byte[] iv = new byte[16];, iv will contain:
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
After byte[] workingHash = new byte[rage.Length - 16];, workingHash will contain:
{ 0, 0, 0, 0 }
After the for loop iv is:
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }
You need:
Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length - 16);
Copy rage.Length - 16 (4) elements from rage's 16th element (which is 17) to workingHash starting from the 0th element.
The result:
{ 17, 18, 19, 20 }
By the way there is a very readable way, probably not as fast as copying arrays, but worth mentioning:
var firstSixteenElements = rage.Take(16).ToArray();
var remainingElements = rage.Skip(16).ToArray();
Fixed:
//split message into iv and encrypted bytes
byte[] iv = new byte[16];
byte[] workingHash = new byte[rage.Length - 16];
//put first 16 bytes into iv
for (int i = 0; i < 16; i++)
{
iv[i] = rage[i];
}
for (int i = 0; i < rage.Length - 16; i++)
{
workingHash[i] = rage[i + 16];
}
Consider the following test:
[Test]
public void TestAes256EcbPkcs7Stream()
{
// 504 bytes of plain text
const string inputString = new string('z', 504);
var inputBytes = Encoding.UTF8.GetBytes(inputString);
byte[] key = {
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0
};
var rij = new RijndaelManaged
{
BlockSize = 256, // 256 bits == 32 bytes
Key = key,
IV = key, // just for test
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
};
var enc = rij.CreateEncryptor();
var encBytes = enc.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
Assert.AreEqual(512, encBytes.Length);
var dec = rij.CreateDecryptor();
byte[] decBytes = new byte[inputBytes.Length];
int decPos = 0;
using (var cipherMs = new MemoryStream(encBytes))
{
var buf = new byte[32];
// process all blocks except the last one
while (cipherMs.Read(buf, 0, buf.Length)==buf.Length &&
cipherMs.Length!=cipherMs.Position)
{
for (int w = 0; w!=buf.Length;)
{
w += dec.TransformBlock(buf, 0, buf.Length, decBytes, decPos);
decPos += w;
}
}
// ensure that we read all blocks
Assert.IsTrue(cipherMs.Length==cipherMs.Position);
// process the last block
var tailBytes = dec.TransformFinalBlock(buf, 0, buf.Length);
// here decPos==480, that means 480 bytes were written to decBytes
// and 504-480 = 24 bytes come from TransformFinalBlock
Assert.AreEqual(24, tailBytes.Length); // <- fail, because the actual length is 56
Buffer.BlockCopy(tailBytes, 0, decBytes, decPos, tailBytes.Length);
}
Assert.AreEqual(inputBytes, decBytes);
}
For some reason I got 56-byte final block instead of 24-byte.
I suppose, TransformBlock/TransformFinalBlock should be used in some other way, but unfortunately, MSDN docs don't explain much about these methods.
Any thoughts?
Ok, here's the thing:
When TransformBlock is called first time, it copies the last block of the input buffer to the so called depad buffer and then transforms and writes remaining blocks to the output buffer. During next calls it transforms data from depad buffer, writes it to the output buffer, copies the last block of the input buffer to the depad buffer again, and writes transformed remaining blocks to the output, just as the first time.
TL;DR: TransformBlock caches the last block of input data so when TransformFinalBlock is called, it can grab the last block and remove padding. Without caching, the last block may be handled by TransformBlock. In that case, padding wouldn't be removed.
This question only vise versa. For now I got this:
UInt32[] target;
byte[] decoded = new byte[target.Length * 2];
Buffer.BlockCopy(target, 0, decoded, 0, target.Length);
And this doesn't work, I get array filled with 0x00.
I would recommend something like the following:
UInt32[] target;
//Assignments
byte[] decoded = new byte[target.Length * sizeof(uint)];
Buffer.BlockCopy(target, 0, decoded, 0, decoded.Length);
See code:
uint[] target = new uint[] { 1, 2, 3 };
//Assignments
byte[] decoded = new byte[target.Length * sizeof(uint)];
Buffer.BlockCopy(target, 0, decoded, 0, decoded.Length);
for (int i = 0; i < decoded.Length; i++)
{
Console.WriteLine(decoded[i]);
}
Console.ReadKey();
Also see:
Size of values
Int Array to Byte Array
BlockCopy MSDN
You can use BitConverter.GetBytes method for converting a unit to byte
Try this code. It works for me.
UInt32[] target = new UInt32[]{1,2,3};
byte[] decoded = new byte[target.Length * sizeof(UInt32)];
Buffer.BlockCopy(target, 0, decoded, 0, target.Length*sizeof(UInt32));
foreach(byte b in decoded)
{
Console.WriteLine( b);
}
You need to multiple by 4 to create your byte array, since UInt32 is 4 bytes (32 bit). But use BitConverter and fill a list of byte and late you can create an array out of it if you need.
UInt32[] target = new UInt32[] { 1, 2, 3 };
byte[] decoded = new byte[target.Length * 4]; //not required now
List<byte> listOfBytes = new List<byte>();
foreach (var item in target)
{
listOfBytes.AddRange(BitConverter.GetBytes(item));
}
If you need array then:
byte[] decoded = listOfBytes.ToArray();
Your code has a few errors:
UInt32[] target = new uint[] { 1, 2, 3, 4 };
// Error 1:
// You had 2 instead of 4. Each UInt32 is actually 4 bytes.
byte[] decoded = new byte[target.Length * 4];
// Error 2:
Buffer.BlockCopy(
src: target,
srcOffset: 0,
dst: decoded,
dstOffset: 0,
count: decoded.Length // You had target.Length. You want the length in bytes.
);
This should yield what you're expecting.
i do have an byte array included a range of numbers...
t Block and not the rest!
How can i have all block 4-8 in Temp[] ??
Elements 4-8 (or in reality index 3-7) is 5 bytes. Not 4.
You have the source offset and count mixed up:
Buffer.BlockCopy(bResponse, 3, temp, 0, 5);
Now temp will contain [23232].
If you want the last 4 bytes then use this:
Buffer.BlockCopy(bResponse, 4, temp, 0, 4);
Now temp will contain [3232].
To convert this to an int:
if (BitConverter.IsLittleEndian)
Array.Reverse(temp);
int i = BitConverter.ToInt32(temp, 0);
Edit: (After your comment that [43323232] actually is {43, 32, 32, 32})
var firstByte = temp[0]; // This is 43
var secondByte = temp[1]; // This is 32
var thirdByte = temp[2]; // 32
var fourthByte = temp[3]; // 32
If you want to convert this to an int then the BitConverter example above still works.