Encode / Decode RealVNC password - c#

I'm trying to write C# application that can remotely change the RealVNC password on another box.
What works currently is that I can pull a password from a box that has already been changed, store it as a hex string, and then send it to another box AND then change the password that way but I need to be able to change the password or randomize it on the fly.
I'm having problems with creating the correct binary to place in the registry.
I know the VNC key:
byte[] Key = { 23, 82, 107, 6, 35, 78, 88, 7 };
So using the above key and passing "1234" as the password to encrypt using the following code:
public static byte[] EncryptTextToMemory(string Data, byte[] Key)
{
try
{
MemoryStream mStream = new MemoryStream()
DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider();
desProvider.Mode = CipherMode.ECB;
desProvider.Key = Key;
CryptoStream cStream = new CryptoStream(mStream,
desProvider.CreateEncryptor(),
CryptoStreamMode.Write);
byte[] toEncrypt = new ASCIIEncoding().GetBytes(Data);
cStream.Write(toEncrypt, 0, toEncrypt.Length);
cStream.FlushFinalBlock();
byte[] ret = mStream.ToArray();
cStream.Close();
mStream.Close();
return ret;
}
catch (CryptographicException ex)
{
MessageBox.Show("A Cryptographic error occurred: " + ex.Message);
return null;
}
After passing the returned byte array to BitConverter.ToString, I would expect to get the same hex values as stored in the registry of a password already set to 1234 with RealVNC itself, but I'm not.

Here are my sources to encrypt/decrypt VNC password:
public static string EncryptVNC(string password)
{
if (password.Length > 8)
{
password = password.Substring(0, 8);
}
if (password.Length < 8)
{
password = password.PadRight(8, '\0');
}
byte[] key = { 23, 82, 107, 6, 35, 78, 88, 7 };
byte[] passArr = new ASCIIEncoding().GetBytes(password);
byte[] response = new byte[passArr.Length];
char[] chars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
// reverse the byte order
byte[] newkey = new byte[8];
for (int i = 0; i < 8; i++)
{
// revert desKey[i]:
newkey[i] = (byte)(
((key[i] & 0x01) << 7) |
((key[i] & 0x02) << 5) |
((key[i] & 0x04) << 3) |
((key[i] & 0x08) << 1) |
((key[i] & 0x10) >> 1) |
((key[i] & 0x20) >> 3) |
((key[i] & 0x40) >> 5) |
((key[i] & 0x80) >> 7)
);
}
key = newkey;
// reverse the byte order
DES des = new DESCryptoServiceProvider();
des.Padding = PaddingMode.None;
des.Mode = CipherMode.ECB;
ICryptoTransform enc = des.CreateEncryptor(key, null);
enc.TransformBlock(passArr, 0, passArr.Length, response, 0);
string hexString = String.Empty;
for (int i = 0; i < response.Length; i++)
{
hexString += chars[response[i] >> 4];
hexString += chars[response[i] & 0xf];
}
return hexString.Trim().ToLower();
}
And to decrypt:
public static string DecryptVNC(string password)
{
if (password.Length < 16)
{
return string.Empty;
}
byte[] key = { 23, 82, 107, 6, 35, 78, 88, 7 };
byte[] passArr = ToByteArray(password);
byte[] response = new byte[passArr.Length];
// reverse the byte order
byte[] newkey = new byte[8];
for (int i = 0; i < 8; i++)
{
// revert key[i]:
newkey[i] = (byte)(
((key[i] & 0x01) << 7) |
((key[i] & 0x02) << 5) |
((key[i] & 0x04) << 3) |
((key[i] & 0x08) << 1) |
((key[i] & 0x10) >> 1) |
((key[i] & 0x20) >> 3) |
((key[i] & 0x40) >> 5) |
((key[i] & 0x80) >> 7)
);
}
key = newkey;
// reverse the byte order
DES des = new DESCryptoServiceProvider();
des.Padding = PaddingMode.None;
des.Mode = CipherMode.ECB;
ICryptoTransform dec = des.CreateDecryptor(key, null);
dec.TransformBlock(passArr, 0, passArr.Length, response, 0);
return System.Text.ASCIIEncoding.ASCII.GetString(response);
}
Also this function is needed:
public static byte[] ToByteArray(String HexString)
{
int NumberChars = HexString.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16);
}
return bytes;
}
At top add:
using System.Security.Cryptography;
Can't remember where I got the code from. I am not the original author.

Related

C# encrypt code and c++ encrypt code is not matching

