The updated Handelsbanken app for Android and iPhone uses a new API with a new login method. The login method attempts to increase security by obfuscating some of the data. The custom keyboard matrix for example is sent as an image instead of clear text.
This might make things appear more secure to the end user but doesn’t provide any significant technical security benefits.
The following example will demonstrate how the new login method works.

Request to get the custom keyboard

GET /app/init-matrix-xml?height=600&width=628 HTTP/1.1
Cache-Control: no-transform
X-SHB-DEVICE-CLASS: app
User-Agent: Mozilla/5.0 (Linux; U; Android 4.0.2; sv-; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
X-SHB-DEVICE-MODEL: AND-4.0.2, 2.0.2, Galaxy Nexus
X-SHB-MCC: 240
X-SHB-MNC: 02
X-SHB-LC:
X-SHB-APP-VERSION: 2.0
X-SHB-DEVICE-ID: 123456789012345
Host: m2.handelsbanken.se
Connection: Keep-Alive

This is the first request that is sent to SHB when a user attempts to login. The height and width parameters define the desired size of the keyboard image returned in the response.

All headers starting with X-SHB are sent with every request and mostly contain information about the device that performs the request.

The keyboard matrix response

HTTP/1.1 200 OK
Date: Sat, 25 Feb 2012 20:56:29 GMT
Server: Apache
Cache-Control: private, proxy-revalidate
Content-Language: en-US
Connection: close
Content-Type: text/html;charset=UTF-8
Content-Length: 10517

<?xml version="1.0" encoding="utf-8"?>
    <response code="000" label="OK" >
        <matrix>
            <matrixId>009013526</matrixId>
            <matrixMetaData>0,5,7,11,13,14</matrixMetaData>
            <image type="png">
                <![CDATA[ ... base64 encoded png data, example below ... ]]>
            </image>
        </matrix>
    </response>

What we’re looking for in the response is the matrixId tag (we’ll need to send it back to the api when we’re logging in) and the image tag.

matrixMetaData tells the Android/iPhone app which buttons on the custom keyboard to make clickable. Not very interesting to us so we’ll disregard it.

Mapping a password to matrix positions

The image tag contains a base64 encoded transparent png image and looks something like this:

SHB custom keyboard
The image represents a 44 matrix where the numbers 0 to 9 have been placed randomly, the remaining 6 positions are empty.
When a user enters a password their real password isn’t sent to the api, instead the indices of the selected numbers (in a transposed 4
4 matrix) are sent as a concatenated string.
Let’s say the users password is 1234 and we’ve extracted the following matrix from the image:

968 40 7 52 31

Now the only thing that remains to do is to pick out the corresponding index for every number from the matrix below and send it to the api together with the username and matrixId.

04812 15913 261014 371115

The user enters the password 1234 and we get the positions 11,14,3,1.

Login request

GET /bb/glss/servlet/ssco_auth4?deviceid=123456789012345&username=8001010000&matrixPos=11,14,3,1&matrixId=009013526&entryId=privpnrpinse&appAction=doAuthentication&JSP_PATH=ssse&language=sv&country=SE&deviceClass=app HTTP/1.1
Cache-Control: no-transform
X-SHB-DEVICE-CLASS: app
User-Agent: Mozilla/5.0 (Linux; U; Android 4.0.2; sv-; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
X-SHB-DEVICE-MODEL: AND-4.0.2, 2.0.2, Galaxy Nexus
X-SHB-MCC: 240
X-SHB-MNC: 02
X-SHB-LC:
X-SHB-APP-VERSION: 2.0
X-SHB-DEVICE-ID: 123456789012345
Host: m2.handelsbanken.se
Connection: Keep-Alive

We’re almost there! But first a short description of some of the parameters:
deviceid - the device id from your Android/iPhone. Should be the same as the one in the header.
username - the users’ social security number in the format YYMMDDXXXX.
matrixPos - the positions of the numbers we calculated earlier.
matrixId - the same id that we got from our first request to the api.

Login response

HTTP/1.1 200 Document follows
Date: Sat, 25 Feb 2012 20:58:41 GMT
Server: Apache
Cache-Control: private, proxy-revalidate, no-cache="set-cookie, set-cookie2"
Accept-Ranges: bytes
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Content-Language: en-US
Set-Cookie: JSESSIONID=0000Y4saPX4Aq_tCypur61bkzki:C4F1745366942536000007A8000098D000000000; Path=/
Content-Length: 226
Last-Modified: Sat, 25 Feb 2012 20:58:40 GMT
Connection: close
Content-Type: text/xml;charset=UTF-8

<response code="X8005" label="Kontrollera dina uppgifter. Efter tre felaktiga kodförsök spärras koden. I Internettjänsten kan du byta din kod om den har blivit spärrad. Alternativt kan du kontakta närmaste bankkontor."/>

Yea… well I don’t have a SHB account (yet) so I couldn’t get any further than this. I’ll update this post with more information about the API when I get my login credentials from SHB.