# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kdesasl.cpp

    00001 /* This file is part of the KDE libraries
    00002    Copyright (C) 2001-2002 Michael Häckel <haeckel@kde.org>
    00003    $Id: kdesasl.cpp 286962 2004-02-10 23:07:49Z porten $
    00004
    00005    This library is free software; you can redistribute it and/or
    00006    modify it under the terms of the GNU Library General Public
    00007    License version 2 as published by the Free Software Foundation.
    00008
    00009    This library is distributed in the hope that it will be useful,
    00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012    Library General Public License for more details.
    00013
    00014    You should have received a copy of the GNU Library General Public License
    00015    along with this library; see the file COPYING.LIB.  If not, write to
    00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00017    Boston, MA 02111-1307, USA.
    00018 */
    00019
    00020 #include "kdesasl.h"
    00021
    00022 #include <kmdcodec.h>
    00023 #include <kurl.h>
    00024
    00025 #include <qstrlist.h>
    00026
    00027 #include <stdlib.h>
    00028 #include <string.h>
    00029
    00030 KDESasl::KDESasl(const KURL &aUrl)
    00031 {
    00032   mProtocol = aUrl.protocol();
    00033   mUser = aUrl.user();
    00034   mPass = aUrl.pass();
    00035   mFirst = true;
    00036 }
    00037
    00038 KDESasl::KDESasl(const QString &aUser, const QString &aPass,
    00039   const QString &aProtocol)
    00040 {
    00041   mProtocol = aProtocol;
    00042   mUser = aUser;
    00043   mPass = aPass;
    00044   mFirst = true;
    00045 }
    00046
    00047 KDESasl::~KDESasl() {
    00048 }
    00049
    00050 QCString KDESasl::chooseMethod(const QStrIList aMethods)
    00051 {
    00052   if (aMethods.contains("DIGEST-MD5")) mMethod = "DIGEST-MD5";
    00053   else if (aMethods.contains("CRAM-MD5")) mMethod = "CRAM-MD5";
    00054   else if (aMethods.contains("PLAIN")) mMethod = "PLAIN";
    00055   else if (aMethods.contains("LOGIN")) mMethod = "LOGIN";
    00056   else mMethod = QCString();
    00057   return mMethod;
    00058 }
    00059
    00060 void KDESasl::setMethod(const QCString &aMethod)
    00061 {
    00062   mMethod = aMethod.upper();
    00063 }
    00064
    00065 QByteArray KDESasl::getPlainResponse()
    00066 {
    00067   QCString user = mUser.utf8();
    00068   QCString pass = mPass.utf8();
    00069   int userlen = user.length();
    00070   int passlen = pass.length();
    00071   // result = $user\0$user\0$pass (no trailing \0)
    00072   QByteArray result(2 * userlen + passlen + 2);
    00073   if ( userlen ) {
    00074     memcpy( result.data(), user.data(), userlen );
    00075     memcpy( result.data() + userlen + 1, user.data(), userlen );
    00076   }
    00077   if ( passlen )
    00078     memcpy( result.data() + 2 * userlen + 2, pass.data(), passlen );
    00079   result[userlen] = result[2*userlen+1] = '\0';
    00080   return result;
    00081 }
    00082
    00083 QByteArray KDESasl::getLoginResponse()
    00084 {
    00085   QByteArray result = (mFirst) ? mUser.utf8() : mPass.utf8();
    00086   mFirst = !mFirst;
    00087   if (result.size()) result.resize(result.size() - 1);
    00088   return result;
    00089 }
    00090
    00091 QByteArray KDESasl::getCramMd5Response(const QByteArray &aChallenge)
    00092 {
    00093   uint i;
    00094   QByteArray secret = mPass.utf8();
    00095   int len = mPass.utf8().length();
    00096   secret.resize(len);
    00097   if (secret.size() > 64)
    00098   {
    00099     KMD5 md5(secret);
    00100     secret.duplicate((const char*)(&(md5.rawDigest()[0])), 16);
    00101     len = 16;
    00102   }
    00103   secret.resize(64);
    00104   for (i = len; i < 64; i++) secret[i] = 0;
    00105   QByteArray XorOpad(64);
    00106   for (i = 0; i < 64; i++) XorOpad[i] = secret[i] ^ 0x5C;
    00107   QByteArray XorIpad(64);
    00108   for (i = 0; i < 64; i++) XorIpad[i] = secret[i] ^ 0x36;
    00109   KMD5 md5;
    00110   md5.update(XorIpad);
    00111   md5.update(aChallenge);
    00112   KMD5 md5a;
    00113   md5a.update(XorOpad);
    00114   md5a.update(md5.rawDigest(), 16);
    00115   QByteArray result = mUser.utf8();
    00116   len = mUser.utf8().length();
    00117   result.resize(len + 33);
    00118   result[len] = ' ';
    00119   QCString ch = md5a.hexDigest();
    00120   for (i = 0; i < 32; i++) result[i+len+1] = *(ch.data() + i);
    00121   return result;
    00122 }
    00123
    00124 QByteArray KDESasl::getDigestMd5Response(const QByteArray &aChallenge)
    00125 {
    00126   mFirst = !mFirst;
    00127   if (mFirst) return QByteArray();
    00128   QCString str, realm, nonce, qop, algorithm, charset;
    00129   QCString nc = "00000001";
    00130   unsigned int a, b, c, d;
    00131   a = 0;
    00132   while (a < aChallenge.size())
    00133   {
    00134     b = a;
    00135     while (b < aChallenge.size() && aChallenge[b] != '=') b++;
    00136     c = b + 1;
    00137     if (aChallenge[c] == '"')
    00138     {
    00139       d = c + 1;
    00140       while (d < aChallenge.size() && aChallenge[d] != '"') d++;
    00141       c++;
    00142     } else {
    00143       d = c;
    00144       while (d < aChallenge.size() && aChallenge[d] != ',') d++;
    00145     }
    00146     str = QCString(aChallenge.data() + c, d - c + 1);
    00147     if (qstrnicmp(aChallenge.data() + a, "realm=", 6) == 0) realm = str;
    00148     else if (qstrnicmp(aChallenge.data() + a, "nonce=", 6) == 0) nonce = str;
    00149     else if (qstrnicmp(aChallenge.data() + a, "qop=", 4) == 0) qop = str;
    00150     else if (qstrnicmp(aChallenge.data() + a, "algorithm=", 10) == 0)
    00151       algorithm = str;
    00152     else if (qstrnicmp(aChallenge.data() + a, "charset=", 8) == 0)
    00153       charset = str;
    00154     a = (d < aChallenge.size() && aChallenge[d] == '"') ? d + 2 : d + 1;
    00155   }
    00156   if (qop.isEmpty()) qop = "auth";
    00157   qop = "auth";
    00158   bool utf8 = qstricmp(charset, "utf-8") == 0;
    00159   QCString digestUri = QCString(mProtocol.latin1()) + "/" + realm;
    00160
    00161   /* Calculate the response */
    00162   /* Code based on code from the http io-slave
    00163      Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org>
    00164      Copyright (C) 2000,2001 Waldo Bastian <bastian@kde.org>
    00165      Copyright (C) 2000,2001 George Staikos <staikos@kde.org> */
    00166   KMD5 md, md2;
    00167   QCString HA1, HA2;
    00168   QCString cnonce;
    00169   cnonce.setNum((1 + static_cast<int>(100000.0*rand()/(RAND_MAX+1.0))));
    00170   cnonce = KCodecs::base64Encode( cnonce );
    00171
    00172   // Calculate H(A1)
    00173   QCString authStr = (utf8) ? mUser.utf8() : QCString(mUser.latin1());
    00174   authStr += ':';
    00175   authStr += realm;
    00176   authStr += ':';
    00177   authStr += (utf8) ? mPass.utf8() : QCString(mPass.latin1());
    00178
    00179   md.update( authStr );
    00180   authStr = "";
    00181   if ( algorithm == "md5-sess" )
    00182   {
    00183     authStr += ':';
    00184     authStr += nonce;
    00185     authStr += ':';
    00186     authStr += cnonce;
    00187   }
    00188   md2.reset();
    00189   /* SASL authentication uses rawDigest here, whereas HTTP authentication uses
    00190      hexDigest() */
    00191   md2.update(md.rawDigest(), 16);
    00192   md2.update( authStr );
    00193   md2.hexDigest( HA1 );
    00194
    00195   // Calcualte H(A2)
    00196   authStr = "AUTHENTICATE:";
    00197   authStr += digestUri;
    00198   if ( qop == "auth-int" || qop == "auth-conf" )
    00199   {
    00200     authStr += ":00000000000000000000000000000000";
    00201   }
    00202   md.reset();
    00203   md.update( authStr );
    00204   md.hexDigest( HA2 );
    00205
    00206   // Calcualte the response.
    00207   authStr = HA1;
    00208   authStr += ':';
    00209   authStr += nonce;
    00210   authStr += ':';
    00211   if ( !qop.isEmpty() )
    00212   {
    00213     authStr += nc;
    00214     authStr += ':';
    00215     authStr += cnonce;
    00216     authStr += ':';
    00217     authStr += qop;
    00218     authStr += ':';
    00219   }
    00220   authStr += HA2;
    00221   md.reset();
    00222   md.update( authStr );
    00223   QCString response = md.hexDigest();
    00224   /* End of response calculation */
    00225
    00226   QCString result;
    00227   if (utf8)
    00228   {
    00229     result = "charset=utf-8,username=\"" + mUser.utf8();
    00230   } else {
    00231     result = "charset=iso-8859-1,username=\"" + QCString(mUser.latin1());
    00232   }
    00233   result += "\",realm=\"" + realm + "\",nonce=\"" + nonce;
    00234   result += "\",nc=" + nc + ",cnonce=\"" + cnonce;
    00235   result += "\",digest-uri=\"" + digestUri;
    00236   result += "\",response=" + response + ",qop=" + qop;
    00237   QByteArray ba;
    00238   ba.duplicate(result.data(), result.length());
    00239   return ba;
    00240 }
    00241
    00242 QByteArray KDESasl::getBinaryResponse(const QByteArray &aChallenge, bool aBase64)
    00243 {
    00244   if (aBase64)
    00245   {
    00246     QByteArray ba;
    00247     KCodecs::base64Decode(aChallenge, ba);
    00248     KCodecs::base64Encode(getBinaryResponse(ba, false), ba);
    00249     return ba;
    00250   }
    00251   if (qstricmp(mMethod, "PLAIN") == 0) return getPlainResponse();
    00252   if (qstricmp(mMethod, "LOGIN") == 0) return getLoginResponse();
    00253   if (qstricmp(mMethod, "CRAM-MD5") == 0)
    00254     return getCramMd5Response(aChallenge);
    00255   if (qstricmp(mMethod, "DIGEST-MD5") == 0)
    00256     return getDigestMd5Response(aChallenge);
    00257 //    return getDigestMd5Response(QCString("realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8"));
    00258   return QByteArray();
    00259 }
    00260
    00261 QCString KDESasl::getResponse(const QByteArray &aChallenge, bool aBase64)
    00262 {
    00263   QByteArray ba = getBinaryResponse(aChallenge, aBase64);
    00264   return QCString(ba.data(), ba.size() + 1);
    00265 }
    00266
    00267 QCString KDESasl::method() const {
    00268   return mMethod;
    00269 }
    00270
    00271 bool KDESasl::clientStarts() const {
    00272   return method() == "PLAIN";
    00273 }
    00274
    00275 bool KDESasl::dialogComplete( int n ) const {
    00276   if ( method() == "PLAIN" || method() == "CRAM-MD5" )
    00277     return n >= 1;
    00278   if ( method() == "LOGIN" || method() == "DIGEST-MD5" )
    00279     return n >= 2;
    00280   return true;
    00281 }
    00282
    00283 bool KDESasl::isClearTextMethod() const {
    00284   return method() == "PLAIN" || method() == "LOGIN" ;
    00285 }

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:55 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003