kio Library API Documentation

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,v 1.8.4.1 2003/01/29 18:33:50 mcamen Exp $
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 <stdlib.h>
00021 #include <qstrlist.h>
00022 #include <kmdcodec.h>
00023 #include <kurl.h>
00024 #include "kdesasl.h"
00025 
00026 KDESasl::KDESasl(const KURL &aUrl)
00027 {
00028   mProtocol = aUrl.protocol();
00029   mUser = aUrl.user();
00030   mPass = aUrl.pass();
00031   mFirst = TRUE;
00032 }
00033 
00034 KDESasl::KDESasl(const QString &aUser, const QString &aPass,
00035   const QString &aProtocol)
00036 {
00037   mProtocol = aProtocol;
00038   mUser = aUser;
00039   mPass = aPass;
00040   mFirst = TRUE;
00041 }
00042 
00043 KDESasl::~KDESasl() {
00044 }
00045 
00046 QCString KDESasl::chooseMethod(const QStrIList aMethods)
00047 {
00048   if (aMethods.contains("DIGEST-MD5")) mMethod = "DIGEST-MD5";
00049   else if (aMethods.contains("CRAM-MD5")) mMethod = "CRAM-MD5";
00050   else if (aMethods.contains("LOGIN")) mMethod = "LOGIN";
00051   else if (aMethods.contains("PLAIN")) mMethod = "PLAIN";
00052   else mMethod = QCString();
00053   return mMethod;
00054 }
00055 
00056 void KDESasl::setMethod(const QCString &aMethod)
00057 {
00058   mMethod = aMethod;
00059 }
00060 
00061 QByteArray KDESasl::getPlainResponse()
00062 {
00063   QCString user = mUser.utf8();
00064   QCString pass = mPass.utf8();
00065   int userlen = user.length();
00066   int passlen = pass.length();
00067   QByteArray result(2 * userlen + passlen + 2);
00068   for (int i = 0; i <= userlen; i++) result[i+userlen+1] = result[i] = user[i];
00069   for (int i = 0; i < passlen; i++) result[i+2*userlen+2] = pass[i];
00070   return result;
00071 }
00072 
00073 QByteArray KDESasl::getLoginResponse()
00074 {
00075   QByteArray result = (mFirst) ? mUser.utf8() : mPass.utf8();
00076   mFirst = !mFirst;
00077   if (result.size()) result.resize(result.size() - 1);
00078   return result;
00079 }
00080 
00081 QByteArray KDESasl::getCramMd5Response(const QByteArray &aChallenge)
00082 {
00083   uint i;
00084   QByteArray secret = mPass.utf8();
00085   int len = mPass.utf8().length();
00086   secret.resize(len);
00087   if (secret.size() > 64)
00088   {
00089     KMD5 md5(secret);
00090     secret.duplicate((const char*)md5.rawDigest(), 16);
00091     len = 16;
00092   }
00093   secret.resize(64);
00094   for (i = len; i < 64; i++) secret[i] = 0;
00095   QByteArray XorOpad(64);
00096   for (i = 0; i < 64; i++) XorOpad[i] = secret[i] ^ 0x5C;
00097   QByteArray XorIpad(64);
00098   for (i = 0; i < 64; i++) XorIpad[i] = secret[i] ^ 0x36;
00099   KMD5 md5;
00100   md5.update(XorIpad);
00101   md5.update(aChallenge);
00102   KMD5 md5a;
00103   md5a.update(XorOpad);
00104   md5a.update(md5.rawDigest(), 16);
00105   QByteArray result = mUser.utf8();
00106   len = mUser.utf8().length();
00107   result.resize(len + 33);
00108   result[len] = ' ';
00109   QCString ch = md5a.hexDigest();
00110   for (i = 0; i < 32; i++) result[i+len+1] = *(ch.data() + i);
00111   return result;
00112 }
00113 
00114 QByteArray KDESasl::getDigestMd5Response(const QByteArray &aChallenge)
00115 {
00116   mFirst = !mFirst;
00117   if (mFirst) return QByteArray();
00118   QCString str, realm, nonce, qop, algorithm, charset;
00119   QCString nc = "00000001";
00120   unsigned int a, b, c, d;
00121   a = 0;
00122   while (a < aChallenge.size())
00123   {
00124     b = a;
00125     while (b < aChallenge.size() && aChallenge[b] != '=') b++;
00126     c = b + 1;
00127     if (aChallenge[c] == '"')
00128     {
00129       d = c + 1;
00130       while (d < aChallenge.size() && aChallenge[d] != '"') d++;
00131       c++;
00132     } else {
00133       d = c;
00134       while (d < aChallenge.size() && aChallenge[d] != ',') d++;
00135     }
00136     str = QCString(aChallenge.data() + c, d - c + 1);
00137     if (qstrnicmp(aChallenge.data() + a, "realm=", 6) == 0) realm = str;
00138     else if (qstrnicmp(aChallenge.data() + a, "nonce=", 6) == 0) nonce = str;
00139     else if (qstrnicmp(aChallenge.data() + a, "qop=", 4) == 0) qop = str;
00140     else if (qstrnicmp(aChallenge.data() + a, "algorithm=", 10) == 0)
00141       algorithm = str;
00142     else if (qstrnicmp(aChallenge.data() + a, "charset=", 8) == 0)
00143       charset = str;
00144     a = (d < aChallenge.size() && aChallenge[d] == '"') ? d + 2 : d + 1;
00145   }
00146   if (qop.isEmpty()) qop = "auth";
00147   qop = "auth";
00148   bool utf8 = qstricmp(charset, "utf-8") == 0;
00149   QCString digestUri = QCString(mProtocol.latin1()) + "/" + realm;
00150 
00151   /* Calculate the response */
00152   /* Code based on code from the http io-slave
00153      Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org>
00154      Copyright (C) 2000,2001 Waldo Bastian <bastian@kde.org>
00155      Copyright (C) 2000,2001 George Staikos <staikos@kde.org> */
00156   KMD5 md, md2;
00157   QCString HA1, HA2;
00158   QCString cnonce;
00159   cnonce.setNum((1 + static_cast<int>(100000.0*rand()/(RAND_MAX+1.0))));
00160   cnonce = KCodecs::base64Encode( cnonce );
00161 
00162   // Calculate H(A1)
00163   QCString authStr = (utf8) ? mUser.utf8() : QCString(mUser.latin1());
00164   authStr += ':';
00165   authStr += realm;
00166   authStr += ':';
00167   authStr += (utf8) ? mPass.utf8() : QCString(mPass.latin1());
00168 
00169   md.update( authStr );
00170   authStr = "";
00171   if ( algorithm == "md5-sess" )
00172   {
00173     authStr += ':';
00174     authStr += nonce;
00175     authStr += ':';
00176     authStr += cnonce;
00177   }
00178   md2.reset();
00179   /* SASL authentication uses rawDigest here, whereas HTTP authentication uses
00180      hexDigest() */
00181   md2.update(md.rawDigest(), 16);
00182   md2.update( authStr );
00183   md2.hexDigest( HA1 );
00184 
00185   // Calcualte H(A2)
00186   authStr = "AUTHENTICATE:";
00187   authStr += digestUri;
00188   if ( qop == "auth-int" || qop == "auth-conf" )
00189   {
00190     authStr += ":00000000000000000000000000000000";
00191   }
00192   md.reset();
00193   md.update( authStr );
00194   md.hexDigest( HA2 );
00195 
00196   // Calcualte the response.
00197   authStr = HA1;
00198   authStr += ':';
00199   authStr += nonce;
00200   authStr += ':';
00201   if ( !qop.isEmpty() )
00202   {
00203     authStr += nc;
00204     authStr += ':';
00205     authStr += cnonce;
00206     authStr += ':';
00207     authStr += qop;
00208     authStr += ':';
00209   }
00210   authStr += HA2;
00211   md.reset();
00212   md.update( authStr );
00213   QCString response = md.hexDigest();
00214   /* End of response calculation */
00215 
00216   QCString result;
00217   if (utf8)
00218   {
00219     result = "charset=utf-8,username=\"" + mUser.utf8();
00220   } else {
00221     result = "charset=iso-8859-1,username=\"" + QCString(mUser.latin1());
00222   }
00223   result += "\",realm=\"" + realm + "\",nonce=\"" + nonce;
00224   result += "\",nc=" + nc + ",cnonce=\"" + cnonce;
00225   result += "\",digest-uri=\"" + digestUri;
00226   result += "\",response=" + response + ",qop=" + qop;
00227   QByteArray ba;
00228   ba.duplicate(result.data(), result.length());
00229   return ba;
00230 }
00231 
00232 QByteArray KDESasl::getBinaryResponse(const QByteArray &aChallenge, bool aBase64)
00233 {
00234   if (aBase64)
00235   {
00236     QByteArray ba;
00237     KCodecs::base64Decode(aChallenge, ba);
00238     KCodecs::base64Encode(getBinaryResponse(ba, FALSE), ba);
00239     return ba;
00240   }
00241   if (qstricmp(mMethod, "PLAIN") == 0) return getPlainResponse();
00242   if (qstricmp(mMethod, "LOGIN") == 0) return getLoginResponse();
00243   if (qstricmp(mMethod, "CRAM-MD5") == 0)
00244     return getCramMd5Response(aChallenge);
00245   if (qstricmp(mMethod, "DIGEST-MD5") == 0)
00246     return getDigestMd5Response(aChallenge);
00247 //    return getDigestMd5Response(QCString("realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8"));
00248   return QByteArray();
00249 }
00250 
00251 QCString KDESasl::getResponse(const QByteArray &aChallenge, bool aBase64)
00252 {
00253   QByteArray ba = getBinaryResponse(aChallenge, aBase64);
00254   return QCString(ba.data(), ba.size() + 1);
00255 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:29 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001