SCRAM over SASL for SkySpark v318th May 2017

I recently implemented SCRAM (SHA-256) over SASL for SkySpark v3 so I could use the REST API.

SkySpark v3 sports a new authentication algorithm that must be used to communicate with it. But alas there is not much available that succinctly explains how it works.

What I did find though, was a bucket load of specifications and documentation that were as cryptic as the authentication mechanism itself!

So now I present to you, what would have been extremely helpful to me, a fully worked authentication conversation with SkySpark for SCRAM (SHA-256) over SASL.

Overview

All the authentication documentation for SkySpark v3 talks of SCRAM SHA-256, or Salted Challenge Response Authentication Mechanism (SCRAM) with SHA-256. SCRAM defines how to encode an authentication message to send to the server. It uses the PBKDF2 algorithm from the Public-Key Cryptography Standards (PKCS).

Simple Authentication and Security Layer (SASL) then defines a protocol of how to send / receive these authentication messages.

These SASL messages are then wrapped up in HTTP headers and the HTTP request is sent as usual.

If you want the low down on all of the above, here are links to the relevant parts of the specifications:

The Project Haystack and SkySpark documentation do have a sample client / server conversation (the SASL part), but they make no attempt to explain how they calculated the values and the given messages (the SCRAM part)!

1. Hello!

The first request is to initiate the authentication conversation, sending the username we wish to authenticate as.

Note that the URL we authenticate against needs to be a real URL lest we get a 404. It also needs to be one that we're not going to be redirected from. Project specific URLs are fine, but for general purpose usage I find that /ui works well in all scenarios.

The username is just our username user Base64 encoded. But note the lack of trailing = characters that are usually used for padding. That's because the Authorization header uses Base64 URIs, which lack the padding.

SkySpark replies with the above, which tells us we're to use SHA-256 for all our encoding. In general Project Haystack mechanisms this could also be SHA-1 or SHA-512.

The handshakeToken is used by the server to keep track of the authentication conversation, similar to a session cookie. So we need to make sure we pass the same value back. (Just ignore the fact it looks like our encoded username - this may change!)

2. First Message

Send an authentication request to the server.

In the request we name the user we wish to authenticate as, and a nonce. The nonce is random sequence of characters and should be of cryptographic strength.

3. Second Message

Send an encoded message that proves we have the password. This is hard part.

First we do the cryptographic stuff. Most languages have classes or libraries for doing this. Fantom uses Java's javax.crypto.spec.PBEKeySpec. Because we're using the SHA-256 hashing algorithm, we use PBKDF2WithHmacSHA256.

The xor() method is an annoying little thing where each byte of each input have to be xored together. It is not a native Fantom function, but instead a method you have to write yourself. See Fantom Code for more details.

It is the clientFinal string that we send to the server in the next message. Like last time, we Base64 URI encode it and send it as the data attribute of the Authorization header:

It is the authToken attribute that we're after. We can use in all subsequent HTTP requests to communicate with SkySpark.

But before we do; how do we know we're communicating with the correct server? How do we know our requests aren't be re-routed to some hackers server? Well now is our chance to validate the server and check that it also knows the user's password.

Base64 decoding the data attribute gives us:

v=TzqJVW8nNngZ9g1b/YWiO8s/ZlHqBL2op1blR7KqdmE=

If the server truly knows the user's password then we should be able to compute the same value for v.