/*
 * Copyright (C) 2008  Remko Troncon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

#include "xmpp/sasl/digestmd5response.h"

#include <QByteArray>
#include <QtCrypto>
#include <QtDebug>

#include "xmpp/sasl/digestmd5proplist.h"
#include "xmpp/base/randomnumbergenerator.h"

namespace XMPP {

DIGESTMD5Response::DIGESTMD5Response(const QByteArray& challenge, const QString& service, const QString& host, const QString& arealm, const QString& user, const QString& authz,  const QByteArray& password, const RandomNumberGenerator& rand) : isValid_(true)
{
    QString realm = arealm;

    // get props
    DIGESTMD5PropList in;
    if(!in.fromString(challenge)) {
        isValid_ = false;
        return;
    }
    //qDebug() << (QString("simplesasl.cpp: IN: %1").arg(QString(in.toString())));

    // make a cnonce
    QByteArray a;
    a.resize(32);
    for(int n = 0; n < (int)a.size(); ++n) {
        a[n] = (char) rand.generateNumberBetween(0, 255);
    }
    QByteArray cnonce = a.toBase64();

    // make other variables
    if (realm.isEmpty()) {
        realm = QString::fromUtf8(in.get("realm"));
    }
    QByteArray nonce = in.get("nonce");
    QByteArray nc = "00000001";
    QByteArray uri = service.toUtf8() + '/' + host.toUtf8();
    QByteArray qop = "auth";

    // build 'response'
    QByteArray X = user.toUtf8() + ':' + realm.toUtf8() + ':' + password;
    QByteArray Y = QCA::Hash("md5").hash(X).toByteArray();
    QByteArray tmp = ':' + nonce + ':' + cnonce;
    if (!authz.isEmpty())
        tmp += ':' + authz.toUtf8();
    //qDebug() << (QString(tmp));

    QByteArray A1(Y + tmp);
    QByteArray A2 = QByteArray("AUTHENTICATE:") + uri;
    QByteArray HA1 = QCA::Hash("md5").hashToString(A1).toLatin1();
    QByteArray HA2 = QCA::Hash("md5").hashToString(A2).toLatin1();
    QByteArray KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + HA2;
    QByteArray Z = QCA::Hash("md5").hashToString(KD).toLatin1();

    //qDebug() << QString("simplesasl.cpp: A1 = %1").arg(QString(A1));
    //qDebug() << QString("simplesasl.cpp: A2 = %1").arg(QString(A2));
    //qDebug() << QString("simplesasl.cpp: KD = %1").arg(QString(KD));

    // build output
    DIGESTMD5PropList out;
    out.set("username", user.toUtf8());
    if (!realm.isEmpty())
        out.set("realm", realm.toUtf8());
    out.set("nonce", nonce);
    out.set("cnonce", cnonce);
    out.set("nc", nc);
    //out.set("serv-type", service.toUtf8());
    //out.set("host", host.toUtf8());
    out.set("digest-uri", uri);
    out.set("qop", qop);
    out.set("response", Z);
    out.set("charset", "utf-8");
    if (!authz.isEmpty())
        out.set("authzid", authz.toUtf8());
    value_  = out.toString();
}

}
