Recently, I was able to get MD5 authentication working for XMPP streams in Swift IOS following the instructions on the following two websites (I used the CC-MD5 function of Apple's CommonCrypto C library for the actual hashing):
http://wiki.xmpp.org/web/SASLandDIGEST-MD5
http://www.deusty.com/2007/09/example-please.html
I'm searching for a similar explanation for how to get other hashed SASL authentication schemes working, especially SCRAM-SHA1. I have found the official RFC5802 document but I'm having a lot of trouble understanding it (it is not specific to XMPP either). I would appreciate a simpler explanation or some simple readable code (C, PHP, C++, Javascript, Java) specific to XMPP authentication that doesn't use libraries for anything other than the actual hashing.
I'm interested in understanding the process and am not looking to use the ios XMPP-Framework. Any help would be appreciated.
SCRAM-SHA-1
The basic overview of how this mechanism works is:
The cryptographic algorithms you'll need are SHA-1, HMAC with SHA-1 and PBKDF2 with SHA-1. You should look up how to use them in your language/framework, as I don't recommend implementing them from scratch.
In detail
normalizedPassword
. This is to ensure the UTF8 encoding can't contain variations of the same password.clientNonce
.initialMessage
is"n=" .. username .. ",r=" .. clientNonce
(I'm using..
for string concatenation).The client prepends the GS2 header (
"n,,"
) to the initialMessage and base64-encodes the result. It sends this as its first message:The server responds with a challenge. The data of the challenge is base64 encoded:
The client base64 decodes it:
The client parses this:
r=
This is theserverNonce
. The client MUST ensure that it starts with theclientNonce
it sent in its initial message.s=
This is thesalt
, base64 encoded (yes, this is base64-encoded twice!)i=
This is the number of iterations,i
.The client computes:
The client base64 encodes the
clientFinalMessage
and sends it as a response:If everything went well, you'll get a
<success>
response from the server:Base64 decoded this contains:
The client MUST make sure the value of
v
is the base64 encoding of theserverSignature
.Extras
This is the basic version of the algorithm. You can extend it to do:
Hashed storage. If the server always sends the same
salt
andi
values, then the client can store onlysaltedPassword
instead of the user's password. This is more secure (as the client doesn't need to store the password, just a hard to reverse salted hash) and faster, as the client doesn't need to do all the key stretching every time.The server can also use hashed storage: the server can store only
salt
,i
,storedKey
andserverKey
. More info on that here.Pitfalls
Some common pitfalls:
salt
(though if you generate them, make sure they are long enough and cryptographically random).salt
is base64 encoded and can contain any data (embeddedNUL
s).initialMessage
part of theauthMessage
does not include the GS2 header (in most situations, this is"n,,"
).Test vectors
If you want to test your implementation, here are all the intermediate results for the example from the RFC:
Username:
user
Password:
pencil
Client generates the random nonce
fyko+d2lbbFgONRv9qkxdawL
Initial message:
n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
Server generates the random nonce
3rfcNHYJY1ZVvWVs7j
Server replies:
r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
The salt (hex):
4125c247e43ab1e93c6dff76
Client final message bare:
c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
Salted password (hex):
1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d
Client key (hex):
e234c47bf6c36696dd6d852b99aaa2ba26555728
Stored key (hex):
e9d94660c39d65c38fbad91c358f14da0eef2bd6
Auth message:
n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
Client signature (hex):
5d7138c486b0bfabdf49e3e2da8bd6e5c79db613
Client proof (hex):
bf45fcbf7073d93d022466c94321745fe1c8e13b
Server key (hex):
0fe09258b3ac852ba502cc62ba903eaacdbf7d31
Server signature (hex):
ae617da6a57c4bbb2e0286568dae1d251905b0a4
Client final message:
c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
Server final message:
v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
Server's server signature (hex):
ae617da6a57c4bbb2e0286568dae1d251905b0a4