Skip to content
Alban LEROUX edited this page Feb 26, 2012 · 9 revisions

Authentification

A quick introduction

Trust is a difficult part in web communication. Both party need to be sure of:

  • Who is speaking to.
  • Validity of the content exchanged.
  • Keep this insurance during the whole exhange.

This protocol try to respond to that problem.

Algorithms

  • Salt = R( Timestamp / Lifetime ) * Lifetime
  • Hash = K( Password )
  • Secret = K( Username Hash Key )
  • Token = K( Challenge Secret Salt )
  • H(Data) = K( Nonce Data Secret )
  • S(Data) = K( Token Data Secret )
  • L(Data) = serialize(Data)

NOTE:

  • S(X) is called the X signature.
  • H(X) is called the X hmac.
  • K(X) is the MD5 hash of X.
  • R(X) is the next highest integer value by rounding up X — aka ceil() in some programming language.
  • L(X) is the serialization of the data, see above in documentation the serialization algorithm.

The protocol

1: And that's the beginning...

We use a Username for tell who we are trying to authenticate.

We use use your Password and a Key. Both are use to create a strong Secret.

We use a Timestamp. Always usefull to locate things in time.

You already known:

Timestamp = 1329866347
Username  = Anthony
Password  = aQe4vdf
Key       = 6fe74546dfa5d730ce5cdfc02fe19dd4

And you are able to calculate:

Hash      = 64257f8b35c6783f824f407bd0bd8825
Secret    = a9283746b094e03e17e4e584fc6a9d8a

2: Solve the challenge...

To authenticate yourself, you have to resolve a Challenge provided by the server: Calculate an authentication Token. This token can be calculated only if you know a Secret. This secret is only known by you and the server.

So only you and the server can calculate that token. Tokens have a Lifetime, by creating a Salt with help of Timestamp and using it in the token generation, tokens have a limited usage in time.

Call API auth.request:

>>	Username  = Anthony
<<	Lifetime  = 300
<<	Challenge = 2c07899ba4d1b28d70c75a767a0a38c0

And you are able to calculate:

Time         = 1329866400
Token        = 7ed52e0636229a210eea607f7fbf5f10
S(Challenge) = 7ba3d30b361a659fa135307aeaaa9502

3: Prove you are yourself...

Be able to calculate a token proves you know the shared secret, or, once that the token has been transmitted through the web, you're able to intercept this token.

To ensure each part is who he pretend to be, Signature helps.
By signing a content, you prove that you know the shared secret and that you know the authentication token.

So, before use the authentication token in its rôle. Both parts exchange a signature. The client signs the challenge, send it and in the reply, the server signs the nonce provided in the reply.

Each part can verify the signature that he receives and now is sure to talk with the good person.

Call API auth.token:

>>  Challenge    = 2c07899ba4d1b28d70c75a767a0a38c0
>>	S(Challenge) = 7ba3d30b361a659fa135307aeaaa9502
<<  Nonce        = d41d8cd98f00b204e9800998ecf8427e
<<	S(Nonce)     = 303893e7d2e4f29b04f71798887d0720

4: Keep this security...

During the communication, it is important that no one modifies or replays a message by using your token.

So, after the authentication, each message have a Hmac. This time, this is the message which is signed. Hmac ensure that the message is not modified during the communication and that's really you who sending the message.

Hmac is calculate with a Nonce. You get a new Nonce at each valid request in the server's reply. This Nonce protect against a replay attack.

HMAC calculation in request

Assume that req.method and req.request are respectively the method and request content of the request

hmac = H(req.method L(req.request))

HMAC calculation in response

Assume that rep.nonce and rep.response are respectively the nonce and response content of the response

hmac = H(rep.nonce L(rep.response))

Serialization Algorithm

Better than long explanation, here we provided a PHP example. This serialization is like json format.

function serialize(array $data = array())
{
	$serial = '';

	foreach($data as $key => $val)
	{
		if (!is_scalar($val))
		{
			$val = $this->serialize((array) $val);
		}

		if (is_bool($val))
		{
			$val = $val ? 'true' : 'false';
		}

		$serial .= sprintf('%s:%s,', $key, $val);
	}

	return sprintf('{%s}', $serial);
}

format of authenticated dialog

Request

{
	"method"    : "photo.version",
	"token"     : "5f15896d48ad3b0b6c033d769753734a",
	"hmac"      : "fa10c4d7b02a13e27a2ae5a5bbe8130b",
	"request"   : ""
}

Response

{
	"status"   : "valid",
	"hmac"     : "ef30c4d7b02a13e27a2ae5a5bbe0129f",
	"nonce"    : "8ad52e0636229a210eea607f7fbf542c",
	"response" :
	{
		"version" : 0.0.1
	}
}

Token end of life

When a token is too old. You can use the api auth.refresh.

This api method can be called whenever you want. It changes token and nonce authentication. To validate the new token and the nonce you have to calculate the new token, sign it, send the refresh request.
In reply, you receive a nonce signed by the new token. If the signature checking succeed, you knows that now the server have the same new token as you.

NOTE:

You don't have to always check if you're token is too old. When you send a request with a such token. You got in reply a error code old_token. Then you knows you should call now auth.refresh before send again you request.

Specials notes

When you uses query method (GET or POST) for calling the api, you need to pass the authentication data as extra parameters. Here is an example:

	GET http://example.com/api/get/auth.config.set/json/token:5f15896d48ad3b0b6c033d769753734a/hash:fa10c4d7b02a13e27a2ae5a5bbe8130b/?lifetime=30

client example

A PHP api client can be found here: [https://gist.github.com/1917812]

Here a example of how use it:

<?php

require_once 'api_client.php'; // https://gist.github.com/1917812

class api_client extends Pixelpost_Api_Client
{
	const API_URL  = 'http://localhost/pp/api/';
	const USERNAME = 'Alban';
	const PASSWORD = '123456';
	const PRIV_KEY = '6fe74546dfa5d730ce5cdfc02fe19dd5';
}

$c = new api_client();

$response = $c->request('auth.config.set', array('lifetime' => 30));

echo $response->message; // configuration updated

?>

Clone this wiki locally