Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can I get the same HMAC256-results in C# like in the PHP unit tests?
    primarykey
    data
    text
    <p>I thought I would try and get the new Signed Request logic added to my facebook canvas application, to make this "easy" on myself I went to the facebook PHP sdk over at GitHub and took a look at the <a href="http://github.com/facebook/php-sdk/blob/master/tests/tests.php" rel="noreferrer">unit tests</a>. </p> <p>My actual problem is that I cannot get the hash included in the request to match the hash I calculate using the application secret, and the data sent within the request. </p> <p>How this is meant to work is described at <a href="http://developers.facebook.com/docs/authentication/" rel="noreferrer">Facebook's authentication page</a>.</p> <pre><code>private string VALID_SIGNED_REQUEST = "ZcZocIFknCpcTLhwsRwwH5nL6oq7OmKWJx41xRTi59E.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOiIxMjczMzU5NjAwIiwib2F1dGhfdG9rZW4iOiIyNTQ3NTIwNzMxNTJ8Mi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODV8dUk3R3dybUJVZWQ4c2VaWjA1SmJkekdGVXBrLiIsInNlc3Npb25fa2V5IjoiMi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODUiLCJ1c2VyX2lkIjoiMTY3Nzg0NjM4NSJ9"; private string NON_TOSSED_SIGNED_REQUEST = "laEjO-az9kzgFOUldy1G7EyaP6tMQEsbFIDrB1RUamE.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiJ9"; public void SignedRequestExample() { var Encoding = new UTF8Encoding(); string ApplicationSecret = "904270b68a2cc3d54485323652da4d14"; string SignedRequest = VALID_SIGNED_REQUEST; string ExpectedSignature = SignedRequest.Substring(0, SignedRequest.IndexOf('.')); string Payload = SignedRequest.Substring(SignedRequest.IndexOf('.') + 1); // Back &amp; Forth with Signature byte[] ActualSignature = FromUrlBase64String(ExpectedSignature); string TestSignature = ToUrlBase64String(ActualSignature); // Back &amp; Forth With Data byte[] ActualPayload = FromUrlBase64String(Payload); string Json = Encoding.GetString(ActualPayload); string TestPayload = ToUrlBase64String(ActualPayload); // Attempt to get same hash var Hmac = SignWithHMAC(ActualPayload, Encoding.GetBytes(ApplicationSecret)); var HmacBase64 = ToUrlBase64String(Hmac); var HmacHex = BytesToHex(Hmac); if (HmacBase64 != ExpectedSignature) { // YAY } else { // BOO } } private static string BytesToHex(byte[] input) { StringBuilder sb = new StringBuilder(); foreach (byte b in input) { sb.Append(string.Format("{0:x2}", b)); } return sb.ToString(); } private string ToUrlBase64String(byte[] Input) { return Convert.ToBase64String(Input).Replace("=", String.Empty).Replace('+', '-').Replace('/', '_'); } // http://tools.ietf.org/html/rfc4648#section-5 private byte[] FromUrlBase64String(string Base64UrlSafe) { Base64UrlSafe = Base64UrlSafe.PadRight(Base64UrlSafe.Length + (4 - Base64UrlSafe.Length % 4) % 4, '='); Base64UrlSafe = Base64UrlSafe.Replace('-', '+').Replace('_', '/'); return Convert.FromBase64String(Base64UrlSafe); } private byte[] SignWithHMAC(byte[] dataToSign, byte[] keyBody) { using (var hmac = new HMACSHA256(keyBody)) { hmac.ComputeHash(dataToSign); /* CryptoStream cs = new CryptoStream(System.IO.Stream.Null, hmac, CryptoStreamMode.Write); cs.Write(dataToSign, 0, dataToSign.Length); cs.Flush(); cs.Close(); byte[] hashResult = hmac.Hash; */ return hmac.Hash; } } public string Base64ToHex(string input) { StringBuilder sb = new StringBuilder(); byte[] inputBytes = Convert.FromBase64String(input); foreach (byte b in inputBytes) { sb.Append(string.Format("{0:x2}", b)); } return sb.ToString(); } </code></pre> <p>Answer thanks to Rasmus below, to assist anyone else here is the updated (cleaned up code): </p> <pre><code>/// Example signed_request variable from PHPSDK Unit Testing private string VALID_SIGNED_REQUEST = "ZcZocIFknCpcTLhwsRwwH5nL6oq7OmKWJx41xRTi59E.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOiIxMjczMzU5NjAwIiwib2F1dGhfdG9rZW4iOiIyNTQ3NTIwNzMxNTJ8Mi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODV8dUk3R3dybUJVZWQ4c2VaWjA1SmJkekdGVXBrLiIsInNlc3Npb25fa2V5IjoiMi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODUiLCJ1c2VyX2lkIjoiMTY3Nzg0NjM4NSJ9"; public bool ValidateSignedRequest() { string applicationSecret = "904270b68a2cc3d54485323652da4d14"; string[] signedRequest = VALID_SIGNED_REQUEST.Split('.'); string expectedSignature = signedRequest[0]; string payload = signedRequest[1]; // Attempt to get same hash var Hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(payload), UTF8Encoding.UTF8.GetBytes(applicationSecret)); var HmacBase64 = ToUrlBase64String(Hmac); return (HmacBase64 == expectedSignature); } private string ToUrlBase64String(byte[] Input) { return Convert.ToBase64String(Input).Replace("=", String.Empty) .Replace('+', '-') .Replace('/', '_'); } private byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody) { using (var hmacAlgorithm = new HMACSHA256(keyBody)) { hmacAlgorithm.ComputeHash(dataToSign); return hmacAlgorithm.Hash; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload