public Protocol Authenticate(string username, string password) { /* Number of authentication tries. */ int tries = 3; /* Set username and password. */ this._username = Encoding.UTF8.GetBytes(username); this._password = Encoding.UTF8.GetBytes(password); while (true) { /* Connect to a spotify server. */ this._protocol.Connect(); /* Send and receive initial packets. */ try { this._protocol.SendInitialPacket(); this._protocol.ReceiveInitialPacket(); break; } catch (ProtocolException e) { if (tries-- > 0) { continue; } throw new AuthenticationException(e); } } /* Generate auth hash. */ this.GenerateAuthHash(); /* Compute shared key (Diffie Hellman key exchange). */ this._dhSharedKey = DH.ComputeSharedKey(this._dhClientKeyPair.PrivateKey, this._dhServerPublicKey); /* Prepare a message to authenticate. */ ByteBuffer buffer = ByteBuffer.Allocate(((this._authHash.Length + this._clientRandom.Length) + this._serverRandom.Length) + 1); /* Append auth hash, client and server random to message. */ buffer.Put(this._authHash); buffer.Put(this._clientRandom); buffer.Put(this._serverRandom); buffer.Put((byte)0x00); /* Changed later */ buffer.Flip(); /* Get message bytes and allocate space for HMACs. */ byte[] bytes = new byte[buffer.Remaining]; byte[] hmac = new byte[5 * 20]; int offset = 0; buffer.Get(bytes); /* Run HMAC SHA-1 over message. 5 times. */ for (int i = 1; i <= 5; i++) { /* Change last byte (53) of message. */ bytes[bytes.Length - 1] = (byte)i; /* Compute HMAC SHA-1 using the shared key. */ Hash.HmacSha1(bytes, this._dhSharedKey, hmac, offset); /* Overwrite first 20 bytes of message with output from this round. */ for (int j = 0; j < 20; j++) { bytes[j] = hmac[offset + j]; } /* Advance to next position. */ offset += 20; } /* Use field of HMACs to setup keys for Shannon stream cipher (key length: 32). */ Array.Copy(hmac, 20, this._keySend, 0, 32); Array.Copy(hmac, 52, this._keyRecv, 0, 32); /* Set stream cipher keys. */ this._shannonSend.key(this._keySend); this._shannonRecv.key(this._keyRecv); /* * First 20 bytes of HMAC output is used to key another HMAC computed * for the second authentication packet send by the client. */ Array.Copy(hmac, 0, this._keyHmac, 0, 20); /* Solve puzzle */ this.SolvePuzzle(); /* Generate HMAC */ this.GenerateAuthHmac(); try { this._protocol.SendAuthenticationPacket(); this._protocol.ReceiveAuthenticationPacket(); } catch (ProtocolException e) { throw new AuthenticationException(e); } return(this._protocol); }