1

I'm following this site to have a token based authentication from an ionic+angularJs mobile client to C# Web API REST Client.

The JS code to generate token is as following:

generate: function (username, domain, password) {

            if (username && domain && password) {
                // If the user is providing credentials, then create a new key.
                this.logout();
            }

            //Set the username
            SecurityManager.username = SecurityManager.username || username;


            //Set the domain
            SecurityManager.domain = SecurityManager.domain || domain;

            // Set the key to a hash of the user's password + salt.
            SecurityManager.key = SecurityManager.key || CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256([password, SecurityManager.salt].join(':'), SecurityManager.salt));

            $log.log("security key: " + SecurityManager.key);

            // Set the client IP address.
            SecurityManager.ip = SecurityManager.ip || this.getIp();

            // Persist key pieces.
            if (SecurityManager.username) {
                localStorage['SecurityManager.username'] = SecurityManager.username;
                localStorage['SecurityManager.domain'] = SecurityManager.domain;
                localStorage['SecurityManager.key'] = SecurityManager.key;
            }

            // Get the (C# compatible) ticks to use as a timestamp. http://stackoverflow.com/a/7968483/2596404
            var ticks = ((new Date().getTime() * 10000) + 621355968000000000);

            // Construct the hash body by concatenating the username, domnain, ip, and userAgent.
            var message = [SecurityManager.username, SecurityManager.domain, SecurityManager.ip, navigator.userAgent.replace(/ \.NET.+;/, ''), ticks].join(':');


            $log.log("values are:" + message.split(':'));


            // Hash the body, using the key.
            var hash = CryptoJS.HmacSHA256(message, SecurityManager.key);

            $log.log("security key hash: " + hash);


            // Base64-encode the hash to get the resulting token.
            var token = CryptoJS.enc.Base64.stringify(hash);

            $log.log("base 64 encoded hash: " + token);

            // Include the username, domain and timestamp on the end of the token, so the server can validate.
            var tokenId = [SecurityManager.username, SecurityManager.domain, ticks].join(':');

            // Base64-encode the final resulting token.
            var tokenStr = CryptoJS.enc.Base64.parse([token, tokenId].join(':'));

            var finalToken = CryptoJS.enc.Base64.stringify(tokenStr);

            $log.log("Token is " + finalToken);

            return finalToken;
 }

This gets the output:

1     414448   log      security key:  LGlemne7vnKZMI35qNw2pgv7YsLerXTaegcycy6x5n0=
2     414562   log      values are:joe,cs,127.0.0.1,Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586,635887772145620000
3     414564   log      security key hash: d27a0346ea0ad6b50ae158cdc4433a129f957a1c965e126d9b2060f9fb11c0b7
4     414565   log      base 64 encoded hash: 0noDRuoK1rUK4VjNxEM6Ep+VehyWXhJtmyBg+fsRwLc=
5     414566   log      Token is 0noDRuoK1rUK4VjNxEM6Ep+VehyWXhJtmyBg+fsRwLc=

The C# Code to Generate Token is:

public static string GenerateToken(string username, string domain, string password, string ip, string userAgent, long ticks)
    {
        string hash = string.Join(":", new string[] { username,  domain, userAgent, ticks.ToString() });
        string hashLeft = string.Empty;
        string hashRight = string.Empty;

        using (HMAC hmac = HMACSHA512.Create(_alg))
        {
            hmac.Key = Encoding.UTF8.GetBytes(GetHashedPassword(password));
            **var a = System.Text.Encoding.UTF8.GetString(hmac.Key); //correct**

            hmac.ComputeHash(Encoding.UTF8.GetBytes(hash));                
            hashLeft = Convert.ToBase64String(hmac.Hash);
            hashRight = string.Join(":", new string[] { username, domain, ticks.ToString() });
        }

        var c =  Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join(":", hashLeft, hashRight)));
        return c;
    }
private static string GetHashedPassword(string password)
    {
        string key = string.Join(":", new string[] { password, _salt });

        using (HMAC hmac = HMACSHA512.Create(_alg))
        {
            // Hash the key.
            hmac.Key = Encoding.UTF8.GetBytes(_salt);
            hmac.ComputeHash(Encoding.UTF8.GetBytes(key));

            return Convert.ToBase64String(hmac.Hash);
        }
    }

When I run the test in C# passing in the same long ticks, string username, string password, string domain, string ip and string user agent I'm getting a different token.

[TestMethod]
    public void GenerateTokenTest2()
    {
        string username = "joe";
        string domain = "cs";
        string password = "password";
        string ip = "127.0.0.1";            
        string userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586";

        long ticks = 635887772145620000;

        var token = SecurityManager.GenerateToken(username, domain, password, ip, userAgent, ticks);

        Assert.IsNotNull(token);           
    }

The C# and JS security key match. LGlemne7vnKZMI35qNw2pgv7YsLerXTaegcycy6x5n0=

But the final tokens do not.

The post has more explanation on what they're trying to achieve. I added the domain bit to it, not that it works without it.

The salt is also the same:9eiPO7M99Xphj9WQf76t

I've also referenced the following libraries in the web page.

 <!--Crypto-JS-->
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha256.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>

1 Answer 1

0

I found my mistake. I wasn't using ip as part of the hash in C#.

Also,

 // Base64-encode the final resulting token.
            var tokenStr = CryptoJS.enc.Utf8.parse([token, tokenId].join(':'));

should be

 // Base64-encode the final resulting token.
            var tokenStr = CryptoJS.enc.Base64.parse([token, tokenId].join(':'));

But this above was only because I was trying different things.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.