Atom WSSE Authentication Using C# .NET

I received an email asking for a hand with a C# .NET implementation of the WSSE atom authentication for Nokia’s Lifeblog.

I took a look at this as I’m brushing up on my C# at the moment for work, and I relish a challenge.

As there are two different methods of authentication depending on the version of Lifeblog being used, the code has to handle this.

The first method is to append the nonce, timestamp and password together, create a SHA1 hash with this and Base64 encode the result. The second way is almost the same, but the nonce has to be Base64 decoded first before being appended with the timestamp and password.

See my previous article on WSSE Authentication For Atom Using Perl for more details on how this works.

The first method can be calculate a digest value using code like this.

string mystring = nonce + created + password;
SHA1Managed SHhash = new SHA1Managed();
string mydigest = Convert.ToBase64String(SHhash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(mystring)));

My first attempt at the second method looked very similar.

string mystring = (System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(nonce))) + created + password;
SHA1Managed SHhash = new SHA1Managed();
string mydigest = Convert.ToBase64String(SHhash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(mystring)));

Looks OK on the surface, but it fails to validate when posting from my Nokia N93 phone.

What’s gone wrong?

Well looking in the debugger, the process of converting the nonce back from the array of bytes Convert.FromBase64String() produces and appending them to form mystring corrupts the data compared with the Perl version in my previous article.

We know the approach is basically right, so we need to cut out this corrupting step.

The best way to do this is to keep the data in byte arrays as we need the data in this format anyway to computer the SHA1.


System.Text.Encoding enc = System.Text.Encoding.UTF8;
byte[] noncebytes = enc.GetBytes(nonce);
byte[] passwordbytes = enc.GetBytes(password);
byte[] createdbytes = enc.GetBytes(created);
byte[] code = new byte[nonce.Length + password.Length + created.Length];
Array.Copy(nonce, code, nonce.Length);
Array.Copy(created, 0, code, nonce.Length, created.Length);
Array.Copy(password, 0, code, nonce.Length + created.Length, password.Length);
System.Security.Cryptography.SHA1Managed SHhash = new System.Security.Cryptography.SHA1Managed();
string digest = Convert.ToBase64String(SHhash.ComputeHash(code));

I’m sure there is a nicer way to achieve the appending of the 3 arrays together in C#, but this works for now.

We can tie this up to form a nice static class to handle our WSSE authentication.

/// <summary>
/// Computes WSSE codes from input for validation.
/// </summary>
public static class WSSE {
/// <summary>
/// Calculate the digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigest(string password, string nonce, string created)
{
return GetDigest(password, nonce, created, System.Text.Encoding.ASCII);
}
/// <summary>
/// Calculate the digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="enc">The System.Text.Encoding to use.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigest(string password, string nonce, string created, System.Text.Encoding enc)
{
byte[] noncebytes = enc.GetBytes(nonce);
byte[] passwordbytes = enc.GetBytes(password);
byte[] createdbytes = enc.GetBytes(created);
return generatecode(noncebytes, passwordbytes, createdbytes);
}
/// <summary>
/// Calculate the alternative digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigestAlt(string password, string nonce, string created)
{
return GetDigestAlt(password, nonce, created, System.Text.Encoding.ASCII);
}
/// <summary>
/// Calculate the alternative digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="enc">The System.Text.Encoding to use.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigestAlt(string password, string nonce, string created, System.Text.Encoding enc)
{
byte[] noncebytes = Convert.FromBase64String(nonce);
byte[] passwordbytes = enc.GetBytes(password);
byte[] createdbytes = enc.GetBytes(created);
return generatecode(noncebytes, passwordbytes, createdbytes);
}
private static string generatecode(byte[] nonce, byte[] password, byte[] created)
{
byte[] code = new byte[nonce.Length + password.Length + created.Length];
Array.Copy(nonce, code, nonce.Length);
Array.Copy(created, 0, code, nonce.Length, created.Length);
Array.Copy(password, 0, code, nonce.Length + created.Length, password.Length);
System.Security.Cryptography.SHA1Managed SHhash = new System.Security.Cryptography.SHA1Managed();
return Convert.ToBase64String(SHhash.ComputeHash(code));
}
/// <summary>
/// Validates password, nonce and created create the same digest code as digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="digest">The digest to validate the password, nonce and created strings against as a string.</param>
/// <returns>true or false depending on wether the digest validates</returns>
public static bool IsValid(string password, string nonce, string created, string digest)
{
return digest == GetDigest(password, nonce, created) || digest == GetDigestAlt(password, nonce, created);
}
/// <summary>
/// Validates password, nonce and created create the same digest code as digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="digest">The digest to validate the password, nonce and created strings against as a string.</param>
/// <param name="enc">A System.Text.Encoding encoding.</param>
/// <returns>true or false depending on wether the digest validates.</returns>
public static bool IsValid(string password, string nonce, string created, string digest, System.Text.Encoding enc)
{
return digest == GetDigest(password, nonce, created, enc) || digest == GetDigestAlt(password, nonce, created, enc);
}
}

We can test the code using the following code snippet.

