00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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((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
00152
00153
00154
00155
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
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
00180
00181 md2.update(md.rawDigest(), 16);
00182 md2.update( authStr );
00183 md2.hexDigest( HA1 );
00184
00185
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
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
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
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 }