-3

Below are 2 similar code blocks. They take a string, encrypt in SHA512, then convert to Base64, I had trouble getting the second code block to produce the same results as my manual test using online calculators and encoders. So I broke the process down step by step and discovered that it was capable of producing the same results as my manual test but only if it behaved like the first code block. Why do these two code blocks produce different results? Thanks!

    private void EditText_AfterTextChanged(object sender, AfterTextChangedEventArgs e)
    {
        //This builds a string to encrypt.
        string domain = txtDomain.Text;
        string username = txtUsername.Text;
        string pin = txtPin.Text;
        txtPreview.Text = string.Format("{0}+{1}+{2}", domain, username, pin);

        //This takes the above string, encrypts it.
        StringBuilder Sb = new StringBuilder();
        SHA512Managed HashTool = new SHA512Managed();
        Byte[] PhraseAsByte = System.Text.Encoding.UTF8.GetBytes(string.Concat(txtPreview.Text));
        Byte[] EncryptedBytes = HashTool.ComputeHash(PhraseAsByte);
        HashTool.Clear();

        //This rebuilds the calculated hash for manual comparison.
        foreach (Byte b in EncryptedBytes)
            Sb.Append(b.ToString("x2"));
        txtHash.Text = Sb.ToString();

        //This takes the rebuilt hash and re-converts it to bytes before encoding it in Base64
        EncryptedBytes = System.Text.Encoding.UTF8.GetBytes(string.Concat(txtHash.Text));
        txtResult.Text = Convert.ToBase64String(EncryptedBytes);

    }

and

    private void EditText_AfterTextChanged(object sender, AfterTextChangedEventArgs e)
    {
        //This builds a string to encrypt.
        string domain = txtDomain.Text;
        string username = txtUsername.Text;
        string pin = txtPin.Text;
        txtPreview.Text = string.Format("{0}+{1}+{2}", domain, username, pin);

        //This takes the above string, encrypts it.
        StringBuilder Sb = new StringBuilder();
        SHA512Managed HashTool = new SHA512Managed();
        Byte[] PhraseAsByte = System.Text.Encoding.UTF8.GetBytes(string.Concat(txtPreview.Text));
        Byte[] EncryptedBytes = HashTool.ComputeHash(PhraseAsByte);
        HashTool.Clear();

        //This takes the EncryptedBytes and converts them to base64.
        txtResult.Text = Convert.ToBase64String(EncryptedBytes);

        //This reverses the EncryptedBytes into readable hash for manual comparison
        foreach (Byte b in EncryptedBytes)
        Sb.Append(b.ToString("x2"));
        txtHash.Text = Sb.ToString();
    }
Josh
  • 141
  • 1
  • 15
  • 2
    "encrypt in SHA512"? You cannot encrypt with SHA, you *hash* with SHA – Camilo Terevinto Apr 04 '18 at 17:14
  • Isn't that just petty semantics?. Encrypt, hash, encode, convert.. – Josh Apr 04 '18 at 17:15
  • 1
    Encrypt is two way, you can recover the original value from the output by decrypting. Hash is one way, you cannot recover the original value from the output. – Kevin Apr 04 '18 at 17:36
  • Right, I do understand the technical difference but I guess I've offended some by not using the terms accurately. I didn't consider it necessary to understand the code. – Josh Apr 04 '18 at 17:50

1 Answers1

-1

Found the answer, no thanks to your less-than-useful downvotes..

Encoding.Unicode is Microsoft's misleading name for UTF-16 (a double-wide encoding, used in the Windows world for historical reasons but not used by anyone else). http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx

If you inspect your bytes array, you'll see that every second byte is 0x00 (because of the double-wide encoding).

You should be using Encoding.UTF8.GetBytes instead.

But also, you will see different results depending on whether or not you consider the terminating '\0' byte to be part of the data you're hashing. Hashing the two bytes "Hi" will give a different result from hashing the three bytes "Hi". You'll have to decide which you want to do. (Presumably you want to do whichever one your friend's PHP code is doing.)

For ASCII text, Encoding.UTF8 will definitely be suitable. If you're aiming for perfect compatibility with your friend's code, even on non-ASCII inputs, you'd better try a few test cases with non-ASCII characters such as é and 家 and see whether your results still match up. If not, you'll have to figure out what encoding your friend is really using; it might be one of the 8-bit "code pages" that used to be popular before the invention of Unicode. (Again, I think Windows is the main reason that anyone still needs to worry about "code pages".)

Source: Hashing a string with Sha256

Community
  • 1
  • 1
Josh
  • 141
  • 1
  • 15