string digest = "nvvHvNuLb+7wGFrop+cC2tjgQqs=";
string nonce = "bgZ4BHcjmWcg7gVhCxyQOg==";
string timestamp = "2006-04-25T19:40:45Z";
string password = "a";
if (WSSE.IsValid(password, nonce, timestamp, digest, System.Text.Encoding.UTF8))
{
Console.WriteLine("valid");
}
else
{
Console.WriteLine("invalid");
}

This gives us the result “valid” as we’d hope.

To save you time, feel free to download the C# code
WSSE.cs.

Programming Bluetooth Using Python

I discovered the pybluez project that brings bluetooth connectivity to Python today. It’s been around for a while and is compatible with both Windows (running XP) and Linux (running the bluez stack).

I installed it using the ready made windows installer and it ran first time. It’s very simple and easy to use.

I tweaked the example inquiry.py file by Albert Huang and set it up to show all the services on nearby devices.

Here’s the code…

import bluetooth
print "looking for nearby devices..."
nearby_devices = bluetooth.discover_devices(lookup_names = True, flush_cache = True, duration = 20)
print "found %d devices" % len(nearby_devices)
for addr, name in nearby_devices:
print " %s - %s" % (addr, name)
for services in bluetooth.find_service(address = addr):
print " Name: %s" % (services["name"])
print " Description: %s" % (services["description"])
print " Protocol: %s" % (services["protocol"])
print " Provider: %s" % (services["provider"])
print " Port: %s" % (services["port"])
print " Service id: %s" % (services["service-id"])
print ""
print ""

Here’s a quick run through of the code.

Firstly we need to import the bluetooth class to give us access to all that lovely bluetooth functionality.

We now look for nearby devices using bluetooth.discover_devices. I’m adding a few parameters as well. lookup_names is set to True so we can get the devices names instead of the just their addresses, and flush_cache is also set to True to make sure we always look for fresh information. Finally we set duration to 20, meaning we look for devices for up to 20 seconds. This is a bit excessive, but useful when testing.

We should have a list of devices now, assuming some were found, so we now loop over them.

We print out the name and address then look for services offered by the device by calling the bluetooth.find_service method and passing in the device’s address.

This returns a list of dictionaries describing the services available. We iterate over this and print out details.

That’s the code, now here’s a few results. I ran this on the train home and discovered 7 active bluetooth devices offereing a variety of services. I won’t bore you with them all, so here’s the entry for my Nokia N93.

Perl - 00:16:BC:30:D8:76
Name:        AVRCP Target
Description: Audio Video Remote Control
Protocol:    L2CAP
Provider:    Symbian Software Ltd.
Port:        23
Service id:  None
Name:        Hands-Free Audio Gateway
Description:
Protocol:    RFCOMM
Provider:    None
Port:        28
Service id:  None
Name:        Headset Audio Gateway
Description:
Protocol:    RFCOMM
Provider:    None
Port:        29
Service id:  None
Name:        SyncMLClient
Description:
Protocol:    RFCOMM
Provider:    None
Port:        10
Service id:  None
Name:        OBEX File Transfer
Description:
Protocol:    RFCOMM
Provider:    None
Port:        11
Service id:  None
Name:        Nokia OBEX PC Suite Services
Description:
Protocol:    RFCOMM
Provider:    None
Port:        12
Service id:  None
Name:        SyncML DM Client
Description:
Protocol:    RFCOMM
Provider:    None
Port:        13
Service id:  None
Name:        Nokia SyncML Server
Description:
Protocol:    RFCOMM
Provider:    None
Port:        14
Service id:  None
Name:        OBEX Object Push
Description:
Protocol:    RFCOMM
Provider:    None
Port:        9
Service id:  None
Name:        Dial-Up Networking
Description:
Protocol:    RFCOMM
Provider:    None
Port:        2
Service id:  None
Name:        Imaging
Description:
Protocol:    RFCOMM
Provider:    None
Port:        15
Service id:  None

As you can see it offers a lot of interesting services, but two have caught my eye and call for a bit more investigation later.

Firstly there is the Imaging service on port 15. I wonder what that does? Does it take input from a remote camera?

Secondly there is AVRCP Target the Audio Visual Remote Control Target from Symbian. I wonder if this means I can use a seperate bluetooth device to control my Nokia N93 when it’s playing back video?

A quick google reveals a (confidential?) specification document for AVRCP

Nokia Lifeblog Posting Protocol Update

Nokia seem to have updated their Atom upload protocol in recent versions of their phones.

I’ve just got hold of a Nokia N93 and tried posting to this blog using Lifeblog and the new Web Upload functionality in the Gallery with use the Atom protocol.

These postings were failing with a bad password error. I know my username and password are correct and they worked using my old phone.

As I had written my own blogging software, and it’s Atom upload functionality I was able to debug the messages being sent from the phone to the server.

It turns out that newer versions of Nokia Lifeblog encrypt their passwords differently to older versions.

They use a method called WSSE. See my previous article on how to use WSSE with Perl for more details on how this works, plus example code.

Very quickly, the password isn’t sent, but a digest of the password and the values to generate the digest yourself are. These are then encoded using base64 for transmission over the internet.

