1

Payload=ABCDEFGHIJKLMNOPQR; basetoConvert = hexa

public static string SHA256HashToBaseMessage(string payload, eBase baseToConvert)
{                        
    StringBuilder sb;
    using (SHA256 sHA256 = SHA256.Create("SHA256"))
    {
        byte[] hash = sHA256.ComputeHash(Encoding.UTF8.GetBytes(payload));
        sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {                    
            sb.Append(Convert.ToString((hash[i] & 0xff) + 0x100, (int)baseToConvert).Substring(1));
        }
    }
    return sb.ToString();
}

public enum eBase
{
    BINARY=2,
    OCTAL=8,
    DECA=10,
    HEXA=16
}

Above is my code for generating the corresponding base string of the byte. I used the code given in the documentation. My question is when I was using this part of code like

sb.Append(Convert.ToString(hash[i], (int)baseToConvert));

Output is:

38d3bed3499804995bda3123885d4f3eab0c19efc2dd03df5be147b359ceed

But when I am using the code as the documentation,

sb.Append(Convert.ToString((hash[i] & 0xff) + 0x100, (int)baseToConvert).Substring(1));

for the same payload, the output is (the original version from above is underneath, for comparison - differences as space),

38d3bed34909804995bda3123885d4f3eab0c19efc2dd03df5be0147b359ceed
38d3bed349 9804995bda3123885d4f3eab0c19efc2dd03df5be 147b359ceed -- original

Can anybody explain why there is a difference in the output? What actually (hash[i] & 0xff) + 0x100) is doing?

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • https://stackoverflow.com/questions/16999361/obtain-sha-256-string-of-a-string/17001289#17001289 – Dmitry Bychenko Nov 16 '18 at 11:28
  • 1
    `&ff` takes just the least significant byte; `+0x100` adds 256 to it, essentially setting the next bit; I'm guessing that was just a hacky way they found to ensure they got a leading zero, when combined with the `Substring`? (tip: it isn't a good way) – Marc Gravell Nov 16 '18 at 11:28
  • Why such complex `sb.Append(Convert.ToString((hash[i] & 0xff) + 0x100, (int)baseToConvert).Substring(1));`? Just formatting with `x2` format string - we want **2** hexadecimal digits `sb.Append(hash[i].ToString("x2"));` – Dmitry Bychenko Nov 16 '18 at 11:29
  • @DmitryBychenko That shows me the different way to implement the same thing. – Shuchin Prakash Nov 16 '18 at 11:30
  • 2
    @DmitryBychenko so... it all comes down to leading zeros, then? the `x2` ensures you get a leading zero, as does the Substring hack; your original version, however, does not; which means that you write `9` instead of `09`, and `1` instead of `01` - is that the difference we're looking at here? – Marc Gravell Nov 16 '18 at 11:33
  • Wich number every letter has is a highly subjective number. Something we barely managed to figure out soemwhat reliably with Unicode. https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/ It is possible that theDocumentation has a faulty value. In particular the spaces indicate that. – Christopher Nov 16 '18 at 11:33
  • @Christopher I added the spaces to help clarify the differences - that's not part of the actual output – Marc Gravell Nov 16 '18 at 11:34
  • @Marc Gravell: yes, it's all about leading zeroes: if we insert `sb.Append('_')` in the loop in order to visualize bytes we'll get `_38_d3_be_d3_49_9_80_49_95_bd_a3_12_38_85_d4_f3_ea_b0_c1_9e_fc_2d_d0_3d_f5_be_1_47_b3_59_ce_ed` - please, note `49_9_80` and `be_1_47` fragments – Dmitry Bychenko Nov 16 '18 at 11:44
  • @MarcGravell Thanks for the explanation. – Shuchin Prakash Nov 16 '18 at 11:44
  • ``hash[i] & 0xff`` seems to be redundant; it makes sure ``hash[i]`` is between 0x00 and 0xff but that is true anyway because the range of ``byte`` is 0x00 to 0xff. Adding 0x100 makes sure the number has 3 digits so that taking the substring from index 1 will return two digits, including any leading zero. However, I believe this particular arithmetic is only correct for hexadecimal numbers (which is all you should need for this type of conversion anyway). Your original will not yield a two-digit string for numbers from 0x0 to 0xf, therefore the difference (that you marked with spaces). – dumetrulo Nov 16 '18 at 11:55

1 Answers1

0

I don't think it's a good idea applying format (adding leading zeros) with bit manipulation. Let's do it explicitly with PadLeft:

public static string SHA256HashToBaseMessage(string payload, eBase baseToConvert) {
  //DONE: public method values' validation 
  if (null == payload)
    throw new ArgumentNullException(nameof(payload));

  int padLength =
    (baseToConvert == eBase.BINARY) ? 8 : // 8 for binary
    (baseToConvert == eBase.HEXA) ? 2 :   // 2 for hexadecimal
    3;                                    // 3 for decimal and octal

  StringBuilder sb = new StringBuilder();

  using (SHA256 sHA256 = SHA256.Create("SHA256")) {
    byte[] hash = sHA256.ComputeHash(Encoding.UTF8.GetBytes(payload));

    for (int i = 0; i < hash.Length; i++) 
      sb.Append(Convert.ToString(hash[i], (int)baseToConvert).PadLeft(padLength, '0'));
  }
  return sb.ToString();
}

If you run this code you'll get

38d3bed34909804995bda3123885d4f3eab0c19efc2dd03df5be0147b359ceed
          ^                                         ^
          padding: 9 -> "09"                        padding: 1 -> "01"

In case you remove padding - .PadLeft(padLength, '0') both 0 will not appear

38d3bed3499804995bda3123885d4f3eab0c19efc2dd03df5be147b359ceed
         ^                                         ^
         no padding: 9 -> "9"                      no padding: 1 -> "1" 
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215