C# Byte[] to long reverse not working - c#

Why is this program not working? I convert a byte array to long. Then from the long I convert back to a byte array. The resulting byte array is not the same as original.
class Program
{
static void Main(string[] args)
{
byte[] myBytes = { 0, 0, 0, 32, 56, 99, 87, 34, 56, 56, 34, 33, 67
, 56, 66, 72, 1, 0, 0, 56, 0, 22};
long data = BitConverter.ToInt64(myBytes, 0);
byte[] byteData = BitConverter.GetBytes(data);
Console.WriteLine("byte array: " + BitConverter.ToString(myBytes));
Console.WriteLine("byte array: " + BitConverter.ToString(byteData));
}
}

Since l4V already gave the right assumption, I just want to add it as an aswer but I think my answer doesn't deserve any votes since all upvotes should go to l4V. Upvote his comment.
From BitConverter.ToInt64
The ToInt64 method converts the bytes from index startIndex to
startIndex + 7 to a Int64 value.
So basicly, this conversations takes only 8 bytes (0, 0, 0, 32, 56, 99, 87, 34) of your byte array. Other bytes of your array are ignored at this situation.

The length of bytes exceed a long can hold(8 bytes, 64 bits).
For alternative solution, I'd suggest to use BigInteger if your target framework is higher than(including) .Net 4.0.

Related

How can I decrypt a file in C# which has been encrypted by des.exe?

I have a file which has been encrypted by des.exe.
A file can be encrypted and decrypted using the following commands:
des -E -k "foo" sample.txt sample.txt.enc
des -D -k "foo" sample.txt.enc sample.txt.dec
I have attempted to decrypt using the following:
public byte[] Decrypt(FileInfo file, string key)
{
byte[] keyAsBytes = LibDesPasswordConvertor.PasswordToKey(key);
byte[] initializationVector = keyAsBytes;
var cryptoProvider = new DESCryptoServiceProvider();
cryptoProvider.Mode = CipherMode.CBC;
cryptoProvider.Padding = PaddingMode.None;
using (FileStream fs = file.OpenRead())
using (var memStream = new MemoryStream())
using (var decryptor = cryptoProvider.CreateDecryptor(keyAsBytes, initializationVector))
using (var cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Write))
{
fs.CopyTo(cryptoStream);
fs.Flush();
cryptoStream.FlushFinalBlock();
return memStream.ToArray();
}
}
public static class LibDesPasswordConvertor
{
public static byte[] PasswordToKey(string password)
{
if (string.IsNullOrWhiteSpace(password))
{
throw new ArgumentException("password");
}
var key = new byte[8];
for (int i = 0; i < password.Length; i++)
{
var c = (int)password[i];
if ((i % 16) < 8)
{
key[i % 8] ^= (byte)(c << 1);
}
else
{
// reverse bits e.g. 11010010 -> 01001011
c = (((c << 4) & 0xf0) | ((c >> 4) & 0x0f));
c = (((c << 2) & 0xcc) | ((c >> 2) & 0x33));
c = (((c << 1) & 0xaa) | ((c >> 1) & 0x55));
key[7 - (i % 8)] ^= (byte)c;
}
}
AddOddParity(key);
var target = new byte[8];
var passwordBuffer = Encoding.ASCII.GetBytes(password).Concat(new byte[8]).Take(password.Length + (8 - (password.Length % 8)) % 8).ToArray();
using(var des = DES.Create())
using(var encryptor = des.CreateEncryptor(key, key))
{
for (int x = 0; x < passwordBuffer.Length / 8; ++x)
{
encryptor.TransformBlock(passwordBuffer, 8 * x, 8, target, 0);
}
}
AddOddParity(target);
return target;
}
private static void AddOddParity(byte[] buffer)
{
for (int i = 0; i < buffer.Length; ++i)
{
buffer[i] = _oddParityTable[buffer[i]];
}
}
private static byte[] _oddParityTable = {
1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
}
But when I execute:
const string KEY = "foo";
var utf8Bytes = Decrypt(new FileInfo(#"PATH-TO\sample.txt.enc"), KEY);
I get:
�1D���z+�a Sample.y���0F�01
Original text:
This is a Sample.
Encrypted:
ñGYjl¦ûg†¼64©‹Bø
é¯Kœ|
To my surprise you've already derived the key correctly. That was the meat of the problem, so Kudos for solving that part already. That the key is correct becomes clear when you see that part of the plaintext is present in the decryption - it wouldn't if the key was wrong.
Looking into the source and some docs from times past, I found a likely IV of all zeros instead of reusing the key bytes (both are very wrong, in cryptographic terms).
Furthermore, as always for SSLeay, the ECB and CBC modes use PKCS#7 compatible padding, rather than no padding.
Finally, FlushFinalBlock will be automatically called if you close the stream, e.g. by exiting the try-with-resources. So if you get the array afterwards then you should get the right values - after you unpad correctly, of course. If you call Flush then FlushFinalBlock will already be called, and calling it twice will make a mess out of things.
Simply removing the flush calls and retrieving the array after the CryptoStream is closed is the way to go.
Both DES and the key derivation (des_string_to_key and des_string_to_2keys) that Young copied from MIT are completely insecure. Using an all zero IV is wrong.
If you use this as transport mode than padding oracles will apply, and decryption is not even necessary for an attacker. The ciphertext is not integrity protected.
If you use the above routines to keep anything confidential or secure you're fooling yourself. This is 80s technology, and I think that real cryptographers wouldn't find it secure back then either.
Basically if your attacker is over 8 years old, you're in trouble.

How to unescape an UTF-8 escaped byte array to an unescaped byte array without allocating a String

I have a Span<byte> representing an escaped string UTF-8 like:
Binary represention:
byte[20] { 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 32, 92, 117, 50, 48, 97, 99, 32, 33 }
Escaped represention:"Hello world \u20ac !"
Desired binary result:
byte[17] { 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 32, 226, 130, 172, 32, 33 }
I tried to transcode the escaped \u20ac by using the GetString() method:
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString())
But this is not unescaping the input.
Is there any way to achieve to the same result ?
// Not working solution
public void NotWorkingUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
var tmp = Encoding.UTF8.GetString(source);
Encoding.UTF8.GetBytes(tmp, destination);
}
// Unknown solution
// UTF-8 escaped byte array -> UTF8-8 unescaped byte array
public void FastUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
// ?
}
Are you looking for a method that does all the work?
You could simply use this:
public void FastUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(source), destination);
}
Or prevent any exception:
public void FastUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
if (source.Length <= destination.Length)
{
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(source), destination);
}
}
Update:
There is another way to do the conversion without using Encoding.UTF8, by seeing the #JonSkeet response you could implement the following:
public static void AnotherMethod(ReadOnlySpan<byte> source, Span<byte> destination)
{
for (int i = 0; i < source.Length; i++)
{
destination[i] = (byte) (Convert.ToChar(source[i]));
}
}
The problem with this code is that when using Convert.toChar, the conversion is done to an equivalent Unicode character no UTF-8 character, which is why & 0x7f is used in the post of the answer to obtain values in the ASCII range.
I did not do many tests in terms of performance or functionality with other special characters that you want to escape, however I have achieved the same results

