You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
696 lines
20 KiB
C++
696 lines
20 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2010 Volker Lanz <vl@fidra.de>
|
|
SPDX-FileCopyrightText: 2012-2019 Andrius Štikonas <andrius@stikonas.eu>
|
|
SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac <teo@kde.org>
|
|
SPDX-FileCopyrightText: 2016 Chantara Tith <tith.chantara@gmail.com>
|
|
SPDX-FileCopyrightText: 2017 Christian Morlok <christianmorlok@gmail.com>
|
|
SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
|
|
SPDX-FileCopyrightText: 2020 Arnaud Ferraris <arnaud.ferraris@collabora.com>
|
|
SPDX-FileCopyrightText: 2020 Gaël PORTAY <gael.portay@collabora.com>
|
|
|
|
SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include "fs/luks.h"
|
|
#include "fs/lvm2_pv.h"
|
|
|
|
#include "fs/filesystemfactory.h"
|
|
|
|
#include "util/externalcommand.h"
|
|
#include "util/capacity.h"
|
|
#include "util/helpers.h"
|
|
#include "util/report.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include <QDebug>
|
|
#include <QDialog>
|
|
#include <QJsonArray>
|
|
#include <QJsonObject>
|
|
#include <QJsonDocument>
|
|
#include <QRegularExpression>
|
|
#include <QPointer>
|
|
#include <QStorageInfo>
|
|
#include <QString>
|
|
#include <QUuid>
|
|
#include <QWidget>
|
|
|
|
#include <KLocalizedString>
|
|
#include <KPasswordDialog>
|
|
|
|
namespace FS
|
|
{
|
|
FileSystem::CommandSupportType luks::m_GetUsed = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_GetLabel = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_Create = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_Grow = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_Shrink = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_Move = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_Check = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_Copy = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_Backup = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_SetLabel = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_UpdateUUID = FileSystem::cmdSupportNone;
|
|
FileSystem::CommandSupportType luks::m_GetUUID = FileSystem::cmdSupportNone;
|
|
|
|
luks::luks(qint64 firstsector,
|
|
qint64 lastsector,
|
|
qint64 sectorsused,
|
|
const QString& label,
|
|
const QVariantMap& features,
|
|
FileSystem::Type t)
|
|
: FileSystem(firstsector, lastsector, sectorsused, label, features, t)
|
|
, m_innerFs(nullptr)
|
|
, m_isCryptOpen(false)
|
|
, m_cryptsetupFound(m_Create != cmdSupportNone)
|
|
, m_isMounted(false)
|
|
, m_KeySize(-1)
|
|
, m_PayloadOffset(-1)
|
|
{
|
|
}
|
|
|
|
luks::~luks()
|
|
{
|
|
delete m_innerFs;
|
|
}
|
|
|
|
void luks::init()
|
|
{
|
|
CommandSupportType cryptsetupFound = findExternal(QStringLiteral("cryptsetup")) ? cmdSupportFileSystem : cmdSupportNone;
|
|
|
|
m_Create = cryptsetupFound;
|
|
m_UpdateUUID = cryptsetupFound;
|
|
m_GetUUID = cryptsetupFound;
|
|
m_Grow = cryptsetupFound;
|
|
m_Shrink = cryptsetupFound;
|
|
|
|
m_SetLabel = cmdSupportNone;
|
|
m_GetLabel = cmdSupportFileSystem;
|
|
m_Check = cmdSupportCore;
|
|
m_Copy = cmdSupportCore;
|
|
m_Move = cmdSupportCore;
|
|
m_Backup = cmdSupportCore;
|
|
m_GetUsed = cmdSupportNone; // libparted does not support LUKS, we do this as a special case
|
|
}
|
|
|
|
void luks::scan(const QString& deviceNode)
|
|
{
|
|
getMapperName(deviceNode);
|
|
getLuksInfo(deviceNode);
|
|
}
|
|
|
|
bool luks::supportToolFound() const
|
|
{
|
|
return m_cryptsetupFound && ((m_isCryptOpen && m_innerFs) ? m_innerFs->supportToolFound() : true);
|
|
}
|
|
|
|
FileSystem::SupportTool luks::supportToolName() const
|
|
{
|
|
if (m_isCryptOpen && m_innerFs && m_cryptsetupFound)
|
|
return m_innerFs->supportToolName();
|
|
return SupportTool(QStringLiteral("cryptsetup"),
|
|
QUrl(QStringLiteral("https://code.google.com/p/cryptsetup/")));
|
|
}
|
|
|
|
bool luks::create(Report& report, const QString& deviceNode)
|
|
{
|
|
Q_ASSERT(m_innerFs);
|
|
Q_ASSERT(!m_passphrase.isEmpty());
|
|
|
|
ExternalCommand createCmd(report, QStringLiteral("cryptsetup"),
|
|
{ QStringLiteral("-s"),
|
|
QStringLiteral("512"),
|
|
QStringLiteral("--batch-mode"),
|
|
QStringLiteral("--force-password"),
|
|
QStringLiteral("--type"), QStringLiteral("luks1"),
|
|
QStringLiteral("luksFormat"),
|
|
deviceNode });
|
|
if (!( createCmd.write(m_passphrase.toLocal8Bit() + '\n') &&
|
|
createCmd.start(-1) && createCmd.exitCode() == 0))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ExternalCommand openCmd(report, QStringLiteral("cryptsetup"),
|
|
{ QStringLiteral("open"),
|
|
deviceNode,
|
|
suggestedMapperName(deviceNode) });
|
|
|
|
if (!( openCmd.write(m_passphrase.toLocal8Bit() + '\n') && openCmd.start(-1)))
|
|
return false;
|
|
|
|
setPayloadSize();
|
|
scan(deviceNode);
|
|
|
|
if (mapperName().isEmpty())
|
|
return false;
|
|
|
|
if (!m_innerFs->create(report, mapperName()))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
QString luks::mountTitle() const
|
|
{
|
|
return xi18nc("@title:menu", "Mount");
|
|
}
|
|
|
|
QString luks::unmountTitle() const
|
|
{
|
|
return xi18nc("@title:menu", "Unmount");
|
|
}
|
|
|
|
QString luks::cryptOpenTitle() const
|
|
{
|
|
return xi18nc("@title:menu", "Unlock");
|
|
}
|
|
|
|
QString luks::cryptCloseTitle() const
|
|
{
|
|
return xi18nc("@title:menu", "Lock");
|
|
}
|
|
|
|
void luks::setPassphrase(const QString& passphrase)
|
|
{
|
|
m_passphrase = passphrase;
|
|
}
|
|
|
|
QString luks::passphrase() const
|
|
{
|
|
return m_passphrase;
|
|
}
|
|
|
|
bool luks::canMount(const QString&, const QString& mountPoint) const
|
|
{
|
|
return m_isCryptOpen &&
|
|
!m_isMounted &&
|
|
m_innerFs &&
|
|
m_innerFs->canMount(mapperName(), mountPoint);
|
|
}
|
|
|
|
bool luks::canUnmount(const QString&) const
|
|
{
|
|
return m_isCryptOpen &&
|
|
m_isMounted &&
|
|
m_innerFs &&
|
|
m_innerFs->canUnmount(mapperName());
|
|
}
|
|
|
|
bool luks::isMounted() const
|
|
{
|
|
return m_isCryptOpen && m_isMounted;
|
|
}
|
|
|
|
void luks::setMounted(bool mounted)
|
|
{
|
|
m_isMounted = mounted;
|
|
}
|
|
|
|
bool luks::canCryptOpen(const QString&) const
|
|
{
|
|
return !m_isCryptOpen && !m_isMounted && supportToolFound();
|
|
}
|
|
|
|
bool luks::canCryptClose(const QString&) const
|
|
{
|
|
return m_isCryptOpen && !m_isMounted && m_cryptsetupFound;
|
|
}
|
|
|
|
bool luks::isCryptOpen() const
|
|
{
|
|
return m_isCryptOpen;
|
|
}
|
|
|
|
void luks::setCryptOpen(bool cryptOpen)
|
|
{
|
|
m_isCryptOpen = cryptOpen;
|
|
}
|
|
|
|
bool luks::cryptOpen(QWidget* parent, const QString& deviceNode)
|
|
{
|
|
if (m_isCryptOpen)
|
|
{
|
|
if (!mapperName().isEmpty())
|
|
{
|
|
qWarning() << "LUKS device" << deviceNode
|
|
<< "already decrypted."
|
|
<< "Cannot decrypt again.";
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
qWarning() << "LUKS device" << deviceNode
|
|
<< "reportedly decrypted but mapper node not found."
|
|
<< "Marking device as NOT decrypted and trying to "
|
|
"decrypt again anyway.";
|
|
m_isCryptOpen = false;
|
|
}
|
|
}
|
|
|
|
KPasswordDialog dlg( parent );
|
|
dlg.setPrompt(i18n("Enter passphrase for %1:", deviceNode));
|
|
if( !dlg.exec() )
|
|
return false;
|
|
|
|
QString passphrase = dlg.password();
|
|
ExternalCommand openCmd(QStringLiteral("cryptsetup"),
|
|
{ QStringLiteral("open"),
|
|
QStringLiteral("--tries"), QStringLiteral("1"),
|
|
deviceNode,
|
|
suggestedMapperName(deviceNode) });
|
|
|
|
if (!( openCmd.write(passphrase.toLocal8Bit() + '\n') &&
|
|
openCmd.start(-1) && openCmd.exitCode() == 0) )
|
|
return false;
|
|
|
|
if (m_innerFs) {
|
|
delete m_innerFs;
|
|
m_innerFs = nullptr;
|
|
}
|
|
|
|
scan(deviceNode);
|
|
|
|
if (mapperName().isEmpty())
|
|
return false;
|
|
|
|
loadInnerFileSystem(mapperName());
|
|
m_isCryptOpen = (m_innerFs != nullptr);
|
|
|
|
if (!m_isCryptOpen)
|
|
return false;
|
|
|
|
for (auto &p : LVM::pvList::list())
|
|
if (p.isLuks() && p.partition()->deviceNode() == deviceNode && p.partition()->fileSystem().type() == FileSystem::Type::Lvm2_PV)
|
|
p.setLuks(false);
|
|
|
|
m_passphrase = passphrase;
|
|
return true;
|
|
}
|
|
|
|
bool luks::cryptClose(const QString& deviceNode)
|
|
{
|
|
if (!m_isCryptOpen)
|
|
{
|
|
qWarning() << "Cannot close LUKS device" << deviceNode
|
|
<< "because it's not open.";
|
|
return false;
|
|
}
|
|
|
|
if (m_isMounted)
|
|
{
|
|
qWarning() << "Cannot close LUKS device" << deviceNode
|
|
<< "because the filesystem is mounted.";
|
|
return false;
|
|
}
|
|
|
|
ExternalCommand cmd(QStringLiteral("cryptsetup"),
|
|
{ QStringLiteral("close"), mapperName() });
|
|
if (!(cmd.run(-1) && cmd.exitCode() == 0))
|
|
return false;
|
|
|
|
delete m_innerFs;
|
|
m_innerFs = nullptr;
|
|
|
|
m_passphrase.clear();
|
|
setLabel(FileSystem::readLabel(deviceNode));
|
|
setUUID(readUUID(deviceNode));
|
|
setSectorsUsed(-1);
|
|
|
|
m_isCryptOpen = (m_innerFs != nullptr);
|
|
|
|
for (auto &p : LVM::pvList::list())
|
|
if (!p.isLuks() && p.partition()->deviceNode() == deviceNode)
|
|
p.setLuks(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
void luks::loadInnerFileSystem(const QString& mapperNode)
|
|
{
|
|
Q_ASSERT(!m_innerFs);
|
|
FileSystem::Type innerFsType = detectFileSystem(mapperNode);
|
|
m_innerFs = FileSystemFactory::cloneWithNewType(innerFsType,
|
|
*this);
|
|
setLabel(m_innerFs->readLabel(mapperNode));
|
|
setUUID(m_innerFs->readUUID(mapperNode));
|
|
if (m_innerFs->supportGetUsed() == FileSystem::cmdSupportFileSystem)
|
|
setSectorsUsed(static_cast<qint64>(std::ceil((m_innerFs->readUsedCapacity(mapperNode) + payloadOffset()) / static_cast<double>(sectorSize()) )));
|
|
m_innerFs->scan(mapperNode);
|
|
}
|
|
|
|
void luks::createInnerFileSystem(FileSystem::Type type)
|
|
{
|
|
Q_ASSERT(!m_innerFs);
|
|
m_innerFs = FileSystemFactory::cloneWithNewType(type, *this);
|
|
}
|
|
|
|
bool luks::check(Report& report, const QString&) const
|
|
{
|
|
Q_ASSERT(m_innerFs);
|
|
|
|
if (mapperName().isEmpty())
|
|
return false;
|
|
|
|
return m_innerFs->check(report, mapperName());
|
|
}
|
|
|
|
qint64 luks::readUsedCapacity(const QString& deviceNode) const
|
|
{
|
|
if (!m_isCryptOpen)
|
|
return -1;
|
|
if (m_innerFs)
|
|
return m_innerFs->readUsedCapacity(deviceNode);
|
|
return -1;
|
|
}
|
|
|
|
bool luks::mount(Report& report, const QString& deviceNode, const QString& mountPoint)
|
|
{
|
|
if (!m_isCryptOpen)
|
|
{
|
|
qWarning() << "Cannot mount device" << deviceNode
|
|
<< "before decrypting it first.";
|
|
return false;
|
|
}
|
|
|
|
if (m_isMounted)
|
|
{
|
|
qWarning() << "Cannot mount device" << deviceNode
|
|
<< "because it's already mounted.";
|
|
return false;
|
|
}
|
|
|
|
Q_ASSERT(m_innerFs);
|
|
|
|
if (mapperName().isEmpty())
|
|
return false;
|
|
|
|
if (m_innerFs->canMount(mapperName(), mountPoint))
|
|
{
|
|
if (m_innerFs->mount(report, mapperName(), mountPoint))
|
|
{
|
|
m_isMounted = true;
|
|
|
|
const QStorageInfo storageInfo = QStorageInfo(mountPoint);
|
|
if (storageInfo.isValid() && !mountPoint.isEmpty())
|
|
setSectorsUsed( (storageInfo.bytesTotal() - storageInfo.bytesFree() + payloadOffset()) / sectorSize());
|
|
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
ExternalCommand mountCmd(
|
|
report,
|
|
QStringLiteral("mount"),
|
|
{ QStringLiteral("--verbose"), mapperName(), mountPoint });
|
|
if (mountCmd.run() && mountCmd.exitCode() == 0)
|
|
{
|
|
m_isMounted = true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool luks::unmount(Report& report, const QString& deviceNode)
|
|
{
|
|
if (!m_isCryptOpen)
|
|
{
|
|
qWarning() << "Cannot unmount device" << deviceNode
|
|
<< "before decrypting it first.";
|
|
return false;
|
|
}
|
|
|
|
if (!m_isMounted)
|
|
{
|
|
qWarning() << "Cannot unmount device" << deviceNode
|
|
<< "because it's not mounted.";
|
|
return false;
|
|
}
|
|
|
|
Q_ASSERT(m_innerFs);
|
|
|
|
if (mapperName().isEmpty())
|
|
return false;
|
|
|
|
if (m_innerFs->canUnmount(mapperName()))
|
|
{
|
|
if (m_innerFs->unmount(report, mapperName()))
|
|
{
|
|
m_isMounted = false;
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
ExternalCommand unmountCmd( report,
|
|
QStringLiteral("umount"),
|
|
{ QStringLiteral("--verbose"), QStringLiteral("--all-targets"), mapperName() });
|
|
if (unmountCmd.run() && unmountCmd.exitCode() == 0)
|
|
{
|
|
m_isMounted = false;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FileSystem::Type luks::type() const
|
|
{
|
|
if (m_isCryptOpen && m_innerFs)
|
|
return m_innerFs->type();
|
|
return FileSystem::Type::Luks;
|
|
}
|
|
|
|
QString luks::suggestedMapperName(const QString& deviceNode) const
|
|
{
|
|
return QStringLiteral("luks-") + readOuterUUID(deviceNode);
|
|
}
|
|
|
|
QString luks::readLabel(const QString& deviceNode) const
|
|
{
|
|
if (m_isCryptOpen && m_innerFs)
|
|
return m_innerFs->readLabel(mapperName());
|
|
|
|
return FileSystem::readLabel(deviceNode);
|
|
}
|
|
|
|
bool luks::writeLabel(Report& report, const QString&, const QString& newLabel)
|
|
{
|
|
Q_ASSERT(m_innerFs);
|
|
return m_innerFs->writeLabel(report, mapperName(), newLabel);
|
|
}
|
|
|
|
bool luks::resize(Report& report, const QString& deviceNode, qint64 newLength) const
|
|
{
|
|
Q_ASSERT(m_innerFs);
|
|
|
|
if (mapperName().isEmpty())
|
|
return false;
|
|
|
|
const qint64 sizeDiff = newLength - length() * sectorSize();
|
|
const qint64 newPayloadSize = m_PayloadSize + sizeDiff;
|
|
if ( sizeDiff > 0 ) // grow
|
|
{
|
|
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperName() });
|
|
report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
|
|
|
|
if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0)
|
|
return m_innerFs->resize(report, mapperName(), newPayloadSize);
|
|
}
|
|
else if (m_innerFs->resize(report, mapperName(), newPayloadSize)) // shrink
|
|
{
|
|
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"),
|
|
{ QStringLiteral("--size"), QString::number(newPayloadSize / 512), // LUKS1 payload length is specified in multiples of 512 bytes
|
|
QStringLiteral("resize"), mapperName() });
|
|
report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
|
|
if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0)
|
|
return true;
|
|
}
|
|
report.line() << xi18nc("@info:progress", "Resizing encrypted file system on partition <filename>%1</filename> failed.", deviceNode);
|
|
return false;
|
|
}
|
|
|
|
bool luks::resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64 length) const
|
|
{
|
|
Q_UNUSED(mountPoint)
|
|
return resize(report, deviceNode, length);
|
|
}
|
|
|
|
QString luks::readUUID(const QString& deviceNode) const
|
|
{
|
|
QString outerUuid = readOuterUUID(deviceNode);
|
|
if (m_isCryptOpen && m_innerFs)
|
|
return m_innerFs->readUUID(mapperName());
|
|
return outerUuid;
|
|
}
|
|
|
|
QString luks::readOuterUUID(const QString &deviceNode) const
|
|
{
|
|
if ( deviceNode.isEmpty() )
|
|
return QString();
|
|
|
|
ExternalCommand cmd(QStringLiteral("cryptsetup"),
|
|
{ QStringLiteral("luksUUID"), deviceNode });
|
|
if (cmd.run()) {
|
|
if ( cmd.exitCode() )
|
|
{
|
|
qWarning() << "Cannot get luksUUID for device" << deviceNode
|
|
<< "\tcryptsetup exit code" << cmd.exitCode()
|
|
<< "\toutput:" << cmd.output().trimmed();
|
|
return QString();
|
|
}
|
|
QString outerUuid = cmd.output().trimmed();
|
|
const_cast< QString& >( m_outerUuid ) = outerUuid;
|
|
return outerUuid;
|
|
}
|
|
return QStringLiteral("---");
|
|
}
|
|
|
|
bool luks::updateUUID(Report& report, const QString& deviceNode) const
|
|
{
|
|
const QString uuid = QUuid::createUuid().toString().remove(QRegularExpression(QStringLiteral("\\{|\\}")));
|
|
|
|
ExternalCommand cmd(report,
|
|
QStringLiteral("cryptsetup"),
|
|
{ QStringLiteral("luksUUID"),
|
|
deviceNode,
|
|
QStringLiteral("--uuid"),
|
|
uuid });
|
|
return cmd.run(-1) && cmd.exitCode() == 0;
|
|
}
|
|
|
|
void luks::getMapperName(const QString& deviceNode)
|
|
{
|
|
ExternalCommand cmd(QStringLiteral("lsblk"),
|
|
{ QStringLiteral("--list"),
|
|
QStringLiteral("--noheadings"),
|
|
QStringLiteral("--paths"),
|
|
QStringLiteral("--json"),
|
|
QStringLiteral("--output"),
|
|
QStringLiteral("type,name"),
|
|
deviceNode });
|
|
m_MapperName = QString();
|
|
|
|
if (cmd.run(-1) && cmd.exitCode() == 0) {
|
|
const QJsonDocument jsonDocument = QJsonDocument::fromJson(cmd.rawOutput());
|
|
QJsonObject jsonObject = jsonDocument.object();
|
|
const QJsonArray jsonArray = jsonObject[QLatin1String("blockdevices")].toArray();
|
|
for (const auto &deviceLine : jsonArray) {
|
|
QJsonObject deviceObject = deviceLine.toObject();
|
|
if (deviceObject[QLatin1String("type")].toString() == QLatin1String("crypt")) {
|
|
m_MapperName = deviceObject[QLatin1String("name")].toString();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void luks::getLuksInfo(const QString& deviceNode)
|
|
{
|
|
ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("luksDump"), deviceNode });
|
|
if (cmd.run(-1) && cmd.exitCode() == 0) {
|
|
QRegularExpression re(QStringLiteral("Cipher name:\\s+(\\w+)"));
|
|
QRegularExpressionMatch rem = re.match(cmd.output());
|
|
if (rem.hasMatch())
|
|
m_CipherName = rem.captured(1);
|
|
else
|
|
m_CipherName = QLatin1String("---");
|
|
|
|
re.setPattern(QStringLiteral("Cipher mode:\\s+(\\w+)"));
|
|
rem = re.match(cmd.output());
|
|
if (rem.hasMatch())
|
|
m_CipherMode = rem.captured(1);
|
|
else
|
|
m_CipherMode = QLatin1String("---");
|
|
|
|
re.setPattern(QStringLiteral("Hash spec:\\s+(\\w+)"));
|
|
rem = re.match(cmd.output());
|
|
if (rem.hasMatch())
|
|
m_HashName = rem.captured(1);
|
|
else
|
|
m_HashName = QLatin1String("---");
|
|
|
|
re.setPattern(QStringLiteral("MK bits:\\s+(\\d+)"));
|
|
rem = re.match(cmd.output());
|
|
if (rem.hasMatch())
|
|
m_KeySize = rem.captured(1).toLongLong();
|
|
else
|
|
m_KeySize = -1;
|
|
|
|
re.setPattern(QStringLiteral("Payload offset:\\s+(\\d+)"));
|
|
rem = re.match(cmd.output());
|
|
if (rem.hasMatch())
|
|
m_PayloadOffset = rem.captured(1).toLongLong() * 512; // assuming LUKS sector size is 512;
|
|
else
|
|
m_PayloadOffset = -1;
|
|
|
|
}
|
|
else {
|
|
m_CipherName = QLatin1String("---");
|
|
m_CipherMode = QLatin1String("---");
|
|
m_HashName = QLatin1String("---");
|
|
m_KeySize = -1;
|
|
m_PayloadOffset = -1;
|
|
}
|
|
}
|
|
|
|
QString luks::outerUuid() const
|
|
{
|
|
return m_outerUuid;
|
|
}
|
|
|
|
bool luks::canEncryptType(FileSystem::Type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case Type::Btrfs:
|
|
case Type::F2fs:
|
|
case Type::Ext2:
|
|
case Type::Ext3:
|
|
case Type::Ext4:
|
|
case Type::Jfs:
|
|
case Type::LinuxSwap:
|
|
case Type::Lvm2_PV:
|
|
case Type::Nilfs2:
|
|
case Type::ReiserFS:
|
|
case Type::Reiser4:
|
|
case Type::Xfs:
|
|
case Type::Zfs:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void luks::initLUKS()
|
|
{
|
|
setPayloadSize();
|
|
QString mapperNode = mapperName();
|
|
bool isCryptOpen = !mapperNode.isEmpty();
|
|
setCryptOpen(isCryptOpen);
|
|
if (isCryptOpen) {
|
|
loadInnerFileSystem(mapperNode);
|
|
setMounted(detectMountStatus(innerFS(), mapperNode));
|
|
}
|
|
}
|
|
|
|
void luks::setPayloadSize()
|
|
{
|
|
ExternalCommand dmsetupCmd(QStringLiteral("dmsetup"), { QStringLiteral("table"), mapperName() });
|
|
dmsetupCmd.run();
|
|
QRegularExpression re(QStringLiteral("\\d+ (\\d+)"));
|
|
QRegularExpressionMatch rem = re.match(dmsetupCmd.output());
|
|
if (rem.hasMatch())
|
|
m_PayloadSize = rem.captured(1).toLongLong() * sectorSize();
|
|
}
|
|
|
|
bool luks::testPassphrase(const QString& deviceNode, const QString& passphrase) const {
|
|
ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("open"), QStringLiteral("--tries"), QStringLiteral("1"), QStringLiteral("--test-passphrase"), deviceNode });
|
|
if (cmd.write(passphrase.toLocal8Bit() + '\n') && cmd.start(-1) && cmd.exitCode() == 0)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|