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:
parent
881a060c27
commit
d1596cff9c
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user