Background: I'm trying to convert Mike Shaffer's VB RC4 encryption to C# (https://web.archive.org/web/20210927195845/https://www.4guysfromrolla.com/articles/091802-1.3.aspx). See a previous question of mine at Converting Mike Shaffer's RC4Encryption to C#.
It seems my encryption is not working.
Using the demo page at: https://web.archive.org/web/20000303125329/http://www.4guysfromrolla.com:80/demos/rc4test.asp, with password of "abc":
Plain text: og;|Q{Fe should result in
A2 FA E2 55 09 A4 AB 16
However, my code is generating the 5th char as 9, instead of 09:
A2 FA E2 55 9 A4 AB 16
Another example - Plain text: cl**z!Ss should result in
AE F1 F3 03 22 FE BE 00
However, my code is generating:
AE F1 F3 3 22 FE BE 0
It seems it's only a problem with certain non-alphanumeric characters.
Here's my code:
private static string EnDeCrypt(string text)
{
int i = 0;
int j = 0;
string cipher = "";
// Call our method to initialize the arrays used here.
RC4Initialize(password);
// Set up a for loop. Again, we use the Length property
// of our String instead of the Len() function
for (int a = 1; a <= text.Length; a++)
{
// Initialize an integer variable we will use in this loop
int itmp = 0;
// Like the RC4Initialize method, we need to use the %
// in place of Mod
i = (i + 1) % 256;
j = (j + sbox[i]) % 256;
itmp = sbox[i];
sbox[i] = sbox[j];
sbox[j] = itmp;
int k = sbox[(sbox[i] + sbox[j]) % 256];
// Again, since the return type of String.Substring is a
// string, we need to convert it to a char using
// String.ToCharArray() and specifying that we want the
// first value, [0].
char ctmp = text.Substring(a - 1, 1).ToCharArray()
[0];
itmp = ctmp; //there's an implicit conversion for char to int
int cipherby = itmp ^ k;
cipher += (char)cipherby; //just cast cipherby to a char
}
// Return the value of cipher as the return value of our
// method
return cipher;
}
public static string ConvertAsciiToHex(string input)
{
return string.Join(string.Empty, input.Select(c => Convert.ToInt32(c).ToString("X")).ToArray());
}
public static string Encrypt(string text)
{
return ConvertAsciiToHex(EnDeCrypt(text));
}
Here's how I get my encrypted result:
var encryptedResult = RC4Encrypt.Encrypt(valuetoencrypt);
The output is correct (leading zeros don't change the value), your code is simply not padding values that fit into a single hex digit (such as 9 or 3 or 0). Use .ToString("X2") instead of .ToString("X").
Related
As the title says, I've been working on MiFare Classic reading a card.
I'm using the MiFare v1.1.3 Library from NuGet
and it returns a byte array, which I parse to readable Hex strings, by looping thru it.
Here's the code snippet:
int sector = 1;
int block = 0;
int size = 16;
var data = await localCard.GetData(sector, block, size);
string hexString = "";
for (int i = 0; i < data.Length; i++)
{
hexString += data[i].ToString("X2") + " ";
}
// hexString returns 84 3D 17 B0 1E 08 04 00 02 63 B5 F6 B9 BE 77 1D
Now, how can I parse it properly?
I've tried parsing it into ASCII, ANSI, Int, Int64, Base64, Long
and all of them didn't match the 'data' that it's suppose to contain
EDIT:
The expected output: 1206058
HEX String returned: 84 3D 17 B0 1E 08 04 00 02 63 B5 F6 B9 BE 77 1D
I've checked the source code
it looks like both Task<byte[]> GetData Task SetData methods do not have any special logic to transform the data. Data are just saved (and read) as byte[]
I suppose that you have to contact author/company that has wrote data you are trying to read.
The expected output: 1206058
Looks strange since you are reading 16 bytes size = 16 and expecting 7 characters to be read.
Is it possible that block or sector values are incorrect ?
I have written a simple program to solve your problem. Perhaps this is what you want to achieve:
// The original byte data array; some random data
byte[] data = { 0, 1, 2, 3, 4, 85, 128, 255 };
// Byte data -> Hex string
StringBuilder hexString = new StringBuilder();
foreach (byte item in data)
{
hexString.Append($"{item.ToString("X2")} ");
}
Console.WriteLine(hexString.ToString().Trim());
// Hex string -> List of bytes
string[] hexArray = hexString.ToString().Trim().Split(' ');
List<byte> dataList = new List<byte>();
foreach (string item in hexArray)
{
dataList.Add(byte.Parse(item, System.Globalization.NumberStyles.HexNumber));
}
dataList.ForEach(b => Console.Write($"{b} "));
Console.WriteLine();
If it is not the right solution please provide us more info about your problem.
If var data potentially is string - you can reverse it from hex by:
// To Hex
byte[] plainBytes = Encoding.ASCII.GetBytes("MiFare v1.1.3");
string hexString = "";
for (int i = 0; i < plainBytes.Length; i++)
hexString += plainBytes[i].ToString("X2") + " ";
Console.WriteLine(hexString); // Result: "4D 69 46 61 72 65 20 76 31 2E 31 2E 33"
// From Hex
hexString = hexString.Replace(" ", ""); // Remove whitespaces to have "4D69466172652076312E312E33"
byte[] hexBytes = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length / 2; i++)
hexBytes[i] = Convert.ToByte(hexString.Substring(2 * i, 2), 16);
string plainString = Encoding.ASCII.GetString(hexBytes);
Console.WriteLine(plainString); // Result: "MiFare v1.1.3"
Just, probably, should be needed to define correct Encoding.
I'm creating my own DNS server and host blocker, I want to get host from DNS request message byte[]
dns message hex dump:
e07901000001000000000000057961686f6f03636f6d0000010001
.y...........yahoo.com.....
code:
using System;
using System.Text;
public class Program
{
public static void Main()
{
string b64 = "4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB";
int pad = b64.Length % 4;
if (pad > 0 )
{
b64 += new string('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while(decoded[end] != 0){
end++;
}
int hostLength = end-start;
byte[] byteHost = new byte[hostLength];
Array.Copy(decoded, start, byteHost, 0, hostLength);
string host = Encoding.Default.GetString(byteHost);
Console.WriteLine(host); // yahoo♥com
}
}
The questions:
is my method above to get host name right/efficient/fastest ?
why I get weird character replacing the dot yahoo♥com ?
change to Encoding.ASCII or Encoding.UTF8 has no effect
There's no need for the second array; Encoding.GetString allows you to pass in an offset and count, so: GetString(decoded, start, hostLength)
Never use Encoding.Default; that is badly named - it should be called Encoding.Wrong :) Find out what encoding the data is in (probably UTF-8 or ASCII), and use that
You should be able to use IndexOf to find the terminating '\0'; also consider what your code should do if it doesn't find one
As for the unusual character: the data contains an 03 byte where you would expect the .; check the DNS protocol specification to see if this is expected. 03 is ETX (end of text). Beyond that: I don't know.
Found the answer, 03 is not ETX but length of the next string, let see the the example
00 05 79 61 68 6F 6F 03 63 6F 6D
. . y a h o o . c o m
05 mean is the length of yahoo and 03 is for com
Valid host or domain name contains only ASCII range from 44-127 or [a-z0-9-\.], domain like bücher.nu will be converted into xn--bcher-kva.nu, so I replace byte like 03,0C,09 or under 44 with the dot .
and thanks to #Marc Gravell for GetString(decoded, start, hostLength)
/*
I0sBAAABAAAAAAAABmMtcmluZwZtc2VkZ2UDbmV0AAABAAE
ldgBAAABAAAAAAAABWZwLXZwCWF6dXJlZWRnZQNuZXQAAAEAAQ
4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB
*/
string b64 = "4VoBAAABAAAAAAAAIGYyNWIzNjgyMGUyNDljNGQxY2I0YzQzNGUxNjc5YTljA2Nsbwxmb290cHJpbnRkbnMDY29tAAABAAE";
int pad = b64.Length % 4;
if (pad > 0)
{
b64 += new string ('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);
Console.WriteLine(host);
edit: micro optimization, benchmark with 1e9 or 1 billion loop
Convert.ToChar() finished in 00:00:04
for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
host += Convert.ToChar(decoded[end]);
end++;
}
}
VS Encoding.ASCII.GetString() finished in 00:03:20 (200 seconds)
for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);
I have this code:
string result = "";
foreach(char item in texte)
{
result += Convert.ToString(item, 2).PadLeft(8, '0');
}
So I have string named result which is conversion of a word like 'bonjour' in binary.
for texte = "bonjour" I have string result = 01100010011011110110111001101010011011110111010101110010 as type integer.
And when I do
Console.writeLine(result[0])
I obtain 0, normal, what I expected, but if I do
Console.WriteLine((int)result[0])
or
Console.WriteLine(Convert.ToInt32(result[0]))
I obtain 48!
I don't want 48, I want 0 or 1 at the type integer.
Could you help me please?
You can just subtract 48 from it!
Console.WriteLine(result[0] - 48);
because the characters digits 0-9 are encoded as 48 to 57.
If you want to access each bit by index, I suggest using a BitArray instead:
var bytes = Encoding.ASCII.GetBytes("someString");
var bitArray = new BitArray(bytes);
// now you can access the first bit like so:
bitArray.Get(0) // this returns a bool
bitArray.Get(0) ? 1 : 0 // this gives you a 1 or 0
string a = "23jlfdsa890123kl21";
byte[] data = System.Text.Encoding.Default.GetBytes(a);
StringBuilder result = new StringBuilder(data.Length * 8);
foreach (byte b in data)
{
result.Append(Convert.ToString(b, 2).PadLeft(8, '0'));
}
you can try this code.
Just Do this
Console.WriteLine(Convert.ToInt32(Convert.ToString(result[0])));
You're expecting it to behave the same as Convert.ToInt32(string input) but actually you're invoking Convert.ToInt32(char input) and if you check the docs, they explicitly state it will return the unicode value (in this case the same as the ASCII value).
http://msdn.microsoft.com/en-us/library/ww9t2871(v=vs.110).aspx
I have code in C# that converts an UInt64 to a float, the entered value is for example '4537294320117481472'. The code that does the work is in the first block, the second block shows the relevant functions, and the answers are at the bottom.
byte[] rawParameterData = new byte[8];
Console.Write("Enter Value: ");
string rawDataString = Console.ReadLine();
UInt64 rawParameterInteger = UInt64.Parse(rawDataString);
rawParameterData = ConvertFromUInt64(rawParameterInteger);
float convertedParameterData = ConvertToFloat(rawParameterData, 0);
rawParameterData now equals a byte array of [62,247,181,37,0,0,0,0]
convertedParameterData now equals 0.4838039
public static byte[] ConvertFromUInt64(UInt64 data)
{
var databuf = BitConverter.GetBytes(data);
return SwapBytes(databuf, 8); // DIS is big-endian; need to convert to little-endian: least significant byte is at lower byte location.
}
static float ConvertToFloat(byte[] data, int offset)
{
var databuf = CopyData(data, offset, 4);
return BitConverter.ToSingle(databuf, 0);
}
static byte[] SwapBytes(byte[] srcbuf, int datalength)
{
var destbuf = new byte[srcbuf.Length];
for (var i = 0; i < datalength; i++)
destbuf[datalength - 1 - i] = srcbuf[i];
return destbuf;
}
It seems that the code is relying on the BitConverter.ToSingle(databuf, 0) function that is part of C#.
Can this be done in Python? Thanks.
In python, this is as simple as
import struct
a = 4537294320117481472
b = struct.pack('Q', a)
f = struct.unpack('ff', b)
print(f) # (0.0, 0.4838038980960846)
https://docs.python.org/3/library/struct.html
import struct
import math
# We only care about the first 4 of eight of the digits so we
# need to shift by the character size * number of characters
# then we will just have databuf in our significantBits variable
# So we are converting from: 3E F7 B5 25 0 0 0 0 to 3E F7 B5 25
characterWidth = 8
significantBits = 4537294320117481472 >> (characterWidth * 4)
# We can use this python function convert from bits to a float
# Taken from https://stackoverflow.com/a/14431225/825093
def bitsToFloat(b):
s = struct.pack('>l', b)
return struct.unpack('>f', s)[0]
float = bitsToFloat(significantBits)
print(float) # 0.483803898096
I'm trying to generate a fixed length hash using the code below.
public int GetStableHash(string s)
{
string strKey = "myHashingKey";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(strKey);
byte[] contentBuffer = UE.GetBytes(s);
// Initialize the keyed hash object.
HMACSHA256 myhmacsha256 = new HMACSHA256(key);
byte[] hashValue = myhmacsha256.ComputeHash(contentBuffer);
return BitConverter.ToInt32(hashValue,0);
}
It gives me output like this.
-1635597425
I need a positive number fixed length (8 digits). Can someone plz tell me how to do that.
Thanks in advance.
You're trying to get a 8-digit number from a hash function output which can have up to
lg(2^256) ~ 78
decimal digits.
You should either consider changing hash function or substitute up to 26 bits (2^26 = 67108864, 2^27 = 134217728 - 9 digits already) rounded down to 3 bytes (24 bits) from output and get Int32 from those 3 bytes.
public int GetStableHash(string s)
{
...
byte[] hashValue = myhmacsha256.ComputeHash(contentBuffer);
byte[] hashPart = new byte[3];
hashValue.CopyTo(hashPart, 29); // 32-3
return System.BitConverter.ToInt32(hashPart, 0);
}
unchecked
{
int num = BitConverter.ToInt32(hashValue,0);
if (num < 0)
{
num = -num;
}
num %= 100000000;
}
I'm using the unchecked because otherwise -int.MinValue would break (but note that normally programs are compiled with the unchecked "flag" "on")
The code means:
unchecked
don't do overflow controls
if (num < 0)
{
num = -num;
}
make the number positive if negative
num %= 100000000;
take the remainder (that has 0-8 digits)
much shorter:
return unchecked((int)((uint)BitConverter.ToInt32(hashValue,0) % 100000000));