0

I have a perl script that hashes and hexes parameters for authenticating a post message. I have to write the same procedure in C#, but have had no luck so far. Here is the perl code:

my $sha1_user_pwd = sha1_base64($user_pwd);
$sha1_user_pwd .= '=' x (4 - (length($sha1_user_pwd) % 4));

my $sha1_ws_pwd = sha1_base64($ws_pwd);
$sha1_ws_pwd    .= '=' x (4 - (length($sha1_ws_pwd) % 4)); # Padding; if neccesary.

my $utc_time = time;

my ($utc_time, $kontekst, $projekt, $userid, $sha1_user_pwd) = @_;
my $auth = calc_hmac($sha1_ws_pwd, $sha1_user_pwd, $utc_time, $kontekst, $projekt, $userid);

sub calc_hmac {
    my ($sha1_ws_pwd, $sha1_user_pwd, $utc_time, $kontekst, $projekt, $userid) = @_;
    my $hmac = Digest::HMAC_SHA1->new($sha1_ws_pwd . $sha1_user_pwd);
    $hmac->add($utc_time . $kontekst . $projekt . $userid);
    return $hmac->hex digest;
}

$kontekst, $projekt, $userid and $ws_userid are all original string values.

Final post message (i have inserted line breaks for readability)

wsBrugerid=$ws_userid
&UTCtime=$utc_time
&kontekst=$kontekst
&projekt=$projekt
&BrugerId=$userid
&Auth=$auth

I have tried to copy the procedure in C#:

    const string APP_KEY = "APP_KEY";
    Encoding enc = Encoding.ASCII;
    HMACSHA1 hmac = new HMACSHA1(enc.GetBytes(APP_KEY));
    hmac.Initialize();

    string ws_user      = "ws_usr";
    string ws_password  = "ws_pwd";

    DateTime epochStart = new System.DateTime(1970, 1, 1, 8, 0, 0, System.DateTimeKind.Utc);
    int time            = (int) (System.DateTime.UtcNow - epochStart).TotalSeconds;
    string context      = "context";
    string project      = "project";

    string user_id      = "user_id";
    string user_pwd     = "user_pwd";

    string sha1_ws_pwd  = System.Convert.ToBase64String(hmac.ComputeHash(enc.GetBytes(ws_password)));
    sha1_ws_pwd += '=';

    string sha1_user_pwd = System.Convert.ToBase64String(hmac.ComputeHash(enc.GetBytes(user_pwd)));
    sha1_user_pwd += '=';

    string k0           = sha1_ws_pwd + sha1_user_pwd;
    string m0           = time + context + project + user_id;
    byte[] _auth        = hmac.ComputeHash(enc.GetBytes(k0 + m0));
    string auth         = BitConverter.ToString(_auth).Replace("-", string.Empty);

    string url = "https://auth.emu.dk/mauth?wsBrugerid="+ws_user+
    "&UTCtime="+time+
    "&kontekst="+context+
    "&projekt="+project+
    "&BrugerId="+user_id+
    "&Auth="+auth;

    print("AuthenticationManager, url: " + url);

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";

    Encoding encoding = System.Text.Encoding.GetEncoding("utf-8");

    String responseString = "";

    HttpWebResponse response = (HttpWebResponse) request.GetResponse();
    using (Stream stream = response.GetResponseStream()){
        StreamReader reader = new StreamReader(stream, encoding);
        responseString = reader.ReadToEnd();
    }

    JSONNode json = JSON.Parse(responseString);
    print("AuthenticationManager, response: " + json[0] + " - " + json[1]);

I have no access to the server or application, which gives the response. The real values has of course been swapped. For example, APP_KEY is not "APP_KEY", but instead an actual string used for authentication. I know the data is correct as it passes in the perl script. I appreciate any help I can get very much.

Asger
  • 1
  • 1
  • 1
    You don't need the `sha1_ws_pwd += '=';` and `sha1_user_pwd += '=';`. The `Convert.ToBase64String` is already padded to length 4 – xanatos Mar 18 '16 at 08:01
  • 1
    I'm sure it has nothing to do but...isn't unix epoch start `1/1/1970 00:00:00` ? Why do you define it as `08:00:00` ? – Pikoh Mar 18 '16 at 08:01
  • Okay, i removed += '='. I remember i had them off at first, but since it did not work i tried adding them. In relation to the time, it is simply because I didn't pay attention.. thanks for pointing that out. But still, it does not work. – Asger Mar 18 '16 at 10:35
  • All you've said about what's wrong is that you've "had no luck so far". That's not very descriptive. What's the problem you're having? Have you tried using something like Fiddler to examine the request/response in the case of both the Perl & C# code, to see the difference? – Dave W Mar 18 '16 at 11:58
  • The perl script does not even compile, but i've managed to print out the final post message and test it in a browser, which returned the correct data. But the post message created in C# does not give the correct data thus the hashing must be different somewhere. – Asger Mar 18 '16 at 12:44

1 Answers1

0

I figured it out!

It was not the time, but instead it was the hmac key. I was using APP_KEY as key, but the perl script is using sha1_ws_pwd + sha1_user_pwd. (so that was a stupid mistake...)

my $hmac = Digest::HMAC_SHA1->new($sha1_ws_pwd . $sha1_user_pwd);

Finally i also had to lower case the auth in C#. So the change in C# was:

// sha1 hash the passwords
string sha1_ws_pwd   = System.Convert.ToBase64String(sha1.ComputeHash(enc.GetBytes(ws_password)));
string sha1_user_pwd = System.Convert.ToBase64String(sha1.ComputeHash(enc.GetBytes(user_pwd)));

…

string k0 = sha1_ws_pwd + sha1_user_pwd;
HMACSHA1 hmac = new HMACSHA1(enc.GetBytes(k0));

…

string auth = BitConverter.ToString(_auth).Replace("-", string.Empty).ToLower(); 

Thank you for your time and answers.

Asger
  • 1
  • 1