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:

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 44 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:
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.
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.