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.13 2004/02/10 23:07:49 porten 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 "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 }
KDE Logo
This file is part of the documentation for kio Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:29:23 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003