Marshalling variable size packet

This question is somewhat extension of a question asked previously c# using marshalling for packet parsing by me.
I have to parse a variable size packet although header size is fixed but data packets inside it can be of different size and may be of more than 1 type are present in same packet.
For example the packet has following fields in its header :
1) username(12 bytes)
2 password(12 bytes)
3) id_number(4 bytes)
4) may be 1 or combination of other data packets of variable size(size can be 12, 16 or 512 bytes)
5) crc(2 bytes)
Now data packets can be following
a) data packet type 1
1) size(2 bytes)
2) name(12 bytes)
3) id_number(2 bytes)
b) data packet type 2
1) size(2 bytes)
2) data(24 bytes)
3) id_number(1 byte).
So there can be either type1 or type2. It is also possible for both type to be present. My question is how can I use marshalling to parse these packets or anyone can suggest some other way.
One more thing I want to add is that 1st and 3rd field of data packets will always be the data packet size(2 bytes) and data packet id number(1 byte) respectively. The 2nd field of data packets can be anything and of variable size(2, 3, 13, 18, 515).
As an alternative, you may use LINQ (assuming that ASCII encoding is being used):
var packet = new byte[]{
97, 108, 101, 120, 0, 0, 0, 0, 0, 0, 0, 0, // username
112, 97, 115, 115, 119, 111, 114, 100, 0, 0, 0, 0, //password
49, 50, 51, 0, // id_number
0, 53, 0, 0, 1, // 1st data packet
0, 54, 1, 2, 5, 2, // 2nd data packet
49, 0 // crc
};
var username = Encoding.ASCII.GetString(packet.Take(12).ToArray());
var password = Encoding.ASCII.GetString(packet.Skip(12).Take(12).ToArray());
var idNumber = Encoding.ASCII.GetString(packet.Skip(24).Take(4).ToArray());
var data = packet.Skip(28).Take(packet.Length - 30).ToArray();
var crc = Encoding.ASCII.GetString(packet.Skip(packet.Length - 2).ToArray());
var nextDataPackedPos = 0;
var nextDataPackedPos = 0;
var dataPackets = data
.TakeWhile(b => nextDataPackedPos < data.Length)
.Zip(data.Skip(nextDataPackedPos), (a, b) =>
{
var size = Int32.Parse(
Encoding.ASCII
.GetString(data.Skip(nextDataPackedPos).Take(2).ToArray())
.Trim('\0')
);
var result = data.Skip(nextDataPackedPos).Take(size).ToArray();
nextDataPackedPos += size;
return result;
}).ToList();
The code first separates the data section from the packet bytes. Then it reads the size of each packet and based on it, it creates an equaly sized array containing the bytes of the data packet. It hen advances to the beginning of the next packet until the end of the array is reached.

