I'm encrypting my file with Blowfish algorithm but it seems that I don't know something about it. Whenever I try to Encipher() it will throw an exception that says 'Invalid Length'. I figured that the length must be zero when it's getting mod with 8 and I think it means there should be 8 by 8 blocks of stream to start encipher. What should I do?
Encipher method of Blowfish:
public void Encipher(byte[] data, int length)
{
uint xl, xr;
if ((length % 8) != 0) <-- Exception Line
throw new Exception("Invalid Length");
for (int i = 0; i < length; i += 8)
{
// Encode the data in 8 byte blocks.
xl = (uint)((data[i] << 24) | (data[i + 1] << 16) | (data[i + 2] << 8) | data[i + 3]);
xr = (uint)((data[i + 4] << 24) | (data[i + 5] << 16) | (data[i + 6] << 8) | data[i + 7]);
Encipher(ref xl, ref xr);
// Now Replace the data.
data[i] = (byte)(xl >> 24);
data[i + 1] = (byte)(xl >> 16);
data[i + 2] = (byte)(xl >> 8);
data[i + 3] = (byte)(xl);
data[i + 4] = (byte)(xr >> 24);
data[i + 5] = (byte)(xr >> 16);
data[i + 6] = (byte)(xr >> 8);
data[i + 7] = (byte)(xr);
}
}
My encryption method:
private void EncryptFile(string szFilePath, string szInfoFile, string szKey, string szEncryptedFile = "")
{
// Blowfish
Blowfish alg = new Blowfish(Encoding.Unicode.GetBytes(szKey));
// Open file
System.IO.FileStream originalStream = System.IO.File.OpenRead(szFilePath);
// Store original file length
long originalLength = originalStream.Length;
System.IO.File.WriteAllText(szInfoFile, originalLength.ToString());
Byte[] buffer = new byte[originalStream.Length + (originalStream.Length % 8)];
originalStream.Read(buffer, 0, buffer.Length);
originalStream.Close();
// Encrypt
alg.Encipher(buffer, buffer.Length);
string szEncFile;
if (szEncryptedFile != string.Empty) szEncFile = szEncryptedFile; else szEncFile = szFilePath;
System.IO.FileStream stream = new System.IO.FileStream(szEncFile, System.IO.FileMode.Create);
stream.Write(buffer, 0, buffer.Length);
stream.Close();
}
Thanks.
If what you're trying to do is round a value up to the next value divisible by 8, then you should do this instead:
Byte[] buffer = new byte[originalStream.Length + (8-(originalStream.Length % 8))];
Peter Ritchie answered it. However, there are a couple of idiomatic pieces you should consider below. One is wrapping IDisposable-implemented classes (such as FileStreams) in using blocks in order to ensure disposal of the resources in the case of exceptional conditions during processing. Another is the if..then you put in one line. It's really .. odd. I've replaced it with the ternary operator, which seems to fit the usage you're employing. Best of luck.
private void EncryptFile(string szFilePath, string szInfoFile, string szKey, string szEncryptedFile = "")
{
// Blowfish
Blowfish alg = new Blowfish(Encoding.Unicode.GetBytes(szKey));
// Open file
using (System.IO.FileStream originalStream = System.IO.File.OpenRead(szFilePath))
{
// Store original file length
long originalLength = originalStream.Length;
System.IO.File.WriteAllText(szInfoFile, originalLength.ToString());
Byte[] buffer = new byte[originalStream.Length + (originalStream.Length % 8)];
originalStream.Read(buffer, 0, buffer.Length);
}
// Encrypt
alg.Encipher(buffer, buffer.Length);
string szEncFile;
szEncFile = string.IsNullOrEmpty(szEncryptedFile) ? szFilePath : szEncryptedFile;
using (System.IO.FileStream stream = new System.IO.FileStream(szEncFile, System.IO.FileMode.Create))
{
stream.Write(buffer, 0, buffer.Length);
}
}
Related
How can i send a message from my WinForm VB.NET project to my WebSocket?
Actually i was able to do it by sending proper byte data to the NetworkStream in c# via the following code in c# which codify the string message to byte array:
private static byte[] EncodeMessageToSend(string message)
{
byte[] response;
byte[] bytesRaw = Encoding.UTF8.GetBytes(message);
byte[] frame = new byte[10];
int indexStartRawData = -1;
int length = bytesRaw.Length;
frame[0] = (Byte)129;
if (length <= 125)
{
frame[1] = (Byte)length;
indexStartRawData = 2;
}
else if (length >= 126 && length <= 65535)
{
frame[1] = (Byte)126;
frame[2] = (Byte)((length >> 8) & 255);
frame[3] = (Byte)(length & 255);
indexStartRawData = 4;
}
else
{
frame[1] = (Byte)127;
frame[2] = (Byte)((length >> 56) & 255);
frame[3] = (Byte)((length >> 48) & 255);
frame[4] = (Byte)((length >> 40) & 255);
frame[5] = (Byte)((length >> 32) & 255);
frame[6] = (Byte)((length >> 24) & 255);
frame[7] = (Byte)((length >> 16) & 255);
frame[8] = (Byte)((length >> 8) & 255);
frame[9] = (Byte)(length & 255);
indexStartRawData = 10;
}
response = new Byte[indexStartRawData + length];
Int32 i, reponseIdx = 0;
//Add the frame bytes to the reponse
for (i = 0; i < indexStartRawData; i++)
{
response[reponseIdx] = frame[i];
reponseIdx++;
}
//Add the data bytes to the response
for (i = 0; i < length; i++)
{
response[reponseIdx] = bytesRaw[i];
reponseIdx++;
}
return response;
}
Then i jsut used that code with stream.Write but what will be an equivalent code in VB? or is there another way to send a message to the WebSocket?
PS: the websocket doesn't accept a simple string or a simple string converted to byte[] i've yet tryed it.
I send a message over a websocket by using System.Net.Websockets.Websocket which has an asynchronous send function:
Dim bytes = Encoding.UTF8.GetBytes(message)
Await socket.SendAsync(New ArraySegment(Of Byte)(bytes, 0, bytes.length), Websockets.WebsocketMessageType.Text, True, cancelToken)
Note that chunking may be required depending on the maximum frame size; if so, send each chunk but the last with the penultimate parameter as False and adjust the initial position and length of the array segment accordingly.
(Addendum: I've just noticed that the initial position and segment length are not required in the ArraySegment(Of Byte) construction if making it out of the whole array, but I'm going to leave it in place here because it will be clearer what changes would need to be made to chunk the message.)
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
As far as I know Microsoft have made .Net Core open source located at https://github.com/dotnet/runtime.
Since I want to look at the source code for the string extension method "Substring" and its overloads I went over there and used Github's search functionality to look for it but had no success. I then downloaded the entire repo and ran a local windows search but couldn't find anything, again, even after looking through the folders and files. Suffice it to say I am a huge novice at navigating and understanding how code is structured.
So where can I find the source code for the "Substring" method and its overloads?
You can find it here string.cs for framework
The fundamental implementation is as such
[System.Security.SecurityCritical] // auto-generated
unsafe string InternalSubString(int startIndex, int length)
{
Contract.Assert( startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
Contract.Assert( length >= 0 && startIndex <= this.Length - length, "length is out of range!");
String result = FastAllocateString(length);
fixed(char* dest = &result.m_firstChar)
fixed(char* src = &this.m_firstChar) {
wstrcpy(dest, src + startIndex, length);
}
return result;
}
Basically it just allocates what it needs, and pointer copies using wstrcpy which in turn uses memcpy, and that just iterates over pointers with a loop
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}
Update
Note the .Net Core uses a different codebase for this method which can be found here
SubString calls InternalSubString calls Buffer.Memmove which has been heavily optimized for certain situations and environments
internal unsafe static void Memmove(byte* dest, byte* src, nuint len)
{
#if AMD64 || (BIT32 && !ARM)
const nuint CopyThreshold = 2048;
#elif ARM64
#if PLATFORM_WINDOWS
//
const nuint CopyThreshold = 2048;
#else // PLATFORM_WINDOWS
// Managed code is currently faster than glibc unoptimized memmove
//
const nuint CopyThreshold = UInt64.MaxValue;
#endif // PLATFORM_WINDOWS
#else
const nuint CopyThreshold = 512;
#endif // AMD64 || (BIT32 && !ARM)
// P/Invoke into the native version when the buffers are overlapping.
if (((nuint)dest - (nuint)src < len) || ((nuint)src - (nuint)dest < len)) goto PInvoke;
byte* srcEnd = src + len;
byte* destEnd = dest + len;
if (len <= 16) goto MCPY02;
if (len > 64) goto MCPY05;
MCPY00:
// Copy bytes which are multiples of 16 and leave the remainder for MCPY01 to handle.
Contract.Assert(len > 16 && len <= 64);
#if HAS_CUSTOM_BLOCKS
*(Block16*)dest = *(Block16*)src; // [0,16]
#elif BIT64
*(long*)dest = *(long*)src;
*(long*)(dest + 8) = *(long*)(src + 8); // [0,16]
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
*(int*)(dest + 8) = *(int*)(src + 8);
*(int*)(dest + 12) = *(int*)(src + 12); // [0,16]
#endif
if (len <= 32) goto MCPY01;
#if HAS_CUSTOM_BLOCKS
*(Block16*)(dest + 16) = *(Block16*)(src + 16); // [0,32]
#elif BIT64
*(long*)(dest + 16) = *(long*)(src + 16);
*(long*)(dest + 24) = *(long*)(src + 24); // [0,32]
#else
*(int*)(dest + 16) = *(int*)(src + 16);
*(int*)(dest + 20) = *(int*)(src + 20);
*(int*)(dest + 24) = *(int*)(src + 24);
*(int*)(dest + 28) = *(int*)(src + 28); // [0,32]
#endif
if (len <= 48) goto MCPY01;
#if HAS_CUSTOM_BLOCKS
*(Block16*)(dest + 32) = *(Block16*)(src + 32); // [0,48]
#elif BIT64
*(long*)(dest + 32) = *(long*)(src + 32);
*(long*)(dest + 40) = *(long*)(src + 40); // [0,48]
#else
*(int*)(dest + 32) = *(int*)(src + 32);
*(int*)(dest + 36) = *(int*)(src + 36);
*(int*)(dest + 40) = *(int*)(src + 40);
*(int*)(dest + 44) = *(int*)(src + 44); // [0,48]
#endif
MCPY01:
// Unconditionally copy the last 16 bytes using destEnd and srcEnd and return.
Contract.Assert(len > 16 && len <= 64);
#if HAS_CUSTOM_BLOCKS
*(Block16*)(destEnd - 16) = *(Block16*)(srcEnd - 16);
#elif BIT64
*(long*)(destEnd - 16) = *(long*)(srcEnd - 16);
*(long*)(destEnd - 8) = *(long*)(srcEnd - 8);
#else
*(int*)(destEnd - 16) = *(int*)(srcEnd - 16);
*(int*)(destEnd - 12) = *(int*)(srcEnd - 12);
*(int*)(destEnd - 8) = *(int*)(srcEnd - 8);
*(int*)(destEnd - 4) = *(int*)(srcEnd - 4);
#endif
return;
MCPY02:
// Copy the first 8 bytes and then unconditionally copy the last 8 bytes and return.
if ((len & 24) == 0) goto MCPY03;
Contract.Assert(len >= 8 && len <= 16);
#if BIT64
*(long*)dest = *(long*)src;
*(long*)(destEnd - 8) = *(long*)(srcEnd - 8);
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
*(int*)(destEnd - 8) = *(int*)(srcEnd - 8);
*(int*)(destEnd - 4) = *(int*)(srcEnd - 4);
#endif
return;
MCPY03:
// Copy the first 4 bytes and then unconditionally copy the last 4 bytes and return.
if ((len & 4) == 0) goto MCPY04;
Contract.Assert(len >= 4 && len < 8);
*(int*)dest = *(int*)src;
*(int*)(destEnd - 4) = *(int*)(srcEnd - 4);
return;
MCPY04:
// Copy the first byte. For pending bytes, do an unconditionally copy of the last 2 bytes and return.
Contract.Assert(len < 4);
if (len == 0) return;
*dest = *src;
if ((len & 2) == 0) return;
*(short*)(destEnd - 2) = *(short*)(srcEnd - 2);
return;
MCPY05:
// PInvoke to the native version when the copy length exceeds the threshold.
if (len > CopyThreshold)
{
goto PInvoke;
}
// Copy 64-bytes at a time until the remainder is less than 64.
// If remainder is greater than 16 bytes, then jump to MCPY00. Otherwise, unconditionally copy the last 16 bytes and return.
Contract.Assert(len > 64 && len <= CopyThreshold);
nuint n = len >> 6;
MCPY06:
#if HAS_CUSTOM_BLOCKS
*(Block64*)dest = *(Block64*)src;
#elif BIT64
*(long*)dest = *(long*)src;
*(long*)(dest + 8) = *(long*)(src + 8);
*(long*)(dest + 16) = *(long*)(src + 16);
*(long*)(dest + 24) = *(long*)(src + 24);
*(long*)(dest + 32) = *(long*)(src + 32);
*(long*)(dest + 40) = *(long*)(src + 40);
*(long*)(dest + 48) = *(long*)(src + 48);
*(long*)(dest + 56) = *(long*)(src + 56);
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
*(int*)(dest + 8) = *(int*)(src + 8);
*(int*)(dest + 12) = *(int*)(src + 12);
*(int*)(dest + 16) = *(int*)(src + 16);
*(int*)(dest + 20) = *(int*)(src + 20);
*(int*)(dest + 24) = *(int*)(src + 24);
*(int*)(dest + 28) = *(int*)(src + 28);
*(int*)(dest + 32) = *(int*)(src + 32);
*(int*)(dest + 36) = *(int*)(src + 36);
*(int*)(dest + 40) = *(int*)(src + 40);
*(int*)(dest + 44) = *(int*)(src + 44);
*(int*)(dest + 48) = *(int*)(src + 48);
*(int*)(dest + 52) = *(int*)(src + 52);
*(int*)(dest + 56) = *(int*)(src + 56);
*(int*)(dest + 60) = *(int*)(src + 60);
#endif
dest += 64;
src += 64;
n--;
if (n != 0) goto MCPY06;
len %= 64;
if (len > 16) goto MCPY00;
#if HAS_CUSTOM_BLOCKS
*(Block16*)(destEnd - 16) = *(Block16*)(srcEnd - 16);
#elif BIT64
*(long*)(destEnd - 16) = *(long*)(srcEnd - 16);
*(long*)(destEnd - 8) = *(long*)(srcEnd - 8);
#else
*(int*)(destEnd - 16) = *(int*)(srcEnd - 16);
*(int*)(destEnd - 12) = *(int*)(srcEnd - 12);
*(int*)(destEnd - 8) = *(int*)(srcEnd - 8);
*(int*)(destEnd - 4) = *(int*)(srcEnd - 4);
#endif
return;
PInvoke:
_Memmove(dest, src, len);
}
I have an array of audio data, which is a lot of Int32 numbers represented by array of bytes (each 4 byte element represents an Int32) and i want to do some manipulation on the data (for example, add 10 to each Int32).
I converted the bytes to Int32, do the manipulation and convert it back to bytes as in this example:
//byte[] buffer;
for (int i=0; i<buffer.Length; i+=4)
{
Int32 temp0 = BitConverter.ToInt32(buffer, i);
temp0 += 10;
byte[] temp1 = BitConverter.GetBytes(temp0);
for (int j=0;j<4;j++)
{
buffer[i + j] = temp1[j];
}
}
But I would like to know if there is a better way to do such manipulation.
You can check the .NET Reference Source for pointers (grin) on how to convert from/to big endian.
class intFromBigEndianByteArray {
public byte[] b;
public int this[int i] {
get {
i <<= 2; // i *= 4; // optional
return (int)b[i] << 24 | (int)b[i + 1] << 16 | (int)b[i + 2] << 8 | b[i + 3];
}
set {
i <<= 2; // i *= 4; // optional
b[i ] = (byte)(value >> 24);
b[i + 1] = (byte)(value >> 16);
b[i + 2] = (byte)(value >> 8);
b[i + 3] = (byte)value;
}
}
}
and sample use:
byte[] buffer = { 127, 255, 255, 255, 255, 255, 255, 255 };//big endian { int.MaxValue, -1 }
//bool check = BitConverter.IsLittleEndian; // true
//int test = BitConverter.ToInt32(buffer, 0); // -129 (incorrect because little endian)
var fakeIntBuffer = new intFromBigEndianByteArray() { b = buffer };
fakeIntBuffer[0] += 2; // { 128, 0, 0, 1 } = big endian int.MinValue - 1
fakeIntBuffer[1] += 2; // { 0, 0, 0, 1 } = big endian 1
Debug.Print(string.Join(", ", buffer)); // "128, 0, 0, 0, 1, 0, 0, 1"
For better performance you can look into parallel processing and SIMD instructions - Using SSE in C#
For even better performance, you can look into Utilizing the GPU with c#
How about the following approach:
struct My
{
public int Int;
}
var bytes = Enumerable.Range(0, 20).Select(n => (byte)(n + 240)).ToArray();
foreach (var b in bytes) Console.Write("{0,-4}", b);
// Pin the managed memory
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
for (int i = 0; i < bytes.Length; i += 4)
{
// Copy the data
My my = (My)Marshal.PtrToStructure<My>(handle.AddrOfPinnedObject() + i);
my.Int += 10;
// Copy back
Marshal.StructureToPtr(my, handle.AddrOfPinnedObject() + i, true);
}
// Unpin
handle.Free();
foreach (var b in bytes) Console.Write("{0,-4}", b);
I made it just for fun.
Not sure that's less ugly.
I don't know, will it be faster? Test it.
I'm trying converse PHP and Javascript page to C# with password hashing system (password hashing with chap token). So I have example page to show steps result:
<?php
$chapid='\115';
$chapchallenge= '\274\013\242\243\236\226\151\224\070\023\243\207\252\061\016\254';
$pass = '123456';
?>
<script type="text/javascript">
<!--
alert('<?php echo $chapid; ?>' + '<?php echo $pass; ?>' + '<?php echo $chapchallenge; ?>');
alert(((str2binl('<?php echo $chapid; ?>' + '<?php echo $pass; ?>' + '<?php echo $chapchallenge; ?>'))));
alert((coreMD5(str2binl('<?php echo $chapid; ?>' + '<?php echo $pass; ?>' + '<?php echo $chapchallenge; ?>'))));
alert(binl2hex(coreMD5(str2binl('<?php echo $chapid; ?>' + '<?php echo $pass; ?>' + '<?php echo $chapchallenge; ?>'))));
//-->
</script>
/*
* Convert an 8-bit character string to a sequence of 16-word blocks, stored
* as an array, and append appropriate padding for MD4/5 calculation.
* If any of the characters are >255, the high byte is silently ignored.
*/
function str2binl(str)
{
var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks
var blks = new Array(nblk * 16)
for(var i = 0; i < nblk * 16; i++) blks[i] = 0
for(var i = 0; i < str.length; i++)
blks[i>>2] |= (str.charCodeAt(i) & 0xFF) << ((i%4) * 8)
blks[i>>2] |= 0x80 << ((i%4) * 8)
blks[nblk*16-2] = str.length * 8
return blks
}
First alert displays string "M123456¼¢£i8£ª1¬", so in my code I converted input using:
public static string AsciiOctalToString(string ascii)
{
var list = ascii.Split('\\');
StringBuilder builder = new StringBuilder();
foreach (string octalPart in list.Where(x => x.Length > 0))
{
int i = Convert.ToInt32(octalPart, 8);
builder.Append(Convert.ToChar(i));
}
return builder.ToString();
}
Next I have to convert this string to bytes (like str2binl(str)) but it is in some strange format. I don't understand how to 'Convert an 8-bit character string to a sequence of 16-word blocks'. Expected result (from alert 2) is {858927437, -1137298124, -1633443317, 949250454, -1433951469, -2136207823, 0, 0,0,0,0,0,0,0,184,0}. I translated str2binl(str) to:
public static int[] Str2Binl(string str)
{
var nblk = ((str.Length + 8) >> 6) + 1; // number of 16-word blocks
var blks = new int[nblk*16];
for (var i = 0; i < str.Length; i++)
{
blks[i >> 2] |= (str[i] & 0xFF) << (i%4*8);
blks[i >> 2] |= 0x80 << (i%4*8);
}
blks[nblk*16 - 2] = str.Length*8;
return blks;
}
but my result is different than expected.
Do you know what I'm doing wrong with this?
I added brackets for JavaScript code:
function str2binl(str)
{
var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks
var blks = new Array(nblk * 16)
for(var i = 0; i < nblk * 16; i++)
{
blks[i] = 0
}
for(var i = 0; i < str.length; i++)
{
blks[i>>2] |= (str.charCodeAt(i) & 0xFF) << ((i%4) * 8)
}
blks[i>>2] |= 0x80 << ((i%4) * 8)
blks[nblk*16-2] = str.length * 8
return blks
}
but line blks[i>>2] |= 0x80 << ((i%4) * 8) needs iterator too so how it's work in JS?
P.S. I can't use this JS library in my code, I need only hashed password (it's not a web app).
It seems the issue is that you placed two lines inside the for loop instead of only one. Does this work?
public static int[] Str2Binl(string str)
{
var nblk = ((str.Length + 8) >> 6) + 1; // number of 16-word blocks
var blks = new int[nblk*16];
int i;
for (i = 0; i < str.Length; i++)
{
blks[i >> 2] |= (str[i] & 0xFF) << (i%4*8);
}
blks[i >> 2] |= 0x80 << (i%4*8);
blks[nblk*16 - 2] = str.Length*8;
return blks;
}
Anyway, as I already commented, If you are really concerned about security, you shouldn't do your own hashing, nor even use MD5 or SHA, but one derived from PBKDF2. Unless if for some reason you need to keep your current algorithm.
On the other hand, your AsciiOctalToString gives me a different string: ¼♂¢£??i?8‼£?ª1♫¬.
BTW, you can avoid using that where with this (although you may like it less):
var list = ascii.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
I'm trying to load some decimal values from a file but I can't work out the correct way to take the raw values and convert them into decimals.
I've read the file out into a byte array, and each chunk of four bytes is supposed to represent one decimal value. To help figure it out, I've constructed a table of how the decimal values 1 through to 46 are represented as four byte chunks.
For instance, the number 1 appears as 0,0,128,63 the number 2 as 0,0,0,64 and so on up to 46, which is 0,0,56,66. The full table is available here.
There is also another series of numbers which go to three decimal places and include negatives, which is here.
The only documentation I have states
They are stored least significant byte first: 1's, 256's, 65536's, 16777216's. This makes the hex sequence 01 01 00 00 into the number 257 (decimal). In C/C++, to read e.g. a float, do: float x; fread(&x, sizeof(float), 1, fileptr);
However I'm using .NET's File.ReadAllBytes method so this isn't much help. If anyone can spare a few minutes to look at the examples files and see if they can spot a way to convert the values to decimals I'd be most grateful.
You can use BitConverter.ToSingle to read a float value from a byte array, so to get a sequence of floats, you could do something like this:
byte[] data = File.ReadAllBytes(fileName);
int count = data.Length / 4;
Debug.Assert(data.Length % 4 == 0);
IEnumerable<float> values = Enumerable.Range(0, count)
.Select(i => BitConverter.ToSingle(data, i*4));
Have you looked into using the BitConverter class? It converts between byte arrays and various types.
Edit:
MSDN has a helpful comment on the documentation for BitConverter at http://msdn.microsoft.com/en-us/library/system.bitconverter_methods(v=vs.85).aspx:
public static decimal ToDecimal(byte[] bytes)
{
int[] bits = new int[4];
bits[0] = ((bytes[0] | (bytes[1] << 8)) | (bytes[2] << 0x10)) | (bytes[3] << 0x18); //lo
bits[1] = ((bytes[4] | (bytes[5] << 8)) | (bytes[6] << 0x10)) | (bytes[7] << 0x18); //mid
bits[2] = ((bytes[8] | (bytes[9] << 8)) | (bytes[10] << 0x10)) | (bytes[11] << 0x18); //hi
bits[3] = ((bytes[12] | (bytes[13] << 8)) | (bytes[14] << 0x10)) | (bytes[15] << 0x18); //flags
return new decimal(bits);
}
public static byte[] GetBytes(decimal d)
{
byte[] bytes = new byte[16];
int[] bits = decimal.GetBits(d);
int lo = bits[0];
int mid = bits[1];
int hi = bits[2];
int flags = bits[3];
bytes[0] = (byte)lo;
bytes[1] = (byte)(lo >> 8);
bytes[2] = (byte)(lo >> 0x10);
bytes[3] = (byte)(lo >> 0x18);
bytes[4] = (byte)mid;
bytes[5] = (byte)(mid >> 8);
bytes[6] = (byte)(mid >> 0x10);
bytes[7] = (byte)(mid >> 0x18);
bytes[8] = (byte)hi;
bytes[9] = (byte)(hi >> 8);
bytes[10] = (byte)(hi >> 0x10);
bytes[11] = (byte)(hi >> 0x18);
bytes[12] = (byte)flags;
bytes[13] = (byte)(flags >> 8);
bytes[14] = (byte)(flags >> 0x10);
bytes[15] = (byte)(flags >> 0x18);
return bytes;
}
The .NET library implemented Decimal.GetBytes() method internally.
I've used the decompiled .NET library to create a simple conversion methods between decimal and byte arrary - you can find it here:
https://gist.github.com/eranbetzalel/5384006#file-decimalbytesconvertor-cs
EDIT : Here is the full source code from my link.
public decimal BytesToDecimal(byte[] buffer, int offset = 0)
{
var decimalBits = new int[4];
decimalBits[0] = buffer[offset + 0] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24);
decimalBits[1] = buffer[offset + 4] | (buffer[offset + 5] << 8) | (buffer[offset + 6] << 16) | (buffer[offset + 7] << 24);
decimalBits[2] = buffer[offset + 8] | (buffer[offset + 9] << 8) | (buffer[offset + 10] << 16) | (buffer[offset + 11] << 24);
decimalBits[3] = buffer[offset + 12] | (buffer[offset + 13] << 8) | (buffer[offset + 14] << 16) | (buffer[offset + 15] << 24);
return new Decimal(decimalBits);
}
public byte[] DecimalToBytes(decimal number)
{
var decimalBuffer = new byte[16];
var decimalBits = Decimal.GetBits(number);
var lo = decimalBits.Value[0];
var mid = decimalBits.Value[1];
var hi = decimalBits.Value[2];
var flags = decimalBits.Value[3];
decimalBuffer[0] = (byte)lo;
decimalBuffer[1] = (byte)(lo >> 8);
decimalBuffer[2] = (byte)(lo >> 16);
decimalBuffer[3] = (byte)(lo >> 24);
decimalBuffer[4] = (byte)mid;
decimalBuffer[5] = (byte)(mid >> 8);
decimalBuffer[6] = (byte)(mid >> 16);
decimalBuffer[7] = (byte)(mid >> 24);
decimalBuffer[8] = (byte)hi;
decimalBuffer[9] = (byte)(hi >> 8);
decimalBuffer[10] = (byte)(hi >> 16);
decimalBuffer[11] = (byte)(hi >> 24);
decimalBuffer[12] = (byte)flags;
decimalBuffer[13] = (byte)(flags >> 8);
decimalBuffer[14] = (byte)(flags >> 16);
decimalBuffer[15] = (byte)(flags >> 24);
return decimalBuffer;
}
As others have mentioned, use the BitConverter class, see the example below:
byte[] bytez = new byte[] { 0x00, 0x00, 0x80, 0x3F };
float flt = BitConverter.ToSingle(bytez, 0); // 1.0
bytez = new byte[] { 0x00, 0x00, 0x00, 0x40 };
flt = BitConverter.ToSingle(bytez, 0); // 2.0
bytez = new byte[] { 0, 0, 192, 190 };
flt = BitConverter.ToSingle(bytez, 0); // -0.375