I'm implementing encrypt/decrypt code with c++/c#
I referred to this post and referred to answers.z`
But c++/c# encrypted code was not matched.
Here are my codes.
C++
// base64 encode part
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(BYTE c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
std::string ret;
int i = 0;
int j = 0;
BYTE char_array_3[3];
BYTE char_array_4[4];
while (bufLen--) {
char_array_3[i++] = *(buf++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
//start encrypt
std::string key = "01286567891233460123456789a12345";
std::string iv = "0123456789123456";
std::string encrypt(const std::string& str_in)
{
std::string str_out;
std::string str_out2;
byte* keybyte = (byte*)key.c_str();
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
stfEncryptor.MessageEnd();
str_out2 = base64_encode(reinterpret_cast<const unsigned char*>(str_out.c_str()), strlen(str_out.c_str()));
return str_out2;
}
std::string decrypt(const std::string& cipher_text)
{
std::string str_out;
//need to insert code of decrypt base64
CryptoPP::AES::Decryption aesDecryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, (byte*)iv.c_str());
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(str_out));
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipher_text.c_str()), cipher_text.size());
stfDecryptor.MessageEnd();
return str_out;
}
c#
public string Encrypt(string testCode)
{
string clearText = testCode;
byte[] clearBytes = Encoding.Default.GetBytes(clearText);
using (Aes encryptor = Aes.Create("AES"))
{
//encryptor.BlockSize = 128;
encryptor.Padding = PaddingMode.Zeros;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CBC;
encryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789a12345");
encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
clearText = Convert.ToBase64String(bt); //clearText = Encoding.Default.GetString(bt);
}
}
return clearText; //Return the encrypted command
}
public string Decrypt(string cipherText)
{
byte[] clearBytes = Convert.FromBase64String(cipherText);
using (Aes decryptor = Aes.Create("AES"))
{
// decryptor.BlockSize = 128;
decryptor.Padding = PaddingMode.Zeros;
decryptor.KeySize = 128;
decryptor.Mode = CipherMode.CBC;
decryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789a12345");
decryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
cipherText = Encoding.Default.GetString(bt);
}
}
return cipherText; //Return the decrypted text
}
c++ result
encrypted code : ks8zzu20w6zURkuZMgbx8g==
decrypted code : test
c# result
encrypted code : nsWRYBylyjVaJ5Yckk+SRw==
decrypted code : test
I tested with test word both of C++/C# however encrypted code was not matched.
Also, I tested after remove base64 encode code but pure encrypted code was not matched as well.
Could anyone please share your knowledge?
EDIT1
I tried to copy encrypted code by c++ and pasted to c# decrypt code like below
string testcode = "ks8zzu20w6zURkuZMgbx8g=="
Decrypt(testcode)
//result - test↗↗↗↗↗
As you can see, the results look very similar, but there is something weird.
↗ This symbol is added after the word test.
I could not found out why result like this. Is there something I missed?
Solved
std::string encrypt(const std::string& str_in)
{
std::string str_out;
std::string str_out2;
byte* keybyte = (byte*)key.c_str();
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
// 'str_in.length() + 1' in the line below makes the encryption code different from c# code.
/*stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);*/
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length());
stfEncryptor.MessageEnd();
str_out2 = cryptobase64_encode(str_out);
return str_out2;
}
As I commented, str_in.length() + 1 makes the encrypted code different from C# code.
And I changed C# padding options from Zeros to PKCS7 for matching c++ encrypted code.
But I don't know why I need to set this option. I think I need to study this.
Anyway, It works well. Special thanks to #jdweng.

How to send message to WebSocket in VB.NET?

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.)

Reversing galois multiplication of two byte arrays in C#

I need help in finding the reverse of galois multiplication GF (2^128) in C#. The code below is being used in my AES-GCM functions. I found this code through the web though.
I tried to search the web for galois division but I have no luck in finding it.
Pardon me for my knowledge in this field and my English.
This function derives the value of 2^x.
public byte BIT(byte x)
{
return (byte)(1 << x);
}
This function converts byte array of 4 elements to unsigned int.
public uint WPA_GET_BE32(byte[] a)
{
return (uint)((a[0] << 24 )|( a[1] <<16 )|( a[2] << 8 )| a[3]);
}
This function converts unsigned int into byte array of 4 elements.
public void WPA_PUT_BE32(out byte[] a, uint val)
{
a = new byte[4];
a[0] = (byte)((val >> 24) & 0xff);
a[1] = (byte)((val >> 16) & 0xff);
a[2] = (byte)((val >> 8) & 0xff);
a[3] = (byte)(val & 0xff);
}
public void shift_right_block(ref byte[] v)
{
uint val;
byte[] temp = new byte[4];
temp = v.Skip(12).Take(4).ToArray();
val = WPA_GET_BE32(temp);
val >>= 1;
if ((v[11] & 0x01) > 0) val |= 0x80000000;
WPA_PUT_BE32(out temp, val);
Array.Copy(temp, 0, v, 12, 4);
temp = v.Skip(8).Take(4).ToArray();
val = WPA_GET_BE32(temp);
val >>= 1;
if ((v[7] & 0x01) > 0) val |= 0x80000000;
WPA_PUT_BE32(out temp, val);
Array.Copy(temp, 0, v, 8, 4);
temp = v.Skip(4).Take(4).ToArray();
val = WPA_GET_BE32(temp);
val >>= 1;
if ((v[3] & 0x01) > 0) val |= 0x80000000;
WPA_PUT_BE32(out temp, val);
Array.Copy(temp, 0, v, 4, 4);
temp = v.Skip(0).Take(4).ToArray();
val = WPA_GET_BE32(temp);
val >>= 1;
WPA_PUT_BE32(out temp, val);
Array.Copy(temp, 0, v, 0, 4);
}
This function does a exclusive-OR function on two byte arrays.
public void c_xor_16(ref byte[] dest, byte[] src)
{
int ndx = 0;
for (ndx = 0; ndx < 16; ndx++) dest[ndx] ^= src[ndx];
}
This is the main function and byte array z is the output of the GF multiplication.
public void c_gf_mult(byte[] x, byte[] y, ref byte[] z)
{
int i, j;
byte[] v = new byte[16];
z = new byte[16];
Array.Clear(z, 0, 16);
Array.Copy(y, v, 16);
for (i = 0; i < 16; i++)
{
for (j = 0; j < 8; j++)
{
if ((byte)(x[i] & BIT((byte)(7 - j))) > 0)
{
c_xor_16(ref z, v);
}
if ((byte)(v[15] & 0x01) > 0)
{
shift_right_block(ref v);
v[0] ^= 0xe1;
}
else
{
shift_right_block(ref v);
}
}
}
return;
}

Blowfish Invalid Length Exception

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);
}
}

How do I convert byte values into decimals?

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

Categories

Resources