1
mirror of https://invent.kde.org/network/falkon.git synced 2024-11-14 02:52:12 +01:00

Add cryptographic functions for sync

Add function for HKDF using Nettle.
Add function to process sessionToken.
Add function to process keyFetchToken.
This commit is contained in:
Prasenjit Kumar Shaw 2019-06-26 01:55:57 +05:30
parent 881a060c27
commit d1596cff9c
3 changed files with 99 additions and 75 deletions

View File

@ -28,42 +28,41 @@
FxALoginPage::FxALoginPage(QWidget* parent) FxALoginPage::FxALoginPage(QWidget* parent)
: QWebEngineView(parent) : QWebEngineView(parent)
{ {
m_page = new QWebEnginePage(); m_page = new QWebEnginePage(this);
m_channel = new QWebChannel(m_page); m_channel = new QWebChannel(m_page);
m_page->setWebChannel(m_channel); m_page->setWebChannel(m_channel);
m_page->load(FxALoginUrl); m_page->load(FxALoginUrl);
this->setPage(m_page); setPage(m_page);
connect(m_page, SIGNAL(loadFinished(bool)), this, SLOT(pageLoadFinished(bool))); connect(m_page, &QWebEnginePage::loadFinished, this, &FxALoginPage::pageLoadFinished);
} }
FxALoginPage::~FxALoginPage() FxALoginPage::~FxALoginPage()
{ {
delete m_communicator; delete m_communicator;
delete m_channel; delete m_channel;
delete m_page;
} }
void FxALoginPage::pageLoadFinished(bool pageLoaded) void FxALoginPage::pageLoadFinished(bool pageLoaded)
{ {
if(pageLoaded) { if (pageLoaded) {
QFile apiFile(":/qtwebchannel/qwebchannel.js"); QFile apiFile(":/qtwebchannel/qwebchannel.js");
if(!apiFile.open(QIODevice::ReadOnly)) { if (!apiFile.open(QIODevice::ReadOnly)) {
qDebug() << "Couldn't load Qt's Webchannel API!"; qWarning() << "Couldn't load Qt's Webchannel API!";
} }
QString apiScript = QString::fromLatin1(apiFile.readAll()); QString apiScript = QString::fromUtf8(apiFile.readAll());
apiFile.close(); apiFile.close();
m_page->runJavaScript(apiScript); m_page->runJavaScript(apiScript);
m_communicator = new MessageReceiver(this); m_communicator = new MessageReceiver(this);
connect(m_communicator, SIGNAL(signalMessageReceived()), connect(m_communicator, &MessageReceiver::signalMessageReceived,
this, SLOT(slotMessageReceived())); this, &FxALoginPage::slotMessageReceived);
m_channel->registerObject(QString("communicator"), m_communicator); m_channel->registerObject(QString("communicator"), m_communicator);
QFile scriptFile(":/data/inject.js"); QFile scriptFile(":/data/inject.js");
if(!scriptFile.open(QIODevice::ReadOnly)) { if (!scriptFile.open(QIODevice::ReadOnly)) {
qDebug() << "Couldn't load JavaScript file to inject."; qWarning() << "Couldn't load JavaScript file to inject.";
} }
QString injectScript = QString::fromLatin1(scriptFile.readAll()); QString injectScript = QString::fromUtf8(scriptFile.readAll());
scriptFile.close(); scriptFile.close();
m_page->runJavaScript(injectScript); m_page->runJavaScript(injectScript);
} }
@ -79,21 +78,20 @@ void FxALoginPage::slotMessageReceived()
void FxALoginPage::parseMessage(QJsonObject *msg) void FxALoginPage::parseMessage(QJsonObject *msg)
{ {
QJsonValue command = (*msg).value("detail").toObject().value("message").toObject().value("command"); QJsonValue command = msg->value("detail").toObject().value("message").toObject().value("command");
if(command.toString() == QString("fxaccounts:can_link_account")) { if (command.toString() == QLatin1String("fxaccounts:can_link_account")) {
QJsonObject responseData; QJsonObject responseData;
responseData.insert("ok", true); responseData.insert(QString("ok"), true);
QJsonObject message; QJsonObject message;
message.insert("command", command); message.insert("command", command);
message.insert("data", responseData); message.insert("data", responseData);
message.insert("messageId", (*msg).value("detail").toObject().value("message").toObject().value("messageId")); message.insert("messageId", msg->value("detail").toObject().value("message").toObject().value("messageId"));
QJsonObject response; QJsonObject response;
response.insert("id", (*msg).value("detail").toObject().value("id")); response.insert("id", msg->value("detail").toObject().value("id"));
response.insert("message", message); response.insert("message", message);
sendMessage(response); sendMessage(response);
} } else if (command.toString() == QLatin1String("fxaccounts:login")) {
else if(command.toString() == QString("fxaccounts:login")) { QJsonObject data = msg->value("detail").toObject().value("message").toObject().value("data").toObject();
QJsonObject data = (*msg).value("detail").toObject().value("message").toObject().value("data").toObject();
QString email = data.value("email").toString(); QString email = data.value("email").toString();
QString uid = data.value("uid").toString(); QString uid = data.value("uid").toString();
QString session_token = data.value("sessionToken").toString(); QString session_token = data.value("sessionToken").toString();

View File

@ -15,57 +15,91 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */ * ============================================================ */
#include "synccrypto.h" #include "synccrypto.h"
#include <openssl/evp.h> #include <nettle/sha2.h>
#include <openssl/kdf.h> #include <nettle/hkdf.h>
#include <nettle/hmac.h>
#include <QByteArray> #include <QByteArray>
#include <QString>
HKDF::HKDF(const QByteArray key, const QByteArray salt, const QByteArray info) u_char *syncCryptoHkdf(QByteArray *in, QByteArray *info, size_t out_len)
{ {
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF,NULL); hmac_sha256_ctx *ctx = new hmac_sha256_ctx;
init(key, salt,info); size_t in_len = in->size();
size_t info_len = info->size();
u_char *salt = new u_char[SHA256_DIGEST_SIZE] {0};
u_char *prk = new u_char[SHA256_DIGEST_SIZE];
u_char *output = new u_char[out_len];
nettle_hmac_sha256_set_key(ctx, SHA256_DIGEST_SIZE, salt);
nettle_hkdf_extract(ctx,
(nettle_hash_update_func *)hmac_sha256_update,
(nettle_hash_digest_func *)hmac_sha256_digest,
SHA256_DIGEST_SIZE,
in_len, (u_char *)in->data(), prk);
nettle_hmac_sha256_set_key(ctx, SHA256_DIGEST_SIZE, prk);
nettle_hkdf_expand(ctx,
(nettle_hash_update_func *)hmac_sha256_update,
(nettle_hash_digest_func *)hmac_sha256_digest,
SHA256_DIGEST_SIZE,
info_len, (u_char *)info->data(), out_len, output);
delete[] prk;
return output;
} }
HKDF::~HKDF() { void syncCryptoKW(QByteArray *kw, QString name)
}
void HKDF::init(const QByteArray key, const QByteArray salt, const QByteArray info)
{ {
size_t keylen = key.size(); // Concatenate "name" to Mozilla prefix to get the required KW.
size_t saltlen = salt.size(); // See https://raw.githubusercontent.com/wiki/mozilla/fxa-auth-server/images/onepw-create.png for details.
size_t infolen = info.size(); QString info = QString("identity.mozilla.com/picl/v1/").append(name);
kw->append(info.toUtf8());
if (EVP_PKEY_derive_init(pctx) <= 0) {
qWarning("Unable to initialize public key algorithm context for HKDF.");
return;
}
if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) {
qWarning("Unable to set HKDF message digest.");
return;
}
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (uchar *)salt.data(), saltlen) <= 0) {
qWarning("Unable to set salt.");
return;
}
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (uchar *)key.data(), keylen) <= 0) {
qWarning("Unable to set key.");
return;
}
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (uchar *)info.data(), infolen) <= 0) {
qWarning("Uable to set info for HKDF.");
return;
}
} }
QByteArray HKDF::getKey(size_t outlen) { void deriveSessionToken(QByteArray *sessionToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *reqKey)
QByteArray out; {
if (EVP_PKEY_derive(pctx, (uchar *)out.data(), &outlen) <= 0) { QByteArray *kw = new QByteArray();
qWarning("Unable to derive HKDF key."); syncCryptoKW(kw, QString("sessionToken"));
} size_t len = 32;
return out;
u_char *out = syncCryptoHkdf(sessionToken, kw, 3 * len);
QByteArray *temp = new QByteArray(QByteArray::fromRawData((const char *)out, 3 * len));
QByteArray tId(*temp);
tId.remove(len, 2 * len);
tokenId->append(tId);
reqKey->append(temp->right(len));
temp->remove(0, len);
temp->remove(len, len);
reqHMACKey->append(*temp);
} }
void deriveKeyFetchToken(QByteArray *keyFetchToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *respHMACKey, QByteArray *respXORKey)
{
QByteArray *infoKft = new QByteArray();
syncCryptoKW(infoKft, "keyFetchToken");
QByteArray *infoKeys = new QByteArray();
syncCryptoKW(infoKeys, "account/keys");
size_t len = 32;
u_char *out1 = syncCryptoHkdf(keyFetchToken, infoKft, 3 * len);
QByteArray *temp = new QByteArray(QByteArray::fromRawData((const char *)out1, 3 * len));
QByteArray tId(*temp);
tId.remove(len, 2 * len);
tokenId->append(tId);
QByteArray *reqKey = new QByteArray();
reqKey->append(temp->right(len));
temp->remove(0, len);
temp->remove(len, len);
reqHMACKey->append(*temp);
u_char *out2 = syncCryptoHkdf(reqKey, infoKeys, 3 * len);
QByteArray *temp2 = new QByteArray(QByteArray::fromRawData((const char *)out2, 3 * len));
QByteArray respHKey(*temp2);
respHKey.remove(len, 2 * len);
respHMACKey->append(respHKey);
temp2->remove(0, len);
respXORKey->append(*temp2);
}

View File

@ -17,20 +17,12 @@
* ============================================================ */ * ============================================================ */
#pragma once #pragma once
#include <openssl/evp.h>
#include <QByteArray> #include <QByteArray>
#include <QString>
class HKDF #define SHA256_DIGEST_SIZE 32
{
public:
explicit HKDF(const QByteArray key, const QByteArray salt, const QByteArray info);
~HKDF();
QByteArray getKey(size_t outlen);
private:
void init(const QByteArray key, const QByteArray salt, const QByteArray info);
EVP_PKEY_CTX *pctx;
};
u_char *syncCryptoHkdf(QByteArray *in, QByteArray *info, size_t out_len);
void syncCryptoKW(QByteArray *kw, QString name);
void deriveSessionToken(QByteArray *sessionToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *reqKey);
void deriveKeyFetchToken(QByteArray *keyFetchToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *respHMACKey, QByteArray *respXORKey);