Older versions (pre Lifeblog 2.0) expect a value called the nonce to be used as sent while the password digest is generated. Newer versions (Lifeblog 2.0+) expect the nonce to be decoded from base64 before the digest is generated.

Once I had worked out what was going on, it was simple to modify my code to check against both possible versions of the password digest. This means I can now post using old and new versions of Lifeblog, or the web upload functionality.

Here’s a very quick bit of example Perl code. Assume $my_digest is the digest with the original nonce left in place and $my_alternative_digest is the digest with the nonce decoded first. $digest is the digest sent my incoming Atom request.

## example perl code to check digests)
if (($digest eq $my_digest) || ($digest eq $my_alternative_digest)) {
## one of the digests has validated, so continue here
} else {
## neither digests has validated, so return invalid password responses here.
}

I don’t think this change has been communicated very well amongst the development community. It has probably come about due to changes in the Atom spec, but (admittedly only quickly) checking the documentation I’ve not found it.

I will be updating my WSSE validation example accordingly, and a new version of AtomServer.pm that allows posting from Lifeblog 2.0 to Movable Type shortly.

Posting To Movable Type 3.3 Using Nokia Lifeblog

We’ve been installing Movable Type as a blogging solution at work for various sites recently.

We’d been using Typepad, the hosted version of Movable Type for a while, but wanted some extra flexibility and functionality.

One problem we came across was the lack of support for Nokia Lifeblog on Movable Type, compared to Typepad.

Thankfully Martin Higham has worked on this in the past, and even used my old notes on the Nokia Lifeblog Posting Protocol.

However, the current version of Movable Type is 3.3, and Martin’s work only extends to 3.2.

I took Martin’s code, which modifies AtomServer.pm and modified it so it works on Movable Type 3.3. You can download my Nokia Lifeblog compatible AtomServer.pm for Movable Type 3.3 here.

Make sure you follow Martin’s instructions for Movable Type 3.2 as the method is exactly the same and the same caveats apply (namely, this could well break other Atom tools that use your blog as it has to disable some WSSE authentication).

I hope you find it useful!

UPDATE: 22nd November 2006

With version 2.0 of Lifeblog and web upload functionality from Nokia phones, the authentication method has changed slightly. A new version of AtomServer.pm that works with Lifeblog 2.0 is now available.

UPDATE: 26th June 2007

Neils Berkers has been in touch to say he’s adapted the script so it now works with Movable Type 3.35, Lifeblogging Fixed.

Interesting Nokia Lifeblog Bug

Now here’s an interesting bug in Nokia Lifeblog application on my Nokia 3230 phone.

If you take a photo using the camera and then post it to the web using Lifeblog, it won’t then let you send the image via MMS. Instead, it complains “unable to send copyright protected item”, even though I own the copyright of my own picture.

This is running version 1.51.2 of the Lifeblog software.

Using Series 60 Python To Talk To A Webserver

I’ve been continuing my journey into Python by modifying my earlier location script to now post details to my website when run.

I’m using the standard urllib now and moving to slightly more advanced Python language features such as dictionaries (basically the equivalent of a Perl hash).

The code gets the location, calls a CGI script on my website and prints the returned message from that script to the console.

Here’s the code…

# we need access to the location and urllib modules so have to
#import them.
import location
import urllib
# get the mmc, mnc, lac and cellid by calling the gsm_location
# method from the location module.
(mmc, mnc, lac, cellid) = location.gsm_location()
# add the location to a python dictionary called params.
params = urllib.urlencode({'mmc': mmc, 'mnc': mnc, 'lac': lac, 'cellid': cellid})
# open a filehandle to a cgi tracking script that takes
# the contents of dictionary params as parameters.
f = urllib.urlopen("http://www.robertprice.co.uk/cgi-bin/test/cellid.pl?%s" % params)
# get the results, hopefully a message saying OK.
print f.read()

All the CGI script on my website does is to record the parameters passed to it and return a simple text string saying it ran OK.

As you can see it’s really simple to Series 60 Python to communicate over the phone’s network connection. I have to say, this language is turning out to be better than I had expected, and far easier than J2ME.

My First Python Script

It’s a full day since I started to try to teach myself Python for my Nokia 3230 phone.

My first script is running, and though it isn’t anything impressive, I’m still very pleased with the results.

So what is this amazing script? Well it just gets the current location of the phone by CellID, using the location module supplied with Python, and displays it on the console.

Here’s the code…

# we need access to the location module so have to import it.
import location
# get the mmc, mnc, lac and cellid by calling the gsm_location
# method from the location module.
(mmc, mnc, lac, cellid) = location.gsm_location()
# print out the retrieved details to the console.
print "mmc %sn" % mmc
print "mnc %sn" % mnc
print "lac %sn" % lac
print "cellid %sn" % cellid

screenshot of the python location script results
As you can see it’s not going to win any prizes at PyCon, but it does provide some very practical information for me, namely my location.

But what are those 4 variables returned?

  • MCC = Mobile Country Code
  • MNC = Mobile Network Code
  • LAC = Location Area Code
  • Cell ID = The Cell’s ID 🙂

Stay tuned for more Python adventures over the coming weeks.