public void ItShouldComputeTheHashCorrectly()
        {
            var data = System.Text.Encoding.UTF8.GetBytes("eyJhbGdvcml0aG0iOiJBRVMtMjU2LUNCQyBITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTI4NzYwMTk4OCwiaXYiOiJmRExKQ1cteWlYbXVOYTI0ZVNhckpnIiwicGF5bG9hZCI6IllHeW00cG9Rbk1UckVnaUFPa0ZUVkk4NWxsNVJ1VWlFbC1JZ3FmeFRPVEhRTkl2VlZJOFk4a1Z1T29lS2FXT2Vhc3NXRlRFdjBRZ183d0NDQkVlbjdsVUJCemxGSjFWNjNISjNBZjBTSW5nY3hXVEo3TDZZTGF0TW13WGdEQXZXbjVQc2ZxeldrNG1sOWg5RExuWXB0V0htREdMNmlCaU9oTjdXeUk3cDZvRXBWcmlGdUp3X2NoTG9QYjhhM3ZHRG5vVzhlMlN4eDA2QTJ4MnhraWFwdmcifQ");
            var key  = System.Text.Encoding.UTF8.GetBytes("13750c9911fec5865d01f3bd00bdf4db");

            var expected = new byte[]
            {
                183, 173, 233, 101, 14, 16, 221, 148, 199, 38, 221, 33, 58, 194, 171, 99, 106, 91, 219,
                204, 81, 149, 219, 150, 210, 152, 56, 148, 191, 217, 134, 94
            };

            var hash = FacebookWebUtils.ComputeHmacSha256Hash(data, key);

            Assert.True(expected.SequenceEqual(hash));
        }
예제 #2
0
        /// <summary>
        /// Parse the signed request string.
        /// </summary>
        /// <param name="secret">
        /// The secret.
        /// </param>
        /// <param name="signedRequestValue">
        /// The signed request value.
        /// </param>
        /// <param name="maxAge">
        /// The max age.
        /// </param>
        /// <param name="currentTime">
        /// The current time.
        /// </param>
        /// <param name="throws">
        /// The throws.
        /// </param>
        /// <returns>
        /// The FacebookSignedRequest.
        /// </returns>
        internal static IDictionary <string, object> TryParse(string secret, string signedRequestValue, int maxAge, double currentTime, bool throws)
        {
            if (string.IsNullOrEmpty(secret))
            {
                throw new ArgumentNullException("secret");
            }
            if (string.IsNullOrEmpty(signedRequestValue))
            {
                throw new ArgumentNullException("signedRequestValue");
            }
            if (maxAge < 0)
            {
                throw new ArgumentOutOfRangeException("maxAge", "maxAge must be greater than 0");
            }
            if (currentTime < 0)
            {
                throw new ArgumentOutOfRangeException("currentTime", "currentTime must be greater than 0");
            }

            try
            {
                // NOTE: currentTime added to parameters to make it unit testable.
                string[] split = signedRequestValue.Split('.');
                if (split.Length != 2)
                {
                    // need to have exactly 2 parts
                    throw new InvalidOperationException(FacebookUtils.Resources.InvalidSignedRequest);
                }

                string encodedSignature = split[0];
                string encodedEnvelope  = split[1];

                if (string.IsNullOrEmpty(encodedSignature))
                {
                    throw new InvalidOperationException(FacebookUtils.Resources.InvalidSignedRequest);
                }

                if (string.IsNullOrEmpty(encodedEnvelope))
                {
                    throw new InvalidOperationException(FacebookUtils.Resources.InvalidSignedRequest);
                }

                var envelope = (IDictionary <string, object>)JsonSerializer.Current.DeserializeObject(Encoding.UTF8.GetString(FacebookWebUtils.Base64UrlDecode(encodedEnvelope)));

                string algorithm = (string)envelope["algorithm"];

                if (!algorithm.Equals("AES-256-CBC HMAC-SHA256") && !algorithm.Equals("HMAC-SHA256"))
                {
                    // TODO: test
                    throw new InvalidOperationException("Invalid signed request. (Unsupported algorithm)");
                }

                byte[] key    = Encoding.UTF8.GetBytes(secret);
                byte[] digest = FacebookWebUtils.ComputeHmacSha256Hash(Encoding.UTF8.GetBytes(encodedEnvelope), key);

                if (!digest.SequenceEqual(FacebookWebUtils.Base64UrlDecode(encodedSignature)))
                {
                    throw new InvalidOperationException(Facebook.Web.Properties.Resources.InvalidSignedRequestSignature);
                }

                IDictionary <string, object> result;

                if (algorithm.Equals("HMAC-SHA256"))
                {
                    // for requests that are signed, but not encrypted, we're done
                    result = envelope;
                }
                else
                {
                    result = new JsonObject();

                    result["algorithm"] = algorithm;

                    long issuedAt = (long)envelope["issued_at"];

                    if (issuedAt < currentTime)
                    {
                        throw new InvalidOperationException(Web.Properties.Resources.OldSignedRequest);
                    }

                    result["issued_at"] = issuedAt;

                    // otherwise, decrypt the payload
                    byte[] iv            = FacebookWebUtils.Base64UrlDecode((string)envelope["iv"]);
                    byte[] rawCipherText = FacebookWebUtils.Base64UrlDecode((string)envelope["payload"]);
                    var    plainText     = FacebookWebUtils.DecryptAes256CBCNoPadding(rawCipherText, key, iv);

                    var payload = (IDictionary <string, object>)JsonSerializer.Current.DeserializeObject(plainText);
                    result["payload"] = payload;
                }

                return(result);
            }
            catch
            {
                if (throws)
                {
                    throw;
                }

                return(null);
            }
        }