How to compare OracleTimeStamps

I have two byte[] (like this { 0, 0, 0, 0, 52, 246, 141, 6 }) that represent two Oracle's timestamps.
How do I know which one is older?
Convert the binary timestamp to Int64 and then compare the corresponding long values:
var value = new byte[] { 0, 0, 0, 0, 52, 246, 141, 6 };
long timestamp = BitConverter.ToInt64(value, 0);
The bigger the long value, the more recent the timestamp. I haven't used Oracle but I would guess this represents the number of ticks since the Epoch.

'Bad Data' When decrypting messages using DES3

C# 2008
I am using the following code to encrypt and encrypt a message. However, when I attempt to decrypt I get a 'Bad Data' error.
Is there anything wrong with my code below?
Many thanks,
public string encryptText(string text)
{
try
{
TripleDESCryptoServiceProvider encrypt = new TripleDESCryptoServiceProvider();
encrypt.Key = new byte[] { 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 144, 89, 55, 34, 21, 13, 8, 5, 3, 2, 1, 0 };
encrypt.IV = new byte[] { 1, 2, 3, 5, 8, 13, 21, 34 };
byte[] byteText = Encoding.Unicode.GetBytes(text);
ICryptoTransform encryptor = encrypt.CreateEncryptor();
byte[] encryptedText = encryptor.TransformFinalBlock(byteText, 0, byteText.Length);
return Encoding.Unicode.GetString(encryptedText);
}
catch (Exception ex)
{
Console.Write(ex.Message);
return ex.Message;
}
}
/// Decrypt the text
public string decryptText(string encryptedText)
{
try
{
byte[] bytesText = Encoding.Unicode.GetBytes(encryptedText);
TripleDESCryptoServiceProvider decrypt = new TripleDESCryptoServiceProvider();
decrypt.Key = new byte[] { 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 144, 89, 55, 34, 21, 13, 8, 5, 3, 2, 1, 0 };
decrypt.IV = new byte[] { 1, 2, 3, 5, 8, 13, 21, 34 };
ICryptoTransform decryptor = decrypt.CreateDecryptor();
byte[] originalText = decryptor.TransformFinalBlock(bytesText, 0, encryptedText.Length);
return Encoding.Unicode.GetString(originalText);
}
catch (Exception ex)
{
Console.Write(ex.Message);
return ex.Message;
}
}
You're taking the encrypted bytes and converting them to a string using Encoding.Unicode, but then you're taking the string and converting it back to bytes using Encoding.Default. That's pretty much guaranteed not to work (unless the default happens to be UTF-16).
However, you should use either of these - converting arbitrary binary data to text using an encoding is a bad idea. Use Convert.ToBase64String (in the encryptor) and Convert.FromBase64String (in the decryptor) instead.
(I'd also very much query the wisdom of returning an exception message as if it were the successful result of encrypting/decrypting, but hopefully you only did that for the sake of the sample code.)
Yup, there are a few mistakes in the code.
encryptedText and bytesText must be the same byte array. As Jon Skeet suggest you could use Base64 encoding.
The IV is part of the ciphertext. Hence you don't have to set the IV when you decrypt.
The default mode of encryption is CBC. This mode requires that IV is random (rsp. unpredictable). Hence you must not set a fixed IV, when you encrypt. When you create the CryptoServiceProvider a random IV is already set. Hence overwritting the IV with a fixed value decreases your security.
Putting a key explicitly in the code isn't a great idea. I hope you'll change this once your code leaves the experimental state.
Is there a reason to use TripleDes? Otherwise you might want to consider using AES instead.

Categories

Resources