XMPP Authentication SASL SCRAM-SHA1

Recently, I was able to get MD5 authentication for XMPP streams in Swift IOS by following the instructions on the following two sites (I used the Apple CommonCrypto C library CC-MD5 function for the actual hash):

http://wiki.xmpp.org/web/SASLandDIGEST-MD5

http://www.deusty.com/2007/09/example-please.html

I am looking for a similar explanation of how to use other SASL hashing schemes, especially SCRAM-SHA1. I found the official RFC5802 document, but I have a lot of problems understanding it (this is not typical for XMPP). I would like a simpler explanation or simple readable code (C, PHP, C ++, Javascript, Java) specific to XMPP authentication that doesn't use libraries for anything other than actual hashing.

I am interested in understanding the process and do not want to use iOS XMPP-Framework. Any help would be appreciated.

+8
authentication xmpp sasl
source share
1 answer

SCRAM-SHA-1

A basic overview of the operation of this mechanism:

  • The client sends the username that wants to authenticate as.
  • The server sends back the salt for this user and the number of iterations (either generating them, or browsing them in his database for the given username).
  • The client sets a password with the specified salt for a given number of iterations.
  • The client sends the result back.
  • The server performs a hash variation and sends the result back to the client, so the client can also verify that the server had a password / password hash.

The cryptographic algorithms you will need are SHA-1, HMAC with SHA-1, and PBKDF2 with SHA-1. You should see how to use them in your language / framework, as I do not recommend them to implement them from scratch.

More details

  • First, normalize the password (using SASLprep ), this will be normalizedPassword . This is necessary so that the UTF8 encoding cannot contain changes to the same password.
  • Select a random string (for example, 32 hexadecimal bytes). This will be clientNonce .
  • initialMessage - "n=" .. username .. ",r=" .. clientNonce (I use .. to concatenate strings).
  • The client adds the GS2 header ( "n,," ) to the initial Message and base64 encodes the result. He sends this as his first message:

     <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="SCRAM-SHA-1"> biwsbj1yb21lbyxyPTZkNDQyYjVkOWU1MWE3NDBmMzY5ZTNkY2VjZjMxNzhl </auth> 
  • The server answers the call. The call data is encoded by base64:

     <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> cj02ZDQ0MmI1ZDllNTFhNzQwZjM2OWUzZGNlY2YzMTc4ZWMxMmIzOTg1YmJkNGE4ZTZmODE0YjQyMmFiNzY2NTczLHM9UVNYQ1IrUTZzZWs4YmY5MixpPTQwOTY= </challenge> 
  • Client base64 decodes it:

     r=6d442b5d9e51a740f369e3dcecf3178ec12b3985bbd4a8e6f814b422ab766573,s=QSXCR+Q6sek8bf92,i=4096 
  • The client analyzes this:

    • r= This is serverNonce . The client MUST ensure that it starts with the clientNonce that it sent in its original message.
    • s= This is the salt encoding, base64 (yes, this is the base64 encoding twice!)
    • i= This is the number of iterations, i .
  • The client calculates:

     clientFinalMessageBare = "c=biws,r=" .. serverNonce saltedPassword = PBKDF2-SHA-1(normalizedPassword, salt, i) clientKey = HMAC-SHA-1(saltedPassword, "Client Key") storedKey = SHA-1(clientKey) authMessage = initialMessage .. "," .. serverFirstMessage .. "," .. clientFinalMessageBare clientSignature = HMAC-SHA-1(storedKey, authMessage) clientProof = clientKey XOR clientSignature serverKey = HMAC-SHA-1(saltedPassword, "Server Key") serverSignature = HMAC-SHA-1(serverKey, authMessage) clientFinalMessage = clientFinalMessageBare .. ",p=" .. base64(clientProof) 
  • The base64 client encodes clientFinalMessage and sends it as a response:

     <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> Yz1iaXdzLHI9NmQ0NDJiNWQ5ZTUxYTc0MGYzNjllM2RjZWNmMzE3OGVjMTJiMzk4NWJiZDRhOGU2ZjgxNGI0MjJhYjc2NjU3MyxwPXlxbTcyWWxmc2hFTmpQUjFYeGFucG5IUVA4bz0= </response> 
  • If all goes well, you will receive a response from <success> from the server:

      <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> dj1wTk5ERlZFUXh1WHhDb1NFaVc4R0VaKzFSU289 </success> 
  • Base64 base decoding contains:

      v=pNNDFVEQxuXxCoSEiW8GEZ+1RSo= 
  • The client MUST verify that the value of v is base64 encoded by serverSignature .

Additionally

This is the basic version of the algorithm. You can expand it to do:

  • Linking channels. This mixes some information from the TLS connection with the procedure to prevent MitM attacks.
  • Hashing If the server always sends the same salt and i values, then the client can only store saltedPassword instead of the user password. This is more secure (since the client does not need to store a password, it is simply difficult to cancel the salty hash) and faster, since the client does not need to do all the key stretching every time.

    The server can also use hashed storage: the server can only store salt , i , storedKey and serverKey . Read more about it here .

  • Perhaps the addition of SCRAM-SHA-256 (although server support seems to be non-existent).

Trap

Some common mistakes:

  • Do not think about the length of nonces or salt (although if you create them, make sure they are long enough and cryptographically random).
  • salt is encoded by base64 and can contain any data (embedded NUL s).
  • Not using SASLprep may work fine for users using ASCII passwords, but it can completely upset registration for people using other scripts.
  • The initialMessage authMessage does not include the GS2 header (in most cases it is "n,," ).

Test vectors

If you want to test your implementation, here are all the intermediate results for an example from the RFC:

  • Username: user

  • Password: pencil

  • The client creates a random value nonce fyko+d2lbbFgONRv9qkxdawL

  • Original post: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL

  • Server generates random value nonce 3rfcNHYJY1ZVvWVs7j

  • Server responses: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096

  • Salt (hex): 4125c247e43ab1e93c6dff76

  • Final client message bare: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j

  • Salty password (hexadecimal): 1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d

  • Client key (hex): e234c47bf6c36696dd6d852b99aaa2ba26555728

  • Saved Key (hex): e9d94660c39d65c38fbad91c358f14da0eef2bd6

  • Error message: n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j

  • Client Signature (hex): 5d7138c486b0bfabdf49e3e2da8bd6e5c79db613

  • Client Certificate (Hex): bf45fcbf7073d93d022466c94321745fe1c8e13b

  • Server key (hexadecimal): 0fe09258b3ac852ba502cc62ba903eaacdbf7d31

  • Server Signature (hex): ae617da6a57c4bbb2e0286568dae1d251905b0a4

  • The final client message: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=

  • Final server message: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=

  • Server Server Signature (hex): ae617da6a57c4bbb2e0286568dae1d251905b0a4

+38
source share

All Articles