#include "diality_keys.h" #include #include #include #include #include static bool parseHexField(const QJsonObject& obj, const char* name, int expectedBytes, QByteArray* out, QString* err) { if (!obj.contains(name) || !obj.value(name).isString()) { if (err) *err = QString("Missing or invalid field: %1").arg(QString::fromLatin1(name)); return false; } const QString s = obj.value(name).toString().trimmed(); const QString h = QString(s).remove(' '); if (h.size() != expectedBytes * 2) { if (err) *err = QString("Field %1: wrong hex length (expected %2 hex chars)") .arg(QString::fromLatin1(name)) .arg(expectedBytes * 2); return false; } const QByteArray bin = QByteArray::fromHex(h.toLatin1()); if (bin.size() != expectedBytes) { if (err) *err = QString("Field %1: hex decode failed").arg(QString::fromLatin1(name)); return false; } if (out) *out = bin; return true; } namespace diality { bool loadKeysFromJsonFile(const QString& path, Keys* outKeys, QString* error) { if (!outKeys) { if (error) *error = "Internal error: outKeys is null"; return false; } QFile f(path); if (!f.open(QIODevice::ReadOnly)) { if (error) *error = QString("Cannot open keys file: %1").arg(path); return false; } const QByteArray data = f.readAll(); f.close(); QJsonParseError pe; const QJsonDocument doc = QJsonDocument::fromJson(data, &pe); if (doc.isNull() || !doc.isObject()) { if (error) *error = QString("Invalid JSON in %1: %2").arg(path, pe.errorString()); return false; } const QJsonObject obj = doc.object(); QString err; Keys k; if (!parseHexField(obj, "encKey32", 32, &k.encKey32, &err)) { if (error) *error = err; return false; } if (obj.contains("signSk32")) { if (!parseHexField(obj, "signSk32", 32, &k.signSk32, &err)) { if (error) *error = err; return false; } } if (!parseHexField(obj, "signPk32", 32, &k.signPk32, &err)) { if (error) *error = err; return false; } *outKeys = k; return true; } static QString exeDirKeysJson() { const QString exe = QCoreApplication::applicationFilePath(); const QFileInfo fi(exe); return fi.absolutePath() + "/keys.json"; } bool loadPcKeys(Keys* outKeys, QString* loadedPath, QString* error) { const QString p = exeDirKeysJson(); Keys k; QString err; if (!loadKeysFromJsonFile(p, &k, &err)) { if (error) *error = err; return false; } if (k.signSk32.size() != 32) { if (error) *error = "keys.json is missing signSk32 (PC needs private key to sign)"; return false; } *outKeys = k; if (loadedPath) *loadedPath = p; return true; } bool loadDeviceKeys(Keys* outKeys, QString* loadedPath, QString* error) { const QStringList candidates = { "/etc/diality/keys.json", exeDirKeysJson() }; QString lastErr; for (const QString& p : candidates) { Keys k; QString err; if (loadKeysFromJsonFile(p, &k, &err)) { k.signSk32.clear(); *outKeys = k; if (loadedPath) *loadedPath = p; return true; } lastErr = err; } if (error) *error = lastErr.isEmpty() ? "No keys file found" : lastErr; return false; } } // namespace diality