I'm trying to get a website Login page and a C# launcher to connect to a MySQL database, my C# code converts a string to SHA256 but in uppercase. So I figured it would be easier to change in PHP, so using strtoupper I pass the variable string for the encrypted password. It works great the only problem is this:
bec4c38f480db265e86e1650b1515216be5095f7a049852f76eea9934351b9ac - Original
BEC4C38F48DB265E86E1650B1515216BE5095F7A049852F76EEA9934351B9AC - C#
^ Right here there is meant to be a 0
I'm not sure what's gone wrong as both are using the exact same encryption method and it's odd that it's only one Character... Has anyone experienced this before?
PHP to encrypt text to SHA256 and then strtoupper:
$encrypt_password=(hash('sha256', $mypassword));
$s_password = strtoupper($encrypt_password);
C# Convert string to SHA256:
System.Security.Cryptography.SHA256 sha256 = new System.Security.Cryptography.SHA256Managed();
byte[] sha256Bytes = System.Text.Encoding.Default.GetBytes(txtpass.Text);
byte[] cryString = sha256.ComputeHash(sha256Bytes);
string sha256Str = string.Empty;
for (int i = 0; i < cryString.Length; i++)
{
sha256Str += cryString[i].ToString("X");
}
This is the only code that involves encrypting on both sides.
A value like 13 is just "D" not "0D" like would represented in the hash. You need to pad values that are less than 2 digits. Use "X2" as the format string.
Related
I'm working on rewriting a piece of PHP code to C#. This code is used for password hashing. In the first step it produces a string like "password{salt}", than hashes it via sha512 hash algorithm. After that a loop is hashing the combination of the first hash and the salt again for 5000 iterations.
The PHP Code looks like this:
<?php
$password = 'abc';
$salt = 'def';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
for ($i=1; $i<5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encodedPassword = base64_encode($digest);
//$encodedPassword contains the final hash code
I was able to get it working without the loop (with just the first hash() call). So the main hashing and base64 encoding is done correctly. I found out that this part is what I cannot manage to rewrite in C#:
$digest.$salted
$digest seems to be a binary representation since PHP's hash() function was used with "true" as the last parameter (see PHP hash - manual). $salted is a string. Both get somehow magically combined by PHP's dot / concat operator. I guess there will be some sort of standard conversion from binary to string under the hood when using the dot operator with a non-string operand.
This is my code so far:
void Main()
{
string password = "abc";
string salt = "def";
string salted = String.Format("{0}{{{1}}}", password, salt);
byte[] digest = hash(salted);
for(int i = 1; i < 1; i++)
{
digest = hash(String.Format("{0}{1}", System.Text.Encoding.UTF8.GetString(digest), salted));
}
var encodedPassword = System.Convert.ToBase64String(digest);
//$encodedPassword should contain the final hash code
}
static byte[] hash(string toHash)
{
System.Security.Cryptography.SHA512 sha512 = new System.Security.Cryptography.SHA512Managed();
return sha512.ComputeHash(System.Text.Encoding.UTF8.GetBytes(toHash));
}
As you see I tried to convert the hash bytes back to a string with System.Text.Encoding.UTF8.GetString() and then append the salt but that doesn't produce the same output as the PHP code.
I would be very happy if someone could help me on this. Thank you very much.
In the PHP version you loop 4999 times, while in the C# version 0. The second problem is that the returned bytes from hash() have no encoding at all.
This should give you the same result as the PHP version:
System.Security.Cryptography.SHA512 sha512 = new System.Security.Cryptography.SHA512Managed();
var saltedUtf8Bytes = System.Text.Encoding.UTF8.GetBytes(salted);
for(int i = 1; i < 5000; i++)
{
digest = sha512.ComputeHash(digest.Concat(saltedUtf8Bytes).ToArray());
}
I'm trying to recreate the functionallity of
slappasswd -h {md5}
on .Net
I have this code on Perl
use Digest::MD5;
use MIME::Base64;
$ctx = Digest::MD5->new;
$ctx->add('fredy');
print "Line $.: ", $ctx->clone->hexdigest, "\n";
print "Line $.: ", $ctx->digest, "\n";
$hashedPasswd = '{MD5}' . encode_base64($ctx->digest,'');
print $hashedPasswd . "\n";
I've tried to do the same on VB.Net , C# etc etc , but only works the
$ctx->clone->hexdigest # result : b89845d7eb5f8388e090fcc151d618c8
part in C# using the MSDN Sample
static string GetMd5Hash(MD5 md5Hash, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
With this code in Console App :
string source = "fredy";
using (MD5 md5Hash = MD5.Create())
{
string hash = GetMd5Hash(md5Hash, source);
Console.WriteLine("The MD5 hash of " + source + " is: " + hash + ".");
}
outputs : The MD5 hash of fredy is: b89845d7eb5f8388e090fcc151d618c8.
but i need to implement the $ctx->digest function, it outputs some binary data like
¸˜E×ë_ƒˆàüÁQÖÈ
this output happens on Linux and Windows with Perl.
Any ideas?
Thanks
As I already said in my comment above, you are mixing some things up. What the digest in Perl creates is a set of bytes. When those are printed, Perl will convert them automatically to a string-representation, because (simplified) it thinks if you print stuff it goes to a screen and you want to be able to read it. C# does not do that. That doesn't mean the Perl digest and the C# digest are not the same. Just their representation is different.
You have already established that they are equal if you convert both of them to a hexadecimal representation.
Now what you need to do to get output in C# that looks like the string that Perl prints when you do this:
print $ctx->digest; # output: ¸˜E×ë_ƒˆàüÁQÖÈ
... is to convert the C# byte[] data to a string of characters.
That has been answered before,f or example here: How to convert byte[] to string?
Using that technique, I believe your function to get it would look like this. Please note I am a Perl developer and I have no means of testing this. Consider it C#-like pseudo-code.
static string GetMd5PerlishString(MD5 md5Hash, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
string result = System.Text.Encoding.UTF8.GetString(data);
return result;
}
Now it should look the same.
Please also note that MD5 is not a secure hashing algorithm for passwords any more. Please do not store use it to store user passwords!
I am trying to replicate the following code in PHP, It is example code for an API I have to interface with (The API & Example code is in C#, My app is in PHP 5.3). I'm not a C# developer and so am having trouble doing this.
// C# Code I am trying to replicate in PHP
var apiTokenId = 1887;
var apiToken = "E1024763-1234-5678-91E0-T32E4E7EB316";
// Used to authenticate our request by the API (which is in C#)
var stringToSign = string.Empty;
stringToSign += "POST"+"UserAgent"+"http://api.com/post";
// Here is the issue, How can I do the following 3 lines in PHP?
// No "secret key" provided?.. How do I do this in PHP?
var hmacsha1 = new HMACSHA1(new Guid(apiToken).toByteArray());
// Make a byte array with ASCII encoding.
byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(stringToSign);
// Finally, 'computeHash' of the above (what does this do exactly?!)
var calculatedSignature = Convert.ToBase64String(hmacsha1.ComputeHash(byteArray));
I've tried many variations using pack() and other functions I've found online, but without anything to compare it to, I don't know if i've done it right or not.
Can any C# devs run the above code and post the values generated so I can use that to check/test against?
I've tried checking the MSDN to see what these methods do, but am stuck (and not sure if its correct, as I have nothing to compare it to).
PHP Pseudo Code
// Set vars
$apiToken = 'E1024763-1234-5678-91E0-T32E4E7EB316';
$apiTokenId = '1887';
$stringToSign = "POST"."UserAgent"."http://api.com/post";
// HowTo: Build a `byteArray` of our apiToken? (i think)
// C#: var hmacsha1 = new HMACSHA1(new Guid(apiToken).toByteArray());
// HowTo: Convert our $stringToSign to a ASCII encoded `byteArray`?
// C#: byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(stringToSign);
// HowTo: Generate a base64 string of our (`hmacsha1`.ComputeHash(byteArray))
// C#: var calculatedSignature = Convert.ToBase64String(hmacsha1.ComputeHash(byteArray));
This sounds pretty simple and straightforwaard, but I'm not sure what a few of these C# methods do..
What do these C# methods do/return?
ComputeHash(byteArray) - Computed to what?.. what is returned?
System.Text.Encoding.ASCII.GetBytes(stringToSign); - What does this return?
new HMACSHA1(new Guid(apiToken).toByteArray()); No Secret Key?, what is the key used?
Any resources or help would be much appreciated.
I tried variations of other answers on SO, but no joy.
Can I run the 3 lines of code somewhere online (like JSFiddle but for C#?) so I can see the output of each line?
Update - Bounty Added
Still having trouble with this, I have managed to test the C# code in Visual Studio, but am having trouble getting the same hash generated in PHP.
I would like...
.. the above C# code (specifically, the 3 lines which create the SHA1 hash) to be converted into PHP (Check out the Pseudo Code I posted above). I should be able to match the C# hash using PHP.
If you have any other questions, please ask.
The issue is that the string form of the GUID reverses the order of the 2-character hexadecimal numbers in the first 3 segments of the GUID. For more information see the comments in the example at: http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx
The following code should work:
$apiTokenId = 1887;
$apiToken = "E1024763-1234-5678-91E0-FF2E4E7EB316";
$stringToSign = '';
$hexStr = str_replace('-','',$apiToken);
$c = explode('-',chunk_split($hexStr,2,'-'));
$hexArr = array($c[3],$c[2],$c[1],$c[0],$c[5],$c[4],$c[7],$c[6],$c[8],$c[9],$c[10],$c[11],$c[12],$c[13],$c[14],$c[15]);
$keyStr = '';
for ($i = 0; $i < 16; ++$i) {
$num = hexdec($hexArr[$i]);
$keyStr .= chr($num);
}
$stringToSign .= "POST" . "UserAgent" . "http://api.com/post";
$hmacsha1 = base64_encode(hash_hmac('sha1',$stringToSign,$keyStr,true));
I've tested this code against the C# code you provided above and the output was the same. However, the GUID specified in the original code is not valid so I had to change it slightly.
It's pretty easy, when i don't have to test the code :P
http://php.net/manual/en/function.hash-hmac.php - that's the equivalent of the HMACSHA1 c# class.
string hash_hmac (string $algo , string $data , string $key [, bool $raw_output = false ] )
So $algo = "sha1"
$data is your $stringToSign - since that is already an ascii string (i hope) - the C# was just taking the byte equivalent of the same.
new Guid(apiToken).toByteArray() -> that's a 16 byte (16*8 = 128) representation of the GUID - which is 32*4 = 128 bits. This is the key.
$key is a string so you need the ASCII string equivalent for your $apiToken (which is 32 hex chars - first strip / ignore the dashes in between) - E10247631234567891E0T32E4E7EB316 (correct the key - it cannot have a "T")
function hex2str($hex) {
for($i=0;$i<strlen($hex);$i+=2) $str .= chr(hexdec(substr($hex,$i,2)));
return $str;
}
$hexKey = hex2str($apiToken); //strip the dashes first
http://www.linux-support.com/cms/php-convert-hex-strings-to-ascii-strings/
So the method call now works :
$almostResult = hash_hmac ("sha1" , $stringToSign, $hexKey, true)
This returns a binary string - which you need to convert to base64 encoding.
$final = base64_encode ($almostResult)
That should do it...enjoy :)
I faced almost the same problem and after some googling i found this post:
https://www.reddit.com/r/PHP/comments/2k9tol/string_to_byte_array_using_utf8_encoding/
In PHP strings are already byte arrays. What is the specific problem you are having?
For me the solution was just base64_encode('apikey')
I have an algorithm in C# running on server side which hashes a base64-encoded string.
byte[] salt = Convert.FromBase64String(serverSalt); // Step 1
SHA256Managed sha256 = new SHA256Managed(); // Step 2
byte[] hash = sha256.ComputeHash(salt); // Step 3
Echo("String b64: " + Convert.ToBase64String(hash)); // Step 4
The hash is then checked against a database list of hashes.
I'd love to achieve the same with javascript, using the serverSalt as it is transmitted from C# through a websocket.
I know SHA-256 hashes different between C# and Javascript because C# and Javascript have different string encodings.
But I know I can pad zeros in the byte array to make Javascript behave as C# (step 1 above is solved).
var newSalt = getByteArrayFromCSharpString(salt); // Pad zeros where needed
function getByteArrayFromCSharpString(inString)
{
var bytes = [];
for (var i = 0; i < inString.length; ++i)
{
bytes.push(inString.charCodeAt(i));
bytes.push(0);
}
return bytes;
}
Could anyone provide some insight on which algorithms I could use to reproduce steps 2, 3 and 4?
PS: there are already questions and answers around but not a single code snippet.
Here's the solution, I really hope this could help other people in the same situation.
In the html file, load crypto-js library
<!-- library for doing password hashing, base64 eoncoding / decoding -->
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/core-min.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/sha256.js"></script>
In the javascript, do the following
// This function takes a base64 string, hashes it with the SHA256 algorithm
// and returns a base64 string.
function hashBase64StringAndReturnBase64String(str)
{
// Take the base64 string and parse it into a javascript variable
var words = CryptoJS.enc.Base64.parse(str);
// Create the hash using the CryptoJS implementation of the SHA256 algorithm
var hash = CryptoJS.SHA256(words);
var outString = hash.toString(CryptoJS.enc.Base64)
// Display what you just got and return it
console.log("Output string is: " + outString);
return outString;
}
check Java script SHA256 implementation on the following URL
http://www.movable-type.co.uk/scripts/sha256.html
I was given C# code and I'm trying to generate the equivalent SHA1 using Perl.
public string GetHashedPassword(string passkey)
{
// Add a timestamp to the passkey and encrypt it using SHA1.
string passkey = passkey + DateTime.UtcNow.ToString("yyyyMMddHH0000");
using (SHA1 sha1 = new SHA1CryptoServiceProvider())
{
byte[] hashedPasskey =
sha1.ComputeHash(Encoding.UTF8.GetBytes(passkey));
return ConvertToHex(hashedPasskey);
}
}
private string ConvertToHex(byte[] bytes)
{
StringBuilder hex = new StringBuilder();
foreach (byte b in bytes)
{
if (b < 16)
{
hex.AppendFormat("0{0:X}", b);
}
else
{
hex.AppendFormat("{0:X}", b);
}
}
return hex.ToString();
}
The same as:
use Digest::SHA1 qw( sha1_hex );
my $pass = "blahblah";
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime();
$year += 1900;
my $date = sprintf("%d%02d%02d%02d0000", $year, $mon+1, $mday, $hour);
my $passSha1 = sha1_hex($pass.$date);
//9c55409372610f8fb3695d1c7c2e6945164a2578
I don't actually have any C# experience so I'm not able to test what is normally outputted from the C# code.
The code is supposed to be used as a checksum for a website but the one I'm providing is failing.
Edit: it also adds the UTC timestamp (yyyyMMDDHH0000) to the end of the pass before hashing so I've added that code in case the issue is there.
I do not know C# either. However, {0:X} formats hex digits using upper case letters. So, would
my $passSha1 = uc sha1_hex($pass);
help? (Assuming GetHashedPassword makes sense.)
The only difference I can see (from running the code under Visual Studio 2008) is that the C# code is returning the hex string with alphas in uppercase
D3395867D05CC4C27F013D6E6F48D644E96D8241
and the perl code is using lower case for alphas
d3395867d05cc4c27f013d6e6f48d644e96d8241
The format string used in the C# code is asking for uppercase ("X" as opposed to "x"):
hex.AppendFormat("{0:X}", b);
Maybe the code at the website is using a case sensitive comparison? I assume it would be trivial for you to convert the output from the CPAN function to uppercase before you submit it?
Could it be as simple as changing the uppercase 'X' in the AppendFormat call to a lowercase 'x'?
I think you're looking for Digest::SHA1
Your SHA-1 could have also just been:
BitConverter.ToString(SHA.ComputeHash(buffer)).Replace("-", "");