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
Related
I'm packing some binary data as a short, but want to have 4x values of 0-F.. And would like to do this without having a bunch of switch() cases reading the string.split of a hex
Someone have a clever, elegant solution for this or should I just long-hand it?
eg; 1C4A = (1, 12, 4, 10)
Shift in and out
var a = 1;
var b = 12;
var c = 4;
var d = 10;
// in
var packed = (short) ((a << 12) | (b << 8) | (c << 4) | d);
// out
a = (packed >> 12) & 0xf;
b = (packed >> 8) & 0xf;
c = (packed >> 4) & 0xf;
d = packed & 0xF;
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
Output
1
12
4
10
You can shift by 4 (or divide and multiply by 16) to move numbers into different place values. Then mask and shift your packed number to get your original numbers back.
Eg if you want to store 1 and 2 you could do:
int packed = (1 << 4) + 2;
int v1 = (packed & 0xF0) >> 4;
int v2 = packed & 0x0F;
Console.WriteLine($"{v1}, {v2}");
>>> 1, 2
I read 3 bytes in a binary file which I need to convert into an integer.
I use this code to read the bytes :
LastNum last1Hz = new LastNum();
last1Hz.Freq = 1;
Byte[] LastNumBytes1Hz = new Byte[3];
Array.Copy(lap_info, (8 + (32 * k)), LastNumBytes1Hz, 0, 3);
last1Hz.NumData = LastNumBytes1Hz[2] << 16 + LastNumBytes1Hz[1] << 8 + LastNumBytes1Hz[0];
last1Hz.NumData is an integer.
This seems to be the good way to convert bytes into integers in the posts i have seen.
Here is a capture of the values read:
But the integer last1Hz.NumData is always 0.
I'm missing something but can't figure out what.
You need to use brackets (because addition has a higher priority than bit shifting):
int a = 0x87;
int b = 0x00;
int c = 0x00;
int x = c << 16 + b << 8 + a; // result 0
int z = (c << 16) + (b << 8) + a; // result 135
Your code should look like this:
last1Hz.NumData = (LastNumBytes1Hz[2] << 16) + (LastNumBytes1Hz[1] << 8) + LastNumBytes1Hz[0];
I think the problem is an order of precedence issue. + is evaluated before <<
Put brackets in to force the bit shift to be evaluated first.
last1Hz.NumData = (LastNumBytes1Hz[2] << 16) + (LastNumBytes1Hz[1] << 8) + LastNumBytes1Hz[0];
If I want to convert 4 bytes into an int, I can do this:
byte[] b = BitConverter.GetBytes(i1);
int i2 = BitConverter.ToInt32(b,0);
int i3 = b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24);
and then i1,i2,i3 will all equal.
but how do I do the same for a uint? This:
uint u1 = uint.MaxValue-1000;
byte[] b = BitConverter.GetBytes(u1);
uint u2 = BitConverter.ToUInt32(b,0);
uint u3 = (uint)(b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24));
results in a overlflow for large uints.
It would only throw that exception if in a checked context. See: http://msdn.microsoft.com/en-us/library/y3d0kef1(v=vs.80).aspx.
No exception:
uint u1 = uint.MaxValue - 1000;
byte[] b = BitConverter.GetBytes(u1);
uint u2 = BitConverter.ToUInt32(b, 0);
uint u3 = (uint) (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24));
exception:
checked
{
uint u1 = uint.MaxValue - 1000;
byte[] b = BitConverter.GetBytes(u1);
uint u2 = BitConverter.ToUInt32(b, 0);
uint u3 = (uint) (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24));
}
no exception
checked
{
unchecked
{
uint u1 = uint.MaxValue - 1000;
byte[] b = BitConverter.GetBytes(u1);
uint u2 = BitConverter.ToUInt32(b, 0);
uint u3 = (uint) (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24));
Console.WriteLine(u1 + " " + u2 + " " + u3);
}
}
Make sure you're not compiling with the /checked option.
The exception is thrown by casting from int to uint. Using the shift operator on the bytes (the line with uint u3 = ...) implicitly cast them to int. A uint with the MSB on ("1") is a negative int which is out of range for uint. Using int causes no such exception because there is no explicit cast which might elicit an overflow exception.
I ran your code with uint values up to 4,294,967,295, which is the max and it works fine in all cases.
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);
}
}
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.