void ServerAuthModule::OnMessageVerifyClient(RawMessage& rawMessage)
{
   if (m_bIsVerifiedClient)
      throw AuthException(AuthException::authInternalError, _T("client already verified"), __FILE__, __LINE__);
   if (m_spServer == NULL)
      throw AuthException(AuthException::authInternalError, _T("server == NULL"), __FILE__, __LINE__);

   SRPAuthVerifyClientMessage verifyClientMessage;
   ConstVectorRefStream stream(rawMessage.Data());
   verifyClientMessage.Deserialize(stream);

   HighResolutionTimer timer;
   timer.Start();

   // check client; when failed, client doesn't know password
   TByteArray Ms;
   try
   {
      Ms = m_spServer->VerifyClient(verifyClientMessage.GetHc());
   }
   catch(std::runtime_error& ex)
   {
      throw AuthException(
         AuthException::authFailed, _T("couldn't verify client") + CString(ex.what()),
         __FILE__, __LINE__);
   }

   m_bIsVerifiedClient = true;

   // log
   CString cszText;
   cszText.Format(_T("verifying client took %u ms"), unsigned(timer.Elapsed()*1000.0));
   LOG_INFO(cszText, Log::Server::AuthSRP);

   // send server our hash
   SRPAuthVerifyServerMessage verifyServerMessage(Ms);
   SendMessage(verifyServerMessage);

   // get server session key
   TByteArray K = m_spServer->GetK();

   m_spServer.reset(); // no longer needed

   // set up RC4 encryption
   m_spEncryptModule.reset(new RC4::EncryptModule(K));
}
void ServerAuthModule::OnMessageAuthRequest(RawMessage& rawMessage)
{
   if (m_bIsVerifiedClient)
      throw AuthException(AuthException::authInternalError, _T("client already verified"), __FILE__, __LINE__);
   if (m_spServer != NULL)
      throw AuthException(AuthException::authInternalError, _T("server == NULL"), __FILE__, __LINE__);

   AuthRequestMessage authMessage;
   ConstVectorRefStream stream(rawMessage.Data());
   authMessage.Deserialize(stream);

   // get server infos
   ATLASSERT(m_fnGetServerAuthInfo != NULL);

   TByteArray vecPasswordKey, vecSalt;
   try
   {
      m_fnGetServerAuthInfo(authMessage.GetUsername(), vecPasswordKey, vecSalt, m_iAccountId);
   }
   catch(const Exception& ex)
   {
      LOG_WARN(_T("caught exception during GetServerAuthInfo(): ") + ex.Message(), Log::Server::AuthSRP);

      throw AuthException(
         AuthException::authFailed, _T("couldn't get auth info: ") + ex.Message(),
         __FILE__, __LINE__);
   }
   catch(...)
   {
      throw AuthException(
         AuthException::authFailed, _T("couldn't get auth info"), __FILE__, __LINE__);
   }

   HighResolutionTimer timer;
   timer.Start();

   SRP::GroupParameter gp = SRP::Helper::GetPresetGroupParameter(c_uiDefaultPresetGroupParameter);
   m_spServer.reset(new SRP::Server(gp));

   // generate b
   BigInteger b = SRP::Helper::GenerateRandomBits(1024);

   BigInteger PassVerifier = SRP::Helper::ToInteger<BigInteger>(vecPasswordKey);

   // calculate B
   BigInteger B = m_spServer->GetB(PassVerifier, b);
   TByteArray Bbin;
   SRP::Helper::ToBinaryData(B, Bbin);

   // calculate session key
   TByteArray Abin = authMessage.GetA();
   BigInteger A = SRP::Helper::ToInteger<BigInteger>(Abin);

   BigInteger s = SRP::Helper::ToInteger<BigInteger>(vecSalt);

   USES_CONVERSION;
   std::string strUsername(T2CA(authMessage.GetUsername()));

   m_spServer->CalcSessionKey(A, s, strUsername, PassVerifier);

   // log
   CString cszText;
   cszText.Format(_T("calculating session key took %u ms"), unsigned(timer.Elapsed()*1000.0));
   LOG_INFO(cszText, Log::Server::AuthSRP);

   // send response
   SRPAuthResponseMessage authResponseMessage(vecSalt, Bbin);
   SendMessage(authResponseMessage);
}