0

I have to port some code from VB.net to C#. Now I'm quite embarassed, but I can't figuere out, how to translate the following code:

From VB

Dim Hash() As Byte
Hash = Encoding.UTF8.GetBytes("StackOverflow".GetHashCode)

To C# (not working):

byte[] Hash;
Hash = Encoding.UTF8.GetBytes("StackOverflow".GetHashCode());

What is the correct syntax?

Mister 832
  • 1,177
  • 1
  • 15
  • 34
  • 3
    The VB code is broken. `GetBytes` expects a *string* while GetHashCode returns an `int`. You already have two bytes, you don't need to "convert" them to anything. BTW why UTF8 when .NET uses Unicode? Does the VB.NET code even run? – Panagiotis Kanavos Dec 29 '16 at 10:09
  • The VB.Net code ran for over 6 now;) Wondered myself what was going on there... – Mister 832 Dec 29 '16 at 10:11
  • I don't think that VB code is doing what you think it is doing. `UTF8.GetBytes()` will return a byte array representation of the provided string in a UTF8 format, it's not a hash. – pstrjds Dec 29 '16 at 10:12
  • Are you sure about that? Either VB did some magic and converted the integer to a string using the current locale, or the code *didn't* work and some `catch all` statement hid this. At best, the hashcode is ineffectual, resulting in *vastly slower* comparisons instead of faster. – Panagiotis Kanavos Dec 29 '16 at 10:12
  • If you really want to convert the int to a byte array check the question [Int to byte array](http://stackoverflow.com/questions/4176653/int-to-byte-array). Hint: just call `BitConverter.GetBytes` – Panagiotis Kanavos Dec 29 '16 at 10:14
  • 2
    Out of curiosity, this code wasn't used to validate passwords was it? If it was, you should actually modify it (not just port it) to work correctly, using a more cryptographically secure hashing algorithm. – pstrjds Dec 29 '16 at 10:20
  • Actually, I think it was. I will look into converting it to somewhat more secure, once I got everything running. – Mister 832 Dec 29 '16 at 10:22
  • 3
    @Mister832 actually, run. Just drop the keyboard and run to find a lawyer. You'll need one when you get called as a witness to the inevitable trial. *Passwords* should use cryptographic hash algorithms like SHA256 with thousands of repetitions *and* salting. What you posted can be broken in nanoseconds – Panagiotis Kanavos Dec 29 '16 at 10:25
  • Oh, btw, now that you posted this question, expect exploits to come out by the end of the week, if there aren't out there already. Script kiddies actually *use* bad SO questions or answers, because they know they'll appear in production soon – Panagiotis Kanavos Dec 29 '16 at 10:26
  • @Mister832 seriously, you can get Troy Hunt's security courses from PluralSight *for free* through the (also free) Visual Studio Dev Essentials program. – Panagiotis Kanavos Dec 29 '16 at 10:31
  • 1
    @Mister832 also, ASP.NET provides robust authentication services already, which can also be used by desktop applications. There is absolutely no reason to implement your own, unless you are already a security expert. Note that security experts *don't* create their own authentication if they can help it – Panagiotis Kanavos Dec 29 '16 at 10:33
  • @pstrjds how did you guess? This is actually important, helps identify similar weak sites/services – Panagiotis Kanavos Dec 29 '16 at 10:37
  • From the looks of the code, it seems as it was taken from the internet some years back. I would be surprised, if there weren't any exploits out for it already. – Mister 832 Dec 29 '16 at 10:46
  • @PanagiotisKanavos - I guessed based on what seemed to be the "intent" of the code - hashing a string. If one is hashing a string, there is a possibility it is for a password/authentication purpose. If one is hashing a string poorly, one is almost definitely creating some sort of home grown "security" scheme based on a few articles that one has read from a magazine or blog post. I have fixed lots of legacy code and come across many "home grown" security schemes. This smelled of that. – pstrjds Dec 29 '16 at 13:19

2 Answers2

4

There are two problems with current approach.

A) Your problematic domain of possible passwords is int.MinValue to int.MaxValue (-2147483648 - 2147483647) i.e. 2^32, this means if this is exposed as web service and I can produce requests at pace say 10000 requests per second, it will take around 5 days (worst case) to brute-force guess password.

B) If your "hashed" passwords got ever stolen it will be very easy to reverse engineer passwords of your users since the default .NET string hashing function (https://github.com/floodyberry/Marvin32/blob/master/Marvin32.c) is not cryptographically strong (it is very fast - which is desirable for usage in hashtables and dictionaries, for which the GetHashCode() method is intended) - so random walking trough known password list will generate results with matching hashes FAST.

One might argue though that since you're not using well known cryptographic function, hacker will have to write some unique code to crack it and identify the hash function being used (that is without access to source code) - this is known as security through obscurity and true only for B)

Correct approach goes like:

var password = "StackOverflow";
// ideally salt should be something bound for given user
var salt = "MY UNIQUE SALT";
byte[] hash;
using (var algorithm = new SHA512Managed()) {
  hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(salt + password));
}

Problematic domain of SHA512 is 2^512 - i.e. with requests at pace say 10000 per second it will take (4e+142 years) to crack it via brute-force. Plus since you're salting if your "hashed" passwords got ever stolen, it is impossible to reconstruct the original passwords.

So I'd recommend to implement a decent password hashing and force-switch users to new method.

Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
2

Try

Hash = Encoding.UTF8.GetBytes("StackOverflow".GetHashCode().ToString());

For both C# and VB it gives the same result

Byte[] (11 items)
45 
50 
48 
51 
54 
49 
50 
54 
55 
56 
49 
Damian
  • 2,752
  • 1
  • 29
  • 28
  • Why? The hashcode is an `int` already. And .NET Stringgs are *UTF16*, not UTF8. – Panagiotis Kanavos Dec 29 '16 at 10:11
  • The line `Hash = Encoding.UTF8.GetBytes("StackOverflow".GetHashCode().ToString());`works fine for. VS accepts the syntax and the function returns the same result. – Mister 832 Dec 29 '16 at 10:17
  • 2
    Broken code is broken in both languages. An `int` is just four bytes. This code resulted in 11. This code will break when used with *any* code that implements a correct conversion. Hashcodes are used to speed up comparisons and create dictionary buckets. The result of this code will be that objects that should have been considered equal will fail the comparison – Panagiotis Kanavos Dec 29 '16 at 10:18
  • The correct answer as returned by BitConverter is `184,216,221,125`. You'll notice how the incorrect conversion to UTF8 actually *reduced* the range of the values, resulting in a worse hash – Panagiotis Kanavos Dec 29 '16 at 10:23
  • 3
    Even if the code is not correct because of the bit conversion, the result is the most important part - he is porting the code and is expecting the same result for both C# and VB – Damian Dec 29 '16 at 10:28
  • 3
    I don't understand why answer with the result for described problem is downvoted. If you think the question shows invalid approach to the problem simply add comment under it, not under the answer. – Damian Dec 29 '16 at 10:35
  • 4
    Yep, this is the correct code. The original VB.NET code was implicitly converting the result of `GetHashCode` to a string, so the C# code just needed to explicitly convert it via the `ToString` method. – reduckted Dec 29 '16 at 10:37