I have this function in VB.net and I am trying to convert this code from VB to C#.
Function HashEncode(strSecret)
' Function takes an ASCII string less than 2^61 characters long and
' one way hash encrypts it using 160 bit encryption into a 40 digit hex value.
' The encoded hex value cannot be decoded to the original string value.
'
' This is the only function that you need to call for encryption.
'
' Written By: Mark G. Jager
' Written Date: 8/10/2000
'
' Free to distribute as long as code is not modified, and header is kept intact
'
' The author makes no warranties as to the validity, and/or authenticity of this code.
' You may use any code found herein at your own risk.
' This code was written to follow as closely as possible the standards found in
' Federal Information Processing Standards Publication (FIPS PUB 180-1)
' http://csrc.nist.gov/fips/fip180-1.txt -- Secure Hash Standard SHA-1
'
' This code is for private use only, and the security and/or encryption of the resulting
' hexadecimal value is not warrented or gaurenteed in any way.
'
Dim strEncode, strH(4)
Dim intPos
If len(strSecret) = 0 or len(strSecret) >= 2^61 then
HashEncode = "0000000000000000000000000000000000000000"
exit function
end if
'Initial Hex words are used for encoding Digest.
'These can be any valid 8-digit hex value (0 to F)
strH(0) = "FB0C14C2"
strH(1) = "9F00AB2E"
strH(2) = "991FFA67"
strH(3) = "76FA2C3F"
strH(4) = "ADE426FA"
For intPos = 1 to len(strSecret) step 56
strEncode = Mid(strSecret, intPos, 56) 'get 56 character chunks
strEncode = WordToBinary(strEncode) 'convert to binary
strEncode = PadBinary(strEncode) 'make it 512 bites
strEncode = BlockToHex(strEncode) 'convert to hex value
'Encode the hex value using the previous runs digest
'If it is the first run then use the initial values above
strEncode = DigestHex(strEncode, strH(0), strH(1), strH(2), strH(3), strH(4))
'Combine the old digest with the new digest
strH(0) = HexAdd(left(strEncode, 8), strH(0))
strH(1) = HexAdd(mid(strEncode, 9, 8), strH(1))
strH(2) = HexAdd(mid(strEncode, 17, 8), strH(2))
strH(3) = HexAdd(mid(strEncode, 25, 8), strH(3))
strH(4) = HexAdd(right(strEncode, 8), strH(4))
Next
'This is the final Hex Digest
HashEncode = strH(0) & strH(1) & strH(2) & strH(3) & strH(4)
End Function
I have converted it in C# as
public string HashEncode(string strSecret)
{
string strEncode;
string[] strH = new string [4];
int intPos;
if (strSecret.Length == 0 || strSecret.Length >= Int64.MaxValue)
{
return "0000000000000000000000000000000000000000";
//break;
}
//Initial Hex words are used for encoding Digest.
//These can be any valid 8-digit hex value (0 to F)
strH[0] = "FB0C14C2";
strH[1] = "9F00AB2E";
strH[2] = "991FFA67";
strH[3] = "76FA2C3F";
strH[4] = "ADE426FA";
for(intPos = 1; intPos < strSecret.Length; intPos += 56)
{
strEncode = strSecret.Substring(intPos, strSecret.IndexOf(" ", 56));
//strEncode = Mid(strSecret, intPos, 56); //get 56 character chunks
strEncode = WordToBinary(strEncode); //convert to binary
strEncode = PadBinary(strEncode); //make it 512 bites
strEncode = BlockToHex(strEncode); //convert to hex value
//Encode the hex value using the previous runs digest
//If it is the first run then use the initial values above
strEncode = DigestHex(strEncode, strH[0], strH[1], strH[2], strH[3], strH[4]);
//Combine the old digest with the new digest
//strH[0] = HexAdd(left(strEncode, 8), strH[0]);
//strH[1] = HexAdd(mid(strEncode, 9, 8), strH[1]);
//strH[2] = HexAdd(mid(strEncode, 17, 8), strH[2]);
//strH[3] = HexAdd(mid(strEncode, 25, 8), strH[3]);
//strH[4] = HexAdd(right(strEncode, 8), strH[4]);
strH[0] = HexAdd(strEncode.Substring(0, 8), strH[0]);
strH[1] = HexAdd(strEncode.Substring(9, 8), strH[1]);
strH[2] = HexAdd(strEncode.Substring(17, 8), strH[2]);
strH[3] = HexAdd(strEncode.Substring(25, 8), strH[3]);
strH[4] = HexAdd(strEncode.Substring(strEncode.Length - 8,8),strH[4]);
}
//This is the final Hex Digest
return strH[0] + strH[1] + strH[2] + strH[3] + strH[4];
}
It successfully compiled but not working.
It gives exception at for loop as 'System.IndexOutOfRangeException was unhandled by user'
Is anyone help me to solve this problem
The code is an implementation of the SHA-1 algorithm, correct? In that case:
using System.Security.Cryptography;
using System.Text;
string str = "foobar";
byte[] data = Encoding.ASCII.GetBytes(str);
SHA1 sha = new SHA1Managed();
byte[] hash = sha.ComputeHash(data);
Console.WriteLine(String.Concat(Array.ConvertAll(hash, x => x.ToString("X2"))));
Translation complete.
Your 'for' loop is wrong for a couple of reasons:
1. the ending condition is incorrect - strSecret.Length has to be included if you start your indexing at 1.
2. when converting the legacy VB string functions, you have to be aware that they use 1-based indexing, while the .NET methods use 0-based indexing.
for (int intPos = 1; intPos <= strSecret.Length; intPos += 56)
{
strEncode = strSecret.ToString().Substring(intPos - 1, 56); //get 56 character chunks
strEncode = WordToBinary(strEncode); //convert to binary
strEncode = PadBinary(strEncode); //make it 512 bites
strEncode = BlockToHex(strEncode); //convert to hex value
//Encode the hex value using the previous runs digest
//If it is the first run then use the initial values above
strEncode = DigestHex(strEncode, strH[0], strH[1], strH[2], strH[3], strH[4]);
//Combine the old digest with the new digest
strH[0] = HexAdd(strEncode.Substring(0, 8), strH[0]);
strH[1] = HexAdd(strEncode.Substring(8, 8), strH[1]);
strH[2] = HexAdd(strEncode.Substring(16, 8), strH[2]);
strH[3] = HexAdd(strEncode.Substring(24, 8), strH[3]);
strH[4] = HexAdd(strEncode.Substring(strEncode.Length - 8), strH[4]);
}
You also could use:
for (int intPos = 0; intPos < strSecret.Length; intPos += 56)
{
strEncode = strSecret.ToString().Substring(intPos, 56); //get 56 character chunks
... (rest is identical)
}
Related
So someone took int value, converted it to string then converted it to ASCII values and then finally to byte[] with inconsistent length 1 - 4 bytes.
e.g. 100 -> "100" -> { 49, 48, 48 }.
Now I need that int value and I did it like this:
{ 49, 48, 48 } -> '1' + '0' + '0' -> "100" -> 100
switch (header[25].Count)
{
case 1:
hex = "" + (char)header[25][0];
amountOfData = Convert.ToInt32(hex, 16);
break;
case 2:
hex = "" + (char)header[25][0] + (char)header[25][1];
amountOfData = Convert.ToInt32(hex, 16);
break;
case 3:
hex = "" + (char)header[25][0] + (char)header[25][1] + (char)header[25][2];
amountOfData = Convert.ToInt32(hex, 16);
break;
case 4:
hex = "" + (char)header[25][0] + (char)header[25][1] + (char)header[25][2] + (char)header[25][3];
amountOfData = Convert.ToInt32(hex, 16); ;
break;
default:
break;
}
but maybe there is better solution...
EDIT: sorry for not mentioning that, but header is List<List<byte>>
You can use the Encoding/GetString method to convert bytes of different encodings (e.g. ASCII in your case) to a .NET string:
var input = new byte[] { 49, 48, 48 };
var str = Encoding.ASCII.GetString(input);
var result = int.Parse(str, NumberStyles.None, CultureInfo.InvariantCulture);
You can use library functions to parse from byte-like data to primitives; you're talking about ASCII, which means that Utf8Parser will work fine for us (all ASCII is also valid UTF8, although the reverse is obviously not true); normally, we would expect that header[25] is a byte[], a segment there-of, or some other raw binary source, but: ultimately, something like:
var span = new ReadOnlySpan<byte>(header[25], 0, header[25].Count);
if (!Utf8Parser.TryParse(span, out int amountOfData, out _))
ThrowSomeError(); // not an integer
If header[25] is something less convenient (like a List<byte> - I notice that in your example, your header[25] has a .Count not a .Length, which suggests it isn't a byte[]), then you can always either stackalloc a local buffer and copy the data out, or you can peek inside the list with CollectionMarshal.AsSpan<T>(List<T>), which returns a Span<T> from the underlying data:
var span = CollectionMarshal.AsSpan(header[25]);
if (!Utf8Parser.TryParse(span, out int amountOfData, out _))
ThrowSomeError(); // not an integer
As a runnable example that just shows the API:
using System;
using System.Buffers.Text;
Span<byte> span = stackalloc byte[] { 49, 48, 48 };
if (!Utf8Parser.TryParse(span, out int amountOfData, out _))
throw new FormatException();
Console.WriteLine(amountOfData); // 100
I have an array of integer 1s and 0s (possibly need to get converted to byte type?). I have used an online ASCII to binary generator to get the equivalent binary of this 6 digit letter sequence:
abcdef should equal 011000010110001001100011011001000110010101100110 in binary. So in c#, my array is [0,1,1,0,0,0,0...], built by:
int[] innerArr = new int[48];
for (int i = 0; i < 48); i++) {
int innerIsWhite = color.val[0] > 200 ? 0 : 1;
innerArr[i] = innerIsWhite;
}
I want to take this array, and convert it into abcdef (and be able to do the opposite).
How do I do this? Is there a better way to be storing these ones and zeros.
Try using Linq and Convert:
source = "abcdef";
// 011000010110001001100011011001000110010101100110
string encoded = string.Concat(source
.Select(c => Convert.ToString(c, 2).PadLeft(8, '0')));
// If we want an array
byte[] encodedArray = encoded
.Select(c => (byte) (c - '0'))
.ToArray();
// string from array
string encodedFromArray = string.Concat(encodedArray);
// abcdef
string decoded = string.Concat(Enumerable
.Range(0, encoded.Length / 8)
.Select(i => (char) Convert.ToByte(encoded.Substring(i * 8, 8), 2)));
If your input is a bit string, then you can use a method like below to convert that into character string
public static string GetStringFromAsciiBitString(string bitString) {
var asciiiByteData = new byte[bitString.Length / 8];
for (int i = 0, j = 0; i < asciiiByteData.Length; ++i, j+= 8)
asciiiByteData[i] = Convert.ToByte(bitString.Substring(j, 8), 2);
return Encoding.ASCII.GetString(asciiiByteData);
}
The above code simply uses the Convert.ToByte method asking it to do a base-2 string to byte conversion. Then using Encoding.ASCII.GetString, you get the string representation from the byte array
In my code, I presume your bit string is clean (multiple of 8 and with only 0s and 1s), in production grade code you will have to sanitize your input.
I have a byte array:
newMsg.DATA = new byte[64];
How can I convert it into binary value and then write it in text file with comma separation. Comma should be in between binary values not bytes.....
like 1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0.......
Here is an example that uses LINQ:
byte[] arr = new byte[] { 11, 55, 255, 188, 99, 22, 31, 43, 25, 122 };
string[] result = arr.Select(x => string.Join(",", Convert.ToString(x, 2)
.PadLeft(8, '0').ToCharArray())).ToArray();
System.IO.File.WriteAllLines(#"D:\myFile.txt", result);
Every number in byte[] arr is converted to a binary number with Convert.ToString(x, 2) and the comma "," is added between binary values with string.Join(",",...). At the end you can write all the elements in result to a text file by using System.IO.File.WriteAllLines.
The example above gives you this kind of output in a txt file:
0,0,0,0,1,0,1,1
0,0,1,1,0,1,1,1
1,1,1,1,1,1,1,1
...
Explanation of Convert.ToString(value, baseValue):
The first parameter value represents the number you want to convert to a string
and the second parameter baseValue represents which type of conversion you want to perform.
Posible baseValues are : 2,8,10 and 16.
BaseValue = 2 - represents a conversion to a binary number representation.
BaseValue = 8 - represents a conversion to a octal number representation.
BaseValue = 10 - represents a conversion to a decimal number representation.
BaseValue = 16 - represents a conversion to a hexadecimal number representation.
I think this will Help you c# provides inbuilt functionality to do so
with help of Convert.ToString(byte[],base); here base could be[2(binary),8(octal),16(HexaDecimal)]
byte[] data = new byte[64];
// 2nd parameter 2 is Base e.g.(binary)
string a = Convert.ToString(data[data.Length], 2);
StringBuilder sb = new StringBuilder();
foreach(char ch in a.ToCharArray())
{
sb.Append(ch+",");
}
// This is to remove last extra ,
string ans = sb.ToString().Remove(sb.Length - 1, 1);
This should get you going:
var bytes = new byte[] { 128, 255, 2 };
var stringBuilder = new StringBuilder();
for (var index = 0; index < bytes.Length; index++)
{
var binary = Convert.ToString(bytes[index], 2).PadLeft(8, '0');
var str = string.Join(",", binary.ToCharArray());
stringBuilder.Append(str);
if (index != bytes.Length -1) stringBuilder.Append(",");
}
Console.WriteLine(stringBuilder);
I am trying to rewrite part of code from C# to Python.
But faced some problems with bitwise operation.
Here is C# code :
private string _generateConfirmationHashForTime(long time, string tag)
{
time = 1459152870;
byte[] decode = Convert.FromBase64String("TphBbTrbbVGJuXQ15OVZVZeBB9M=");
int n2 = 8;
if (tag != null)
{
if (tag.Length > 32)
{
n2 = 8 + 32;
}
else
{
n2 = 8 + tag.Length;
}
}
byte[] array = new byte[n2];
int n3 = 8;
while (true)
{
int n4 = n3 - 1;
if (n3 <= 0)
{
break;
}
array[n4] = (byte)time;
time >>= 8;
n3 = n4;
}
if (tag != null)
{
Array.Copy(Encoding.UTF8.GetBytes(tag), 0, array, 8, n2 - 8);
}
try
{
HMACSHA1 hmacGenerator = new HMACSHA1();
hmacGenerator.Key = decode;
byte[] hashedData = hmacGenerator.ComputeHash(array);
string encodedData = Convert.ToBase64String(hashedData, Base64FormattingOptions.None);
Console.WriteLine(encodedData)
return encodedData
}
catch (Exception)
{
return null; //Fix soon: catch-all is BAD!
}
}
I rewrote it to Python:
def _generateConfirmationHashForTime(self, time, tag):
time = 1459152870
decode = base64.b64decode("TphBbTrbbVGJuXQ15OVZVZeBB9M=")
n2 = 8
if tag is not None:
if len(tag) > 32:
n2 = 8 + 32
else:
n2 = 8 + len(tag)
arrayb = [hex(time >> i & 0xff) for i in (56, 48, 40, 32, 24, 16, 8, 0)]
if tag is not None:
for ch in range(0, len(tag)):
arrayb.append(hex(ord(tag[ch])))
arrayc = 0
n4 = len(arrayb) - 1
for i in range(0, len(arrayb)):
arrayc <<= 8
arrayc |= int(arrayb[n4], 16)
n4 -= 1
array_binary = binascii.a2b_hex("{:016x}".format(arrayc))
hmacGenerator = hmac.new(decode, array_binary, hashlib.sha1)
hashedData = hmacGenerator.digest()
encodedData = base64.b64encode(hashedData)
print encodedData
The result of hashing is not equal.
Variables encodedData do not match :(
Can you point where can be error in the code?
OK, now I remember why I don't use Python. Language snarks aside though...
The C# code composes an array of bytes, 8 from the time variable (in big-endian form, MSB first) and up to 32 from the UTF8 encoding of the tag string... but limited by the length of the original string, ignoring multi-byte encoding. Not exactly ideal, but we can handle that.
The bytes from the time variable are simple enough:
arr = struct.pack(">Q", time)
For the tag string convert it to UTF8, then slice the first 32 bytes off and append it to the array:
arr += str(tag).encode("utf-8")[0:min(32, len(str(tag)))]
Up to here we're fine. I compared the base64 encoding of arr against the composed message in C# and they match for my test data, as does the resultant HMAC message digest.
Here's the full code:
def _generateConfirmationHashForTime(time, tag):
time = 1459152870
decode = base64.b64decode("TphBbTrbbVGJuXQ15OVZVZeBB9M=")
arr = struct.pack(">Q", time)
arr += str(tag).encode("utf-8")[0:min(32, len(str(tag)))]
hmacGenerator = hmac.new(decode, arr, hashlib.sha1)
hashedData = hmacGenerator.digest()
encodedData = base64.b64encode(hashedData)
return encodedData
i have exception when i run this code ,, what is wrong
var encoder = new System.Text.UTF8Encoding();
System.Text.Decoder utf8Decode = encoder.GetDecoder();
byte[] todecodeByte = Convert.FromBase64String(encodedMsg);
int charCount = utf8Decode.GetCharCount(todecodeByte, 0, todecodeByte.Length);
var decodedChar = new char[charCount];
utf8Decode.GetChars(todecodeByte, 0, todecodeByte.Length, decodedChar, 0);
var message = new String(decodedChar);
exception occurs in this line
byte[] todecodeByte = Convert.FromBase64String(encodedMsg);
Base64 encoding encodes 6 bits per character. So the length of the string, multiplied by 6, must be divisible by 8. If it is not then it doesn't have enough bits to fill every byte and you'll get this exception.
So good odds that encodedMsg just isn't a properly encoded base64 string. You can append some = characters to bypass the exception and see if anything recognizable pops out. The = character is the padding character for base64:
while ((encodedMsg.Length * 6) % 8 != 0) encodedMsg += "=";